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,23 @@
package content.global.skill
import core.game.node.entity.combat.CombatStyle
import core.game.interaction.InteractionListener
import core.game.interaction.IntType
class AttackListener : InteractionListener {
override fun defineListeners() {
on(IntType.NPC, "attack"){ player, npc ->
//Makes sure player uses correct attack styles for lumbridge dummies
if (npc.id == 4474 && player.getSwingHandler(false).type != CombatStyle.MAGIC) {
player.sendMessage("You can only attack this with magic.")
return@on true
}
if (npc.id == 7891 && player.getSwingHandler(false).type != CombatStyle.MELEE) {
player.sendMessage("You must use the training sword to attack this.")
return@on true
}
player.attack(npc)
return@on true
}
}
}
@@ -0,0 +1,158 @@
package content.global.skill.agility;
import core.game.node.entity.skill.Skills;
import core.game.interaction.OptionHandler;
import core.game.node.entity.player.Player;
import core.plugin.Plugin;
/**
* Represents an agility course.
* @author Emperor
*/
public abstract class AgilityCourse extends OptionHandler {
/**
* The player doing the agility course.
*/
private final Player player;
/**
* The obstacles the player has already passed.
*/
private final boolean[] obstaclesPassed;
/**
* The completion experience.
*/
private double completionExperience;
/**
* Constructs a new {@code AgilityCourse} {@code Object}.
* @param player The player.
* @param size The amount of obstacles in the course.
* @param completionExperience The amount of experience to gain upon
* completing the course.
*/
public AgilityCourse(Player player, int size, double completionExperience) {
this.player = player;
this.obstaclesPassed = new boolean[size];
this.completionExperience = completionExperience;
}
@Override
public final Plugin<Object> newInstance(Object arg) throws Throwable {
if (arg == null) {
configure();
return this;
}
return createInstance((Player) arg);
}
@Override
public Object fireEvent(String identifier, Object... args) {
return null;
}
/**
* Configures the course.
*/
public abstract void configure();
/**
* Creates a new instance for the player.
* @param player The player.
* @return The agility course instance.
*/
public abstract AgilityCourse createInstance(Player player);
/**
* Gets the agility course for the given player. If the player didn't have
* the course as an extension, an extension will be added.
* @param player The player.
* @return The agility course instance.
*/
public AgilityCourse getCourse(Player player) {
AgilityCourse course = player.getExtension(AgilityCourse.class);
if (course == null || course.getClass() != getClass()) {
try {
player.addExtension(AgilityCourse.class, course = createInstance(player));
} catch (Throwable e) {
e.printStackTrace();
}
}
return course;
}
/**
* Finishes the lap by checking for completion and resetting.
*/
public void finish() {
if (isCompleted()) {
player.getSkills().addExperience(Skills.AGILITY, completionExperience, true);
}
reset();
}
/**
* Checks if the course has been completed.
* @return {@code True} if so.
*/
public boolean isCompleted() {
for (int i = 0; i < obstaclesPassed.length; i++) {
if (!obstaclesPassed[i]) {
return false;
}
}
return true;
}
/**
* Resets the currently passed obstacles in the course.
*/
public void reset() {
for (int i = 0; i < obstaclesPassed.length; i++) {
obstaclesPassed[i] = false;
}
}
/**
* Flags an obstacles as passed.
* @param index The obstacle index.
*/
public void flag(int index) {
obstaclesPassed[index] = true;
if (index == obstaclesPassed.length - 1) {
finish();
}
}
/**
* Gets the amount of damage to deal.
* @param player The player.
* @return The amount of damage.
*/
protected static int getHitAmount(Player player) {
int hit = player.getSkills().getLifepoints() / 12;
if (hit < 2) {
hit = 2;
}
return hit;
}
/**
* Gets the player.
* @return The player.
*/
public Player getPlayer() {
return player;
}
/**
* Gets the passed obstacles flags.
* @return The passed obstacles flags.
*/
public boolean[] getPassedObstacles() {
return obstaclesPassed;
}
}
@@ -0,0 +1,323 @@
package content.global.skill.agility;
import static core.api.ContentAPIKt.*;
import core.game.node.entity.impl.PulseType;
import core.game.node.entity.player.link.TeleportManager;
import core.game.node.entity.skill.Skills;
import core.game.interaction.MovementPulse;
import core.game.node.entity.combat.ImpactHandler.HitsplatType;
import core.game.node.entity.impl.ForceMovement;
import core.game.node.entity.player.Player;
import core.game.system.task.Pulse;
import kotlin.Unit;
import core.game.world.GameWorld;
import core.game.world.map.Direction;
import core.game.world.map.Location;
import core.game.world.update.flag.context.Animation;
/**
* Holds agility-related utility methods.
* @author Emperor
*/
public final class AgilityHandler {
/**
* Checks if the player has failed crossing an obstacle.
* @param player The player.
* @param level The level requirement for the obstacle.
* @param failChance The chance of failing (0.0 - 0.99).
* @return {@code True} if the player has failed.
*/
public static boolean hasFailed(Player player, int level, double failChance) {
int levelDiff = player.getSkills().getLevel(Skills.AGILITY) - level;
if (levelDiff > 69) {
return false;
}
double chance = (1 + levelDiff) * 0.01;
chance *= Math.random();
return chance <= (Math.random() * failChance);
}
/**
* Handles failing an obstacle (by using force movement).
* @param player The player.
* @param delay The amount of ticks before teleporting to the destination
* and hitting.
* @param start The start location.
* @param end The end location.
* @param dest The destination.
* @param anim The animation.
* @param hit The amount of damage to hit.
* @param message The message to send.
*/
public static ForceMovement failWalk(final Player player, int delay, Location start, Location end, final Location dest, Animation anim, int speed, final int hit, final String message, Direction direction) {
ForceMovement movement = new ForceMovement(player, start, end, anim, speed) {
@Override
public void stop() {
super.stop();
player.getProperties().setTeleportLocation(dest);
if (hit > 0) {
player.getImpactHandler().setDisabledTicks(0);
player.getImpactHandler().manualHit(player, hit, HitsplatType.NORMAL);
}
if (message != null) {
player.getPacketDispatch().sendMessage(message);
}
}
};
if (direction != null) {
movement.setDirection(direction);
}
movement.start();
movement.setDelay(delay);
GameWorld.getPulser().submit(movement);
return movement;
}
/**
* Handles failing an obstacle (by using force movement).
* @param player The player.
* @param delay The amount of ticks before teleporting to the destination
* and hitting.
* @param start The start location.
* @param end The end location.
* @param dest The destination.
* @param anim The animation.
* @param hit The amount of damage to hit.
* @param message The message to send.
*/
public static ForceMovement failWalk(final Player player, int delay, Location start, Location end, final Location dest, Animation anim, int speed, final int hit, final String message) {
return failWalk(player, delay, start, end, dest, anim, speed, hit, message, null);
}
/**
* Handles failing an obstacle.
* @param player The player.
* @param delay The amount of ticks before teleporting to the destination
* and hitting.
* @param dest The destination.
* @param anim The animation.
* @param hit The amount of damage to hit.
* @param message The message to send.
*/
public static void fail(final Player player, int delay, final Location dest, Animation anim, final int hit, final String message) {
if (anim != null) {
animate(player, anim, true);
submitWorldPulse(new Pulse(animationDuration(anim), player) {
boolean dmg = false;
@Override
public boolean pulse() {
teleport(player, dest, TeleportManager.TeleportType.INSTANT);
animate(player, Animation.RESET, true);
if (!dmg) {
if (hit > 0) {
player.getImpactHandler().setDisabledTicks(0);
impact(player, hit, HitsplatType.NORMAL);
}
if (message != null) {
sendMessage(player, message);
}
dmg = true;
}
setDelay(0);
return player.getLocation().equals(dest);
}
});
}
}
/**
* Walks across an obstacle using the force movement update mask.
* @param start The start location.
* @param end The end location.
* @param animation The animation.
* @param speed The force movement speed.
* @param experience The amount of agility experience to give as reward.
* @param message The message to send upon completion.
* @return The force movement instance, if force movement is used.
*/
public static ForceMovement forceWalk(final Player player, final int courseIndex, Location start, Location end, Animation animation, int speed, final double experience, final String message) {
player.logoutListeners.put("forcewalk", p -> {
p.setLocation(player.getLocation().transform(0,0,0));
return Unit.INSTANCE;
});
lock(player, ((int) start.getDistance(end)) * 3);
ForceMovement movement = new ForceMovement(player, start, end, animation, speed) {
@Override
public void stop() {
super.stop();
if (message != null) {
player.getPacketDispatch().sendMessage(message);
}
if (experience > 0.0) {
player.getSkills().addExperience(Skills.AGILITY, experience, true);
}
setObstacleFlag(player, courseIndex);
player.logoutListeners.remove("forcewalk");
}
};
movement.start();
GameWorld.getPulser().submit(movement);
return movement;
}
/**
* Walks across an obstacle using the force movement update mask.
* @param start The start location.
* @param end The end location.
* @param animation The animation.
* @param speed The force movement speed.
* @param experience The amount of agility experience to give as reward.
* @param message The message to send upon completion.
* @return The force movement instance, if force movement is used.
*/
public static ForceMovement forceWalk(final Player player, final int courseIndex, Location start, Location end, Animation animation, int speed, final double experience, final String message, int delay) {
player.logoutListeners.put("forcewalk", p -> {
p.setLocation(player.getLocation().transform(0,0,0));
return Unit.INSTANCE;
});
lock(player, ((int) start.getDistance(end)) * 3);
if (delay < 1) {
return forceWalk(player, courseIndex, start, end, animation, speed, experience, message);
}
final ForceMovement movement = new ForceMovement(player, start, end, animation, speed) {
@Override
public void stop() {
super.stop();
if (message != null) {
player.getPacketDispatch().sendMessage(message);
}
if (experience > 0.0) {
player.getSkills().addExperience(Skills.AGILITY, experience, true);
}
setObstacleFlag(player, courseIndex);
player.logoutListeners.remove("forcewalk");
}
};
GameWorld.getPulser().submit(new Pulse(delay, player) {
@Override
public boolean pulse() {
movement.start();
GameWorld.getPulser().submit(movement);
return true;
}
});
return movement;
}
/**
* Executes the climbing reward.
* @param player The player.
* @param animation The climbing animation.
* @param destination The destination.
* @param experience The amount of agility experience to give as reward.
* @param message The message to send upon completion.
*/
public static void climb(final Player player, final int courseIndex, Animation animation, final Location destination, final double experience, final String message) {
climb(player, courseIndex, animation, destination, experience, message, 2);
}
/**
* Executes the climbing reward.
* @param player The player.
* @param animation The climbing animation.
* @param destination The destination.
* @param experience The amount of agility experience to give as reward.
* @param message The message to send upon completion.
*/
public static void climb(final Player player, final int courseIndex, Animation animation, final Location destination, final double experience, final String message, int delay) {
player.lock(delay + 1);
player.animate(animation);
GameWorld.getPulser().submit(new Pulse(delay) {
@Override
public boolean pulse() {
if (message != null) {
player.getPacketDispatch().sendMessage(message);
}
if (experience > 0.0) {
player.getSkills().addExperience(Skills.AGILITY, experience, true);
}
player.getProperties().setTeleportLocation(destination);
setObstacleFlag(player, courseIndex);
return true;
}
});
}
public static void walk(final Player player, final int courseIndex, final Location start, final Location end, final Animation animation, final double experience, final String message){
walk(player,courseIndex,start,end,animation,experience,message,false);
}
/**
* Uses the walking queue to walk across an obstacle.
* @param player The player.
* @param courseIndex The obstacle index for the course, {@code -1} if no
* course.
* @param start The start location.
* @param end The end location.
* @param animation The animation.
* @param experience The agility experience.
* @param message The message to send upon completion.
*/
public static void walk(final Player player, final int courseIndex, final Location start, final Location end, final Animation animation, final double experience, final String message, final boolean infiniteRun) {
if (!player.getLocation().equals(start)) {
player.getPulseManager().run(new MovementPulse(player, start) {
@Override
public boolean pulse() {
walk(player, courseIndex, start, end, animation, experience, message, infiniteRun);
return true;
}
}, PulseType.STANDARD);
return;
}
player.getWalkingQueue().reset();
player.getWalkingQueue().addPath(end.getX(), end.getY(), !infiniteRun);
int ticks = player.getWalkingQueue().getQueue().size();
player.getImpactHandler().setDisabledTicks(ticks);
player.lock(1 + ticks);
player.logoutListeners.put("agility", p -> {
p.setLocation(start);
return Unit.INSTANCE;
});
if (animation != null) {
player.getAppearance().setAnimations(animation);
}
player.getSettings().setRunEnergy(100.0);
GameWorld.getPulser().submit(new Pulse(ticks, player) {
@Override
public boolean pulse() {
if (animation != null) {
player.getAppearance().setAnimations();
player.getAppearance().sync();
}
if (message != null) {
player.getPacketDispatch().sendMessage(message);
}
if (experience > 0.0) {
player.getSkills().addExperience(Skills.AGILITY, experience, true);
}
setObstacleFlag(player, courseIndex);
player.logoutListeners.remove("agility");
return true;
}
});
}
/**
* Sets the obstacle flag for the agility course.
* @param player The player.
* @param courseIndex The course index.
*/
public static void setObstacleFlag(Player player, int courseIndex) {
if (courseIndex < 0) {
return;
}
AgilityCourse course = player.getExtension(AgilityCourse.class);
if (course != null && courseIndex < course.getPassedObstacles().length) {
course.flag(courseIndex);
}
}
}
@@ -0,0 +1,228 @@
package content.global.skill.agility;
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.scenery.Scenery;
import core.game.world.map.Direction;
import core.game.world.map.Location;
import core.plugin.Plugin;
import core.game.node.entity.skill.Skills;
/**
* Handles an agility shortcut.
* @author Woah
*/
public abstract class AgilityShortcut extends OptionHandler {
/**
* The ids used for this shortcut.
*/
private final int[] ids;
/**
* The level required.
*/
private final int level;
/**
* The experience required.
*/
private final double experience;
/**
* If the player can fail this shortcut.
*/
private final boolean canFail;
/**
* The chance to fail.
*/
private double failChance;
/**
* The options for the shortcut.
*/
private final String[] options;
/**
* Constructs a new {@Code AgilityShortcut} {@Code Object}
* @param ids the ids.
* @param level the level.
* @param experience the experience.
* @param canFail if this shortcut can be failed.
* @param failChance the chance to fail
* @param options the options.
*/
public AgilityShortcut(int[] ids, int level, double experience, boolean canFail, double failChance, String... options) {
this.ids = ids;
this.level = level;
this.experience = experience;
this.canFail = canFail;
this.failChance = failChance;
this.options = options;
}
/**
* Constructs a new {@Code AgilityShortcut} {@Code Object}
* @param ids the ids.
* @param level the level.
* @param experience the experience.
* @param options the options.
*/
public AgilityShortcut(int[] ids, int level, double experience, String... options) {
this(ids, level, experience, false, 0.0, options);
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
configure(this);
return this;
}
@Override
public boolean handle(Player player, Node node, String option) {
if (!checkRequirements(player)) {
return true;
}
run(player, node.asScenery(), option, checkFail(player, node.asScenery(), option));
return true;
}
/**
* Runs the agility reward for the short cut.
* @param player the player.
* @param object the object.
* @param option the option.
* @param failed the shortcut failed.
*/
public abstract void run(Player player, Scenery object, String option, boolean failed);
/**
* Checks the requirements for a player.
* @param player the player.
* @return {@code True} if so.
*/
public boolean checkRequirements(Player player) {
if (player.getSkills().getLevel(Skills.AGILITY) < level) {
player.getDialogueInterpreter().sendDialogue("You need an Agility level of at least " + level + " to negotiate this obstacle.");
return false;
}
return true;
}
/**
* Checks if the player failed the shortcut.
* @param player the player.
* @param object the object.
* @param option2 the option.
* @return {@code True} if failed.
*/
private boolean checkFail(Player player, Scenery object, String option2) {
if (!canFail) {
return false;
}
return AgilityHandler.hasFailed(player, level, failChance);
}
/**
* Configures this shortcut.
*/
public void configure(AgilityShortcut shortcut) {
for (int objectId : shortcut.ids) {
SceneryDefinition def = SceneryDefinition.forId(objectId);
for (String option : shortcut.options) {
def.getHandlers().put("option:" + option, shortcut);
}
}
}
/**
* Gets the proper object direction.
* @param direction the direction.
* @return the direction.
*/
protected Direction getObjectDirection(Direction direction) {
return direction == Direction.NORTH ? Direction.EAST : direction == Direction.SOUTH ? Direction.WEST : direction == Direction.EAST ? Direction.NORTH : Direction.SOUTH;
}
public Location pipeDestination(Player player, Scenery object, int steps) {
player.faceLocation(object.getLocation());
int diffX = object.getLocation().getX() - player.getLocation().getX();
if (diffX < -1) { diffX = -1; }
if (diffX > 1) { diffX = 1; }
int diffY = object.getLocation().getY() - player.getLocation().getY();
if (diffY < -1) { diffY = -1; }
if (diffY > 1) { diffX = 1; }
Location dest = player.getLocation().transform((diffX) * steps, (diffY) * steps, 0);
return dest;
}
public Location agilityDestination(Player player, Scenery object, int steps) {
player.faceLocation(object.getLocation());
int diffX = object.getLocation().getX() - player.getLocation().getX();
int diffY = object.getLocation().getY() - player.getLocation().getY();
Location dest = player.getLocation().transform((diffX) * steps, (diffY) * steps, 0);
return dest;
}
/**
* Gets the level.
* @return the level
*/
public int getLevel() {
return level;
}
/**
* Gets the experience.
* @return the experience
*/
public double getExperience() {
return experience;
}
/**
* Gets the canFail.
* @return the canFail
*/
public boolean isCanFail() {
return canFail;
}
/**
* Gets the failChance.
* @return the failChance
*/
public double getFailChance() {
return failChance;
}
/**
* Sets the bafailChance.
* @param failChance the failChance to set.
*/
public void setFailChance(double failChance) {
this.failChance = failChance;
}
/**
* Gets the ids.
* @return the ids
*/
public int[] getIds() {
return ids;
}
/**
* Gets the option.
* @return the option
*/
public String[] getOption() {
return options;
}
}
@@ -0,0 +1,343 @@
package content.global.skill.agility
import core.api.*
import core.cache.def.impl.ItemDefinition
import core.cache.def.impl.NPCDefinition
import core.cache.def.impl.SceneryDefinition
import content.region.kandarin.barcrawl.BarcrawlManager
import core.game.node.Node
import core.game.node.scenery.Scenery
import core.game.node.entity.combat.ImpactHandler.HitsplatType
import core.game.node.entity.player.Player
import core.game.system.task.Pulse
import core.game.world.map.Location
import core.game.world.update.flag.context.Animation
import core.game.world.update.flag.context.Graphics
import core.plugin.Initializable
import core.game.world.GameWorld
import core.plugin.ClassScanner
/**
* Handles the barbarian outpost course.
* @author Woah
*
*/
@Initializable
class BarbarianOutpostCourse
/**
* Constructs a new `BarbarianOutpostCourse` `Object`.
* @param player the player.
*/
@JvmOverloads constructor(player: Player? = null) : AgilityCourse(player, 6, 46.2) {
override fun createInstance(player: Player): AgilityCourse {
return content.global.skill.agility.BarbarianOutpostCourse(player)
}
override fun handle(player: Player, node: Node, option: String): Boolean {
val id = node.id
getCourse(player)
when (id) {
2115, 2116 -> if (!BarcrawlManager.getInstance(player).isFinished || BarcrawlManager.getInstance(player).isStarted) {
player.dialogueInterpreter.open(384)
} else {
core.game.global.action.DoorActionHandler.handleAutowalkDoor(player, node as Scenery)
}
2282 -> handleRopeSwing(player, node as Scenery)
2294 -> handleLogBalance(player, node as Scenery)
2302 -> handleLedgeBalance(player, node as Scenery)
20211 -> {
if (player.location.x < node.location.x) {
return true
}
AgilityHandler.climb(player, 2, core.game.global.action.ClimbActionHandler.CLIMB_UP, player.location.transform(-1, 0, 1), 8.0, "You climb the netting...")
}
1948 -> {
if (player.location.x > node.location.x) {
player.packetDispatch.sendMessage("You cannot climb from this side.")
return true //who missed this return? lol.
}
val flag = if (node.location == Location(2536, 3553, 0)) 4 else if (node.location == Location(2539, 3553, 0)) 5 else 6
sendMessage(player, "You climb the low wall...")
AgilityHandler.forceWalk(player, flag, node.location.transform(-1, 0, 0), node.location.transform(1, 0, 0), Animation.create(839), 10, 13.5, null)
}
455 -> BarcrawlManager.getInstance(player).read()
385 -> {
sendMessage(player, "The scorpion stings you!")
player.impactHandler.manualHit(player, 3, HitsplatType.NORMAL)
}
386 -> {
sendMessage(player, "The scorpion stings you!")
player.impactHandler.manualHit(player, 3, HitsplatType.NORMAL)
}
387 -> {
sendMessage(player, "The scorpion stings you!")
player.impactHandler.manualHit(player, 3, HitsplatType.NORMAL)
}
}
return true
}
/**
* Handles the rope swing obstacle.
* @param player the player.
* @param object the object.
*/
private fun handleRopeSwing(player: Player, `object`: Scenery) {
if (player.location.y < 3554) {
sendMessage(player, "You cannot do that from here.")
return
}
if (content.global.skill.agility.BarbarianOutpostCourse.Companion.ropeDelay > GameWorld.ticks) {
sendMessage(player, "The rope is being used.")
return
}
if (AgilityHandler.hasFailed(player, 1, 0.1)) {
AgilityHandler.fail(player, 0, Location.create(2549, 9951, 0), null, getHitAmount(player), "You slip and fall to the pit below.")
return
}
content.global.skill.agility.BarbarianOutpostCourse.Companion.ropeDelay = GameWorld.ticks + 2
player.packetDispatch.sendSceneryAnimation(`object`, Animation.create(497), true)
AgilityHandler.forceWalk(player, 0, player.location, Location.create(2551, 3549, 0), Animation.create(751), 50, 22.0, "You skillfully swing across.", 1)
}
/**
* Handles the log balance obstacle.
* @param player the player.
* @param object the object.
*/
private fun handleLogBalance(player: Player, `object`: Scenery) {
val failed = AgilityHandler.hasFailed(player, 1, 0.5)
val end = if (failed) Location.create(2545, 3546, 0) else Location.create(2541, 3546, 0)
sendMessage(player, "You walk carefully across the slippery log...")
AgilityHandler.walk(player, if (failed) -1 else 1, Location.create(2551, 3546, 0), end, Animation.create(155), if (failed) 0.0 else 13.5, if (failed) null else "...You make it safely to the other side.")
if (failed) {
AgilityHandler.walk(player, -1, player.location, Location.create(2545, 3546, 0), Animation.create(155), 0.0, null)
GameWorld.Pulser.submit(getSwimPulse(player))
return
}
}
/**
* Gets the pulse used to swim when failing the log balance.
* @param player the player.
* @return `Pulse` the pulse.
*/
private fun getSwimPulse(player: Player): Pulse {
return object : Pulse(1, player) {
var counter = 0
override fun pulse(): Boolean {
when (++counter) {
6 -> {
player.animate(Animation.create(771))
player.packetDispatch.sendMessages("...You loose your footing and fall into the water.", "Something in the water bites you.")
}
7 -> {
player.graphics(Graphics.create(68))
player.properties.teleportLocation = Location.create(2545, 3545, 0)
player.impactHandler.manualHit(player, getHitAmount(player), HitsplatType.NORMAL)
AgilityHandler.walk(player, -1, Location.create(2545, 3545, 0), Location.create(2545, 3543, 0), Animation.create(152), 0.0, null)
}
11 -> {
player.properties.teleportLocation = Location.create(2545, 3542, 0)
return true
}
}
return false
}
}
}
/**
* Handles the ledge balance obstacle.
* @param player the player.
* @param object the object.
*/
private fun handleLedgeBalance(player: Player, `object`: Scenery) {
val failed = AgilityHandler.hasFailed(player, 1, 0.3)
val end = if (failed) Location.create(2534, 3547, 1) else Location.create(2532, 3547, 1)
AgilityHandler.walk(player, if (failed) -1 else 3, Location.create(2536, 3547, 1), end, Animation.create(157), if (failed) 0.0 else 22.0, if (failed) null else "You skillfully edge across the gap.")
sendMessage(player, "You put your foot on the ledge and try to edge across..")
if (failed) {
AgilityHandler.fail(player, 3, Location.create(2534, 3545, 0), Animation(760), getHitAmount(player), "You slip and fall to the pit below.")
return
}
}
override fun configure() {
SceneryDefinition.forId(2115).handlers["option:open"] = this
SceneryDefinition.forId(2116).handlers["option:open"] = this
SceneryDefinition.forId(2282).handlers["option:swing-on"] = this
SceneryDefinition.forId(2294).handlers["option:walk-across"] = this
SceneryDefinition.forId(20211).handlers["option:climb-over"] = this
SceneryDefinition.forId(2302).handlers["option:walk-across"] = this
SceneryDefinition.forId(1948).handlers["option:climb-over"] = this
ItemDefinition.forId(455).handlers["option:read"] = this
NPCDefinition.forId(385).handlers["option:pick-up"] = this
NPCDefinition.forId(386).handlers["option:pick-up"] = this
NPCDefinition.forId(387).handlers["option:pick-up"] = this
ClassScanner.definePlugin(content.global.skill.agility.BarbarianOutpostCourse.BarbarianGuardDialogue())
}
override fun getDestination(node: Node, n: Node): Location? {
if (n is Scenery) {
when (n.getId()) {
2282 -> return Location.create(2551, 3554, 0)
}
}
return null
}
/**
* The barbarian guard dialogue plugin.
* @author Woah
*/
class BarbarianGuardDialogue : core.game.dialogue.DialoguePlugin {
/**
* Constructs a new `BarbarianGuardDialogue` `Object`.
*/
constructor() {
/**
* empty.
*/
}
/**
* Constructs a new `BarbarianGuardDialogue` `Object`.
* @param player the player.
*/
constructor(player: Player?) : super(player) {}
override fun newInstance(player: Player): core.game.dialogue.DialoguePlugin {
return content.global.skill.agility.BarbarianOutpostCourse.BarbarianGuardDialogue(player)
}
override fun open(vararg args: Any): Boolean {
if (!BarcrawlManager.getInstance(player).isStarted) {
npc("O, waddya want?")
} else if (BarcrawlManager.getInstance(player).isFinished && !BarcrawlManager.getInstance(player).isStarted) {
npc("'Ello friend.")
stage = 50
} else {
npc("So, how's the Barcrawl coming along?")
stage = 20
}
return true
}
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
when (stage) {
0 -> {
options("I want to come through this gate.", "I want some money.")
stage++
}
1 -> when (buttonId) {
1 -> {
player("I want to come through this gate.")
stage = 5
}
2 -> {
player("I want some money.")
stage = 3
}
}
3 -> {
npc("Do I look like a bank to you?")
stage++
}
4 -> end()
5 -> if (BarcrawlManager.getInstance(player).isFinished) {
npc("You may pass if you like. You are a true", "barbarian now.")
stage = 4
} else {
npc("Barbarians only. Are you a barbarian? You don't look", "like one.")
stage++
}
6 -> {
options("Hmm, yep you've got me there.", "Looks can be deceiving, I am in fact a barbarian.")
stage++
}
7 -> when (buttonId) {
1 -> {
player("Hmm, yep you've got me there.")
stage = 4
}
2 -> {
player("Looks can be deceiving, I am in fact a barbarian.")
stage++
}
}
8 -> {
npc("If you're a barbarian you need to be able to drink like", "one. We barbarians like a good drink.")
stage++
}
9 -> {
npc("I have the perfect challenge for you... the Alfred", "Grimhand Barcrawl! First completed by Alfred", "Grimhand.")
stage++
}
10 -> {
BarcrawlManager.getInstance(player).reset()
BarcrawlManager.getInstance(player).isStarted = true
player.inventory.add(BarcrawlManager.BARCRAWL_CARD, player)
interpreter.sendDialogue("The guard hands you a Barcrawl card.")
stage++
}
11 -> {
npc("Take that card to each of the bards named on it. The", "bartenders will know what it means. We're kinda well", "known.")
stage++
}
12 -> {
npc("They'll give you their strongest drink and sign your", "card. When you've done all that, we'll be happy to let", "you in.")
stage++
}
13 -> end()
20 -> if (!BarcrawlManager.getInstance(player).hasCard()) {
player("I've lost my barcrawl card...")
stage = 23
} else if (BarcrawlManager.getInstance(player).isFinished) {
player("I tink I jusht 'bout done dem all... but I losht count...")
stage = 24
} else {
player("I haven't finished it yet.")
stage++
}
21 -> {
npc("Well come back when you have, you lightweight.")
stage++
}
22 -> end()
23 -> {
npc("What are you like? You're gonna have to start all over", "now.")
stage = 10
}
24 -> {
if (!player.inventory.containsItem(BarcrawlManager.BARCRAWL_CARD)) {
end()
}
BarcrawlManager.getInstance(player).isStarted = false
player.bank.remove(BarcrawlManager.BARCRAWL_CARD)
player.inventory.remove(BarcrawlManager.BARCRAWL_CARD)
interpreter.sendDialogue("You give the card to the barbarian.")
stage++
}
25 -> {
npc("Yep that seems fine, you can come in now. I never", "learned to read, but you look like you've drunk plenty.")
stage = 22
}
50 -> end()
}
return true
}
override fun getIds(): IntArray {
return intArrayOf(384)
}
}
companion object {
/**
* The rope delay.
*/
private var ropeDelay = 0
}
}
@@ -0,0 +1,156 @@
package content.global.skill.agility
import core.api.*
import core.cache.def.impl.SceneryDefinition
import core.game.node.Node
import core.game.node.scenery.Scenery
import core.game.node.entity.npc.NPC
import core.game.node.entity.player.Player
import core.game.world.map.Location
import core.game.world.update.flag.context.Animation
import core.plugin.Initializable
import core.game.world.GameWorld
/**
* Handles the gnome stronghold agility course.
* @author Woah
*/
@Initializable
class GnomeStrongholdCourse
/**
* Constructs a new `GnomeStrongholdCourse` `Object`.
* @param player The player.
*/
/**
* Constructs a new `GnomeStrongholdCourse` `Object`.
*/
@JvmOverloads constructor(player: Player? = null) : AgilityCourse(player, 7, 39.0) {
override fun handle(player: Player, node: Node, option: String): Boolean {
getCourse(player) // Sets the extension.
val `object` = node as Scenery
when (`object`.id) {
2295 -> {
content.global.skill.agility.GnomeStrongholdCourse.Companion.TRAINERS[0]!!.sendChat("Okay get over that log, quick quick!")
sendMessage(player, "You walk carefully across the slippery log...")
AgilityHandler.walk(player, 0, Location.create(2474, 3436, 0), Location.create(2474, 3429, 0), Animation.create(155), 7.5, "...You make it safely to the other side.")
return true
}
2285 -> {
content.global.skill.agility.GnomeStrongholdCourse.Companion.TRAINERS[1]!!.sendChat("Move it, move it, move it!")
sendMessage(player, "You climb the netting...")
AgilityHandler.climb(player, 1, Animation.create(828), `object`.location.transform(0, -1, 1), 7.5, null)
return true
}
35970 -> {
content.global.skill.agility.GnomeStrongholdCourse.Companion.TRAINERS[2]!!.sendChat("That's it - straight up.")
sendMessage(player, "You climb the tree..")
AgilityHandler.climb(player, 2, Animation.create(828), Location.create(2473, 3420, 2), 5.0, "...To the platform above.")
return true
}
2312 -> {
content.global.skill.agility.GnomeStrongholdCourse.Companion.TRAINERS[3]!!.sendChat("Come on scaredy cat, get across that rope!")
sendMessage(player, "You carefully cross the tightrope.")
AgilityHandler.walk(player, 3, Location.create(2477, 3420, 2), Location.create(2483, 3420, 2), Animation.create(155), 7.5, null)
return true
}
4059 -> {
sendMessage(player, "You can't do that from here.")
return true
}
2314, 2315 -> {
sendMessage(player, "You climb down the tree..")
AgilityHandler.climb(player, 4, Animation.create(828), Location.create(2487, 3420, 0), 5.0, "You land on the ground.")
return true
}
2286 -> {
content.global.skill.agility.GnomeStrongholdCourse.Companion.TRAINERS[4]!!.sendChat("My Granny can move faster than you.")
player.faceLocation(player.location.transform(0, 2, 0))
sendMessage(player, "You climb the netting...")
AgilityHandler.climb(player, 5, Animation.create(828), player.location.transform(0, 2, 0), 7.5, null)
return true
}
4058, 154 -> {
val index = if (`object`.id == 154) 0 else 1 //If the player clicks on the left pipe, set index to 0, otherwise 1
val x = 2484 + index * 3 //change the x coordinates for walking/animations depending on index multiplier
if (`object`.location.y == 3435) {
sendMessage(player, "You can't do that from here.")
return true
}
if (content.global.skill.agility.GnomeStrongholdCourse.Companion.USED_PIPES[index] > GameWorld.ticks) {
sendMessage(player, "The pipe is being used.")
return true
}
content.global.skill.agility.GnomeStrongholdCourse.Companion.USED_PIPES[index] = GameWorld.ticks + 10
player.lock()
//Animations and force walking
//X variable is determined by both index and x variables before
AgilityHandler.forceWalk(player, -1, Location.create(x, 3430, 0), Location.create(x, 3433, 0), Animation.create(10580), 10, 0.0, null)
player.lock()
AgilityHandler.forceWalk(player, -1, Location.create(x, 3433, 0), Location.create(x, 3435, 0), Animation.create(844), 10, 0.0, null, 5)
player.lock()
AgilityHandler.forceWalk(player, 6, Location.create(x, 3435, 0), Location.create(x, 3437, 0), Animation.create(10579), 20, 7.5, null, 8)
return true
}
}
return false
}
override fun getDestination(node: Node, n: Node): Location? {
val `object` = n as Scenery
when (`object`.id) {
2295 -> return Location.create(2474, 3436, 0)
2286 -> {
var x = node.location.x
if (x < n.getLocation().x) {
x = n.getLocation().x
} else if (x > n.getLocation().x + 1) {
x = n.getLocation().x + 1
}
return Location.create(x, n.getLocation().y - 1, 0)
}
4058, 154 -> if (n.getLocation().y == 3431) {
return n.getLocation().transform(0, -1, 0)
}
}
return null
}
override fun configure() {
content.global.skill.agility.GnomeStrongholdCourse.Companion.TRAINERS[0] = NPC.create(162, Location.create(2473, 3438, 0))
content.global.skill.agility.GnomeStrongholdCourse.Companion.TRAINERS[1] = NPC.create(162, Location.create(2478, 3426, 0))
content.global.skill.agility.GnomeStrongholdCourse.Companion.TRAINERS[2] = NPC.create(162, Location.create(2474, 3422, 1))
content.global.skill.agility.GnomeStrongholdCourse.Companion.TRAINERS[3] = NPC.create(162, Location.create(2472, 3419, 2))
content.global.skill.agility.GnomeStrongholdCourse.Companion.TRAINERS[4] = NPC.create(162, Location.create(2489, 3425, 0))
for (npc in content.global.skill.agility.GnomeStrongholdCourse.Companion.TRAINERS) {
npc!!.init()
npc.walkRadius = 3
}
SceneryDefinition.forId(2295).handlers["option:walk-across"] = this
SceneryDefinition.forId(2285).handlers["option:climb-over"] = this
SceneryDefinition.forId(35970).handlers["option:climb"] = this
SceneryDefinition.forId(2312).handlers["option:walk-on"] = this
SceneryDefinition.forId(4059).handlers["option:walk-on"] = this
SceneryDefinition.forId(2314).handlers["option:climb-down"] = this
SceneryDefinition.forId(2315).handlers["option:climb-down"] = this
SceneryDefinition.forId(2286).handlers["option:climb-over"] = this
SceneryDefinition.forId(4058).handlers["option:squeeze-through"] = this
SceneryDefinition.forId(154).handlers["option:squeeze-through"] = this
}
override fun createInstance(player: Player): AgilityCourse {
return content.global.skill.agility.GnomeStrongholdCourse(player)
}
companion object {
/**
* The pipes currently in usage.
*/
private val USED_PIPES = IntArray(2)
/**
* The trainer NPCs.
*/
private val TRAINERS = arrayOfNulls<NPC>(5)
}
}
@@ -0,0 +1,266 @@
package content.global.skill.agility
import core.api.*
import core.cache.def.impl.SceneryDefinition
import core.game.node.Node
import core.game.node.scenery.Scenery
import core.game.node.entity.player.Player
import core.game.node.entity.player.link.TeleportManager
import core.game.node.entity.skill.Skills
import core.game.system.task.Pulse
import core.game.world.map.Location
import core.game.world.map.RegionManager
import core.game.world.update.flag.context.Animation
import core.plugin.Initializable
import core.game.world.GameWorld
/**
* Handles the wilderness agility course.
* @author Woah
*/
@Initializable
class WildernessCourse
/**
* Constructs a new `WildernessCourse` `Object`.
*/
@JvmOverloads constructor(player: Player? = null) : AgilityCourse(player, 5, 499.0) {
override fun handle(player: Player, node: Node, option: String): Boolean {
getCourse(player) // Sets the extension.
val `object` = node as Scenery
when (`object`.id) {
2309 -> handleEntrance(player, `object`)
2307, 2308 -> {
core.game.global.action.DoorActionHandler.handleAutowalkDoor(player, `object`)
handleEntranceObstacle(player, `object`)
}
2288 -> handlePipe(player, `object`)
2283 -> handleRopeSwing(player, `object`)
37704 -> handleSteppingStones(player, `object`)
2297 -> handleLogBalance(player, `object`)
2328 -> handleRockClimb(player, `object`)
}
return true
}
/**
* Handles the door entrance.
* @param player the player.
* @param object the object.
*/
private fun handleEntrance(player: Player, `object`: Scenery) {
if (player.location.y > 3916 || player.skills.getLevel(Skills.AGILITY) >= 52) {
core.game.global.action.DoorActionHandler.handleAutowalkDoor(player, `object`)
if (player.location.y <= 3916) {
handleEntranceObstacle(player, `object`)
}
} else {
player.dialogueInterpreter.sendDialogue("You need an Agility level of at least 52 to enter.")
}
}
/**
* Handles the entrance obstacle.
* @param player the player.
* @param object the object.
*/
private fun handleEntranceObstacle(player: Player, `object`: Scenery) {
GameWorld.Pulser.submit(object : Pulse(1, player) {
var counter = 0
val fail = AgilityHandler.hasFailed(player, 1, 0.3)
override fun pulse(): Boolean {
when (++counter) {
2 -> {
val end = if (fail) Location.create(2998, 3924, 0) else if (`object`.id < 2309) Location.create(2998, 3917, 0) else Location.create(2998, 3930, 0)
val start = if (`object`.id < 2309) player.location else Location.create(2998, 3917, 0)
sendMessage(player, "You go through the gate and try to edge over the ridge...")
AgilityHandler.walk(player, -1, start, end, Animation.create(155), if (fail) 0.0 else 15.00, if (fail) "You lose your footing and fail into the wolf pit." else "You skillfully balance across the ridge...")
}
9 -> {
if (fail) {
AgilityHandler.fail(player, 0, player.location.transform(if (`object`.id < 2309) -2 else 2, 0, 0), Animation.create(if (`object`.id < 2309) 771 else 771), getHitAmount(player), null)
}
return fail
}
15 -> player.lock(3)
16 -> {
val doorLoc = if (`object`.id < 2309) Location(2998, 3917, 0) else Location(2998, 3931, 0)
core.game.global.action.DoorActionHandler.handleAutowalkDoor(player, RegionManager.getObject(doorLoc))
return true
}
}
return false
}
})
}
/**
* Handles the pipe obstacle.
* @param player the pipe.
* @param object the object.
*/
private fun handlePipe(player: Player, `object`: Scenery) {
if (`object`.location.y == 3948) {
sendMessage(player, "You can't do that from here.")
return
}
if (player.skills.getLevel(Skills.AGILITY) < 49) {
player.dialogueInterpreter.sendDialogue("You need an Agility level of at least 49 to do this.")
return
}
player.lock(10)
GameWorld.Pulser.submit(object : Pulse(1, player) {
var counter = 0
override fun pulse(): Boolean {
val x = 3004
when (counter++) {
0 -> {
AgilityHandler.forceWalk(player, -1, Location.create(x, 3937, 0), Location.create(x, 3940, 0), Animation.create(10580), 15, 0.0, null, 1) //10
println("1")
player.teleporter.send(Location.create(3004, 3947, 0), TeleportManager.TeleportType.INSTANT, TeleportManager.WILDY_TELEPORT)
println("tele")
counter++
AgilityHandler.forceWalk(player, 0, Location.create(x, 3948, 0), Location.create(x, 3950, 0), Animation.create(10579), 20, 12.5, null, 5) //20
println("3")
return true
}
2 -> {
player.teleporter.send(Location.create(3004, 3947, 0), TeleportManager.TeleportType.INSTANT, TeleportManager.WILDY_TELEPORT)
println("tele")
counter++
AgilityHandler.forceWalk(player, 0, Location.create(x, 3948, 0), Location.create(x, 3950, 0), Animation.create(10579), 20, 12.5, null, 5)
println("3")
return true
}
3 -> {
AgilityHandler.forceWalk(player, 0, Location.create(x, 3948, 0), Location.create(x, 3950, 0), Animation.create(10579), 20, 12.5, null, 5)
println("3")
return true
}
}
return true
}
})
}
/**
* Handles the rope swing obstacle.
* @param player the player.
* @param object the object.
*/
private fun handleRopeSwing(player: Player, `object`: Scenery) {
if (player.location.y < 3554) {
sendMessage(player, "You cannot do that from here.")
return
}
if (content.global.skill.agility.WildernessCourse.Companion.ropeDelay > GameWorld.ticks) {
sendMessage(player, "The rope is being used.")
return
}
if (AgilityHandler.hasFailed(player, 1, 0.1)) {
AgilityHandler.fail(player, 0, Location.create(3005, 10357, 0), null, getHitAmount(player), "You slip and fall to the pit below.")
return
}
content.global.skill.agility.WildernessCourse.Companion.ropeDelay = GameWorld.ticks + 2
player.packetDispatch.sendSceneryAnimation(`object`, Animation.create(497), true)
AgilityHandler.forceWalk(player, 1, player.location, Location.create(3005, 3958, 0), Animation.create(751), 50, 20.0, "You skillfully swing across.", 1)
}
/**
* Handles the stepping stone obstacle.
* @param player the player.
* @param object the object.
*/
private fun handleSteppingStones(player: Player, `object`: Scenery) {
lock(player, 50)
val fail = AgilityHandler.hasFailed(player, 1, 0.3)
val origLoc = player.location
registerLogoutListener(player, "steppingstone"){p ->
teleport(p, origLoc)
}
submitWorldPulse(object : Pulse(2, player){
var counter = 0
override fun pulse(): Boolean {
if (counter == 3 && fail) {
AgilityHandler.fail(player, -1, Location.create(3001, 3963, 0), Animation.create(771), (player.skills.lifepoints * 0.26).toInt(), "...You lose your footing and fall into the lava.")
return true
}
AgilityHandler.forceWalk(player, if (counter == 5) 2 else -1, player.location, player.location.transform(-1, 0, 0), Animation.create(741), 10, if (counter == 5) 20.0 else 0.0, if (counter != 0) null else "You carefully start crossing the stepping stones...")
if(++counter == 6){
unlock(player)
clearLogoutListener(player, "steppingstone")
}
return counter == 6
}
})
}
/**
* Handles the log balance obstacle.
* @param player the player.
* @param object the object.
*/
private fun handleLogBalance(player: Player, `object`: Scenery) {
val failed = AgilityHandler.hasFailed(player, 1, 0.5)
val end = if (failed) Location.create(2998, 3945, 0) else Location.create(2994, 3945, 0)
sendMessage(player, "You walk carefully across the slippery log...")
AgilityHandler.walk(player, if (failed) -1 else 3, player.location, end, Animation.create(155), if (failed) 0.0 else 20.0, if (failed) null else "You skillfully edge across the gap.")
if (failed) {
GameWorld.Pulser.submit(object : Pulse(5, player) {
override fun pulse(): Boolean {
player.faceLocation(Location.create(2998, 3944, 0))
AgilityHandler.fail(player, 3, Location.create(2998, 10345, 0), Animation.create(770), getHitAmount(player), "You slip and fall onto the spikes below.")
return true
}
})
return
}
}
/**
* Handles the rock climbing obstacle.
* @param player the player.
* @param object the object.
*/
private fun handleRockClimb(player: Player, `object`: Scenery) {
AgilityHandler.forceWalk(player, 4, Location.create(2994, 3937, 0), Location.create(2994, 3933, 0), Animation.create(740), 8, 0.0, "You reach the top.")
GameWorld.Pulser.submit(object : Pulse(4, player) {
override fun pulse(): Boolean {
player.animator.reset()
return true
}
})
}
override fun getDestination(node: Node, n: Node): Location? {
when (n.id) {
2283 -> return Location.create(3005, 3953, 0)
37704 -> return Location.create(3002, 3960, 0)
2297 -> return Location.create(3002, 3945, 0)
2328 -> return n.location.transform(0, 1, 0)
}
return null
}
override fun configure() {
SceneryDefinition.forId(2309).handlers["option:open"] = this
SceneryDefinition.forId(2308).handlers["option:open"] = this
SceneryDefinition.forId(2307).handlers["option:open"] = this
SceneryDefinition.forId(2288).handlers["option:squeeze-through"] = this
SceneryDefinition.forId(2283).handlers["option:swing-on"] = this
SceneryDefinition.forId(37704).handlers["option:cross"] = this
SceneryDefinition.forId(2297).handlers["option:walk-across"] = this
SceneryDefinition.forId(2328).handlers["option:climb"] = this
}
override fun createInstance(player: Player): AgilityCourse {
return content.global.skill.agility.WildernessCourse(player)
}
companion object {
/**
* The rope delay.
*/
private var ropeDelay = 0
}
}
@@ -0,0 +1,56 @@
package content.global.skill.agility.brimhaven;
import content.global.skill.agility.AgilityHandler;
import core.game.node.entity.Entity;
import core.game.node.entity.player.Player;
import core.game.system.task.MovementHook;
import core.game.system.task.Pulse;
import kotlin.Unit;
import core.game.world.GameWorld;
import core.game.world.map.Direction;
import core.game.world.map.Location;
import core.game.world.map.RegionManager;
import core.game.world.update.flag.context.Animation;
/**
* Handles the blade trap.
* @author Emperor
*/
public final class BladeTrap implements MovementHook {
@Override
public boolean handle(Entity e, final Location l) {
if (BrimhavenArena.sawBladeActive) {
final Direction dir = e.getDirection();
final Player player = (Player) e;
final Location start = l.transform(-dir.getStepX(), -dir.getStepY(), 0);
e.lock(5);
if(e.isPlayer())
{
e.asPlayer().logoutListeners.put("blade-trap", p -> {
p.setLocation(start);
return Unit.INSTANCE;
});
}
GameWorld.getPulser().submit(new Pulse(2, e) {
@Override
public boolean pulse() {
Direction direction = dir;
Direction d = Direction.get(direction.toInteger() + 2 & 3);
if (RegionManager.getObject(player.getLocation().transform(dir)) != null) {
Direction s = d;
d = direction;
direction = s;
}
Location loc = player.getLocation();
AgilityHandler.failWalk(player, 1, loc, loc.transform(direction), loc.transform(direction), Animation.create(846), 10, 3, "You were hit by the saw blade!").setDirection(d);
player.logoutListeners.remove("blade-trap");
return true;
}
});
return false;
}
return true;
}
}
@@ -0,0 +1,334 @@
package content.global.skill.agility.brimhaven;
import core.game.component.Component;
import core.game.global.action.ClimbActionHandler;
import core.game.interaction.Option;
import core.game.node.Node;
import core.game.node.entity.Entity;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.HintIconManager;
import core.game.node.entity.player.link.diary.DiaryType;
import core.game.node.item.GroundItem;
import core.game.node.item.GroundItemManager;
import core.game.node.item.Item;
import core.game.node.scenery.Scenery;
import core.game.node.scenery.SceneryBuilder;
import core.game.system.task.MovementHook;
import core.game.system.task.Pulse;
import core.game.world.GameWorld;
import core.game.world.map.*;
import core.game.world.map.zone.MapZone;
import core.game.world.map.zone.ZoneBuilder;
import core.game.world.update.flag.context.Animation;
import core.plugin.Initializable;
import core.plugin.Plugin;
import core.tools.RandomFunction;
import java.util.HashMap;
import java.util.Map;
/**
* Handles the Brimhaven agility arena zone.
*
* @author Emperor
*/
@Initializable
public final class BrimhavenArena extends MapZone implements Plugin<Object> {
/**
* The location based traps.
*/
private static final Map<Location, MovementHook> LOCATION_TRAPS = new HashMap<>();
/**
* The overlay component.
*/
private static final Component OVERLAY = new Component(5);
/**
* The ticket dispenser locations.
*/
private static final Location[] DISPENSERS = new Location[24];
/**
* The agility ticket reward item.
*/
private static final Item TICKET = new Item(2996);
/**
* If the saw blade is currently active.
*/
public static boolean sawBladeActive;
/**
* Constructs a new {@code BrimhavenArena} {@code Object}.
*/
public BrimhavenArena() {
super("Brimhaven agility arena", true);
}
/**
* Sets the current ticket dispenser target.
*
* @param player The player.
*/
private void setDispenser(Player player) {
if (!player.getAttribute("brim-tagged", false)) {
player.setAttribute("brim-tagcount", 0);
}
player.setAttribute("brim-tagged", false);
player.getConfigManager().set(309, 0);
int index = RandomFunction.randomize(DISPENSERS.length);
if (index == player.getAttribute("brim-tag", -1)) {
index = (index + 1) % DISPENSERS.length;
}
int iconSlot = player.getAttribute("brim-icon", -1);
if (iconSlot > -1) {
HintIconManager.removeHintIcon(player, iconSlot);
}
player.setAttribute("brim-tag", index);
player.setAttribute("brim-icon", HintIconManager.registerHeightHintIcon(player, DISPENSERS[index], 50));
}
@Override
public boolean enter(Entity entity) {
if (entity instanceof Player) {
Player player = (Player) entity;
player.getInterfaceManager().openOverlay(OVERLAY);
setDispenser(player);
}
return super.enter(entity);
}
@Override
public boolean leave(Entity entity, boolean logout) {
if (entity instanceof Player && !logout) {
Player player = (Player) entity;
player.getInterfaceManager().closeOverlay();
player.removeAttribute("brim-tag");
player.removeAttribute("brim-tagcount");
int iconSlot = player.getAttribute("brim-icon", -1);
if (iconSlot > -1) {
HintIconManager.removeHintIcon(player, iconSlot);
player.removeAttribute("brim-icon");
}
}
return super.enter(entity);
}
@Override
public boolean interact(Entity entity, Node node, Option option) {
if (node instanceof Scenery) {
Scenery object = (Scenery) node;
if (object.getId() == 3610) {
ClimbActionHandler.climb((Player) entity, Animation.create(828), object.getLocation().transform(0, 0, 3));
return true;
}
if (object.getId() == 3608 || object.getId() == 3581) {
Player player = (Player) entity;
if (!object.getLocation().equals(DISPENSERS[player.getAttribute("brim-tag", 0)])) {
player.getPacketDispatch().sendMessage("Tag the pillar indicated by the yellow arrow to get an Agility ticket.");
return true;
}
if (player.getAttribute("brim-tagged", false)) {
player.getPacketDispatch().sendMessage("You have already tagged this pillar.");
return true;
}
player.setAttribute("brim-tagged", true);
int tags = player.getAttribute("brim-tagcount", 0) + 1;
player.setAttribute("brim-tagcount", tags);
player.getConfigManager().set(309, 4);
if (tags > 1) {
int amount = 1;
if (!player.getInventory().add(new Item(TICKET.getId(), amount))) {
GroundItemManager.create(new GroundItem(new Item(TICKET.getId(), amount), player.getLocation(), player));
}
player.getAchievementDiaryManager().finishTask(player, DiaryType.KARAMJA, 1, 0);
player.getDialogueInterpreter().sendItemMessage(TICKET.getId(), "You have received an Agility Arena Ticket!");
player.getPacketDispatch().sendMessage("You have received an Agility Arena Ticket!");
return true;
}
player.getPacketDispatch().sendMessage("You get tickets by tagging more than one pillar in a row, tag the next pillar!");
player.getDialogueInterpreter().sendDialogue("You get tickets by tagging more than one pillar in a row. <col=C04000>Tag the", "<col=C04000>next pillar for a ticket!</col>");
return true;
}
}
return false;
}
@Override
public boolean move(Entity e, Location loc, Location dest) {
if (!e.getLocks().isMovementLocked() && e instanceof Player) {
MovementHook hook = LOCATION_TRAPS.get(loc);
if (hook != null) {
e.setDirection(Direction.getLogicalDirection(loc, dest));
return hook.handle(e, loc);
}
}
return super.move(e, loc, dest);
}
@Override
public void locationUpdate(Entity e, Location last) {
if (!e.getLocks().isMovementLocked() && e instanceof Player) {
MovementHook hook = LOCATION_TRAPS.get(e.getLocation());
if (hook != null) {
if (!hook.handle(e, e.getLocation())) {
if (e.getPulseManager().isMovingPulse()) {
e.getPulseManager().clear();
}
e.getWalkingQueue().reset();
}
}
}
}
@Override
public void configure() {
registerRegion(11157);
PressurePad pad = new PressurePad();
LOCATION_TRAPS.put(Location.create(2800, 9579, 3), pad);
LOCATION_TRAPS.put(Location.create(2799, 9579, 3), pad);
LOCATION_TRAPS.put(Location.create(2800, 9557, 3), pad);
LOCATION_TRAPS.put(Location.create(2799, 9557, 3), pad);
LOCATION_TRAPS.put(Location.create(2772, 9585, 3), pad);
LOCATION_TRAPS.put(Location.create(2772, 9584, 3), pad);
FloorSpikes spikes = new FloorSpikes();
LOCATION_TRAPS.put(Location.create(2800, 9568, 3), spikes);
LOCATION_TRAPS.put(Location.create(2799, 9568, 3), spikes);
LOCATION_TRAPS.put(Location.create(2772, 9552, 3), spikes);
LOCATION_TRAPS.put(Location.create(2772, 9551, 3), spikes);
LOCATION_TRAPS.put(Location.create(2761, 9573, 3), spikes);
LOCATION_TRAPS.put(Location.create(2761, 9574, 3), spikes);
DartTrap dart = new DartTrap();
LOCATION_TRAPS.put(Location.create(2788, 9557, 3), dart);
LOCATION_TRAPS.put(Location.create(2789, 9557, 3), dart);
LOCATION_TRAPS.put(Location.create(2794, 9573, 3), dart);
LOCATION_TRAPS.put(Location.create(2794, 9574, 3), dart);
LOCATION_TRAPS.put(Location.create(2777, 9568, 3), dart);
LOCATION_TRAPS.put(Location.create(2778, 9568, 3), dart);
SpinningBlades blade = new SpinningBlades();
LOCATION_TRAPS.put(Location.create(2778, 9579, 3), blade);
LOCATION_TRAPS.put(Location.create(2783, 9574, 3), blade);
LOCATION_TRAPS.put(Location.create(2778, 9557, 3), blade);
BladeTrap trap = new BladeTrap();
LOCATION_TRAPS.put(Location.create(2788, 9579, 3), trap);
LOCATION_TRAPS.put(Location.create(2789, 9579, 3), trap);
LOCATION_TRAPS.put(Location.create(2783, 9551, 3), trap);
LOCATION_TRAPS.put(Location.create(2783, 9552, 3), trap);
LOCATION_TRAPS.put(Location.create(2761, 9584, 3), trap);
LOCATION_TRAPS.put(Location.create(2761, 9585, 3), trap);
int index = 0;
for (int x = 2761; x < 2815; x += 11) {
for (int y = 9546; y < 9600; y += 11) {
if (x == 2805 && y == 9590) {
continue;
}
DISPENSERS[index++] = Location.create(x, y, 3);
}
}
GameWorld.getPulser().submit(new Pulse(1) {
@Override
public boolean pulse() {
Region r = RegionManager.forId(11157);
if (!r.isActive()) {
return false;
}
if (GameWorld.getTicks() % 100 == 0) {
for (RegionPlane plane : r.getPlanes()) {
for (Player player : plane.getPlayers()) {
setDispenser(player);
}
}
handlePlankSwitching();
}
int ticks = 3;
if (GameWorld.getTicks() % ticks == 0) {
sawBladeActive = !sawBladeActive;
if (sawBladeActive) {
Scenery object = RegionManager.getObject(3, 2788, 9579);
SceneryBuilder.replace(object, object.transform(3567, object.getRotation(), 10), ticks);
object = RegionManager.getObject(3, 2789, 9579);
SceneryBuilder.replace(object, object.transform(0), ticks);
object = RegionManager.getObject(3, 2783, 9551);
SceneryBuilder.replace(object, object.transform(3567, object.getRotation(), 10), ticks);
object = RegionManager.getObject(3, 2783, 9552);
SceneryBuilder.replace(object, object.transform(0), ticks);
object = RegionManager.getObject(3, 2761, 9584);
SceneryBuilder.replace(object, object.transform(3567, object.getRotation(), 10), ticks);
object = RegionManager.getObject(3, 2761, 9585);
SceneryBuilder.replace(object, object.transform(0), ticks);
}
}
return false;
}
});
}
/**
* Switches the plank states.
*/
private static void handlePlankSwitching() {
boolean[] available = new boolean[3];
for (int i = 0; i < 1 + RandomFunction.randomize(2); i++) {
available[RandomFunction.randomize(3)] = true;
}
for (int i = 0; i < 3; i++) {
boolean avail = available[i];
for (PlankSet set : PlankSet.values()) {
Location l = set.entrance[i];
for (int x = 1; x < set.exit[i].getX() - l.getX(); x++) {
Scenery object = RegionManager.getObject(l.transform(x, 0, 0));
if(object != null)
SceneryBuilder.replace(object, object.transform(avail ? 3573 : 3576));
}
RegionManager.getObject(set.entrance[i]).setCharge(avail ? 1000 : 500);
RegionManager.getObject(set.exit[i]).setCharge(avail ? 1000 : 500);
}
}
}
/**
* The plank obstacles.
*
* @author Emperor
*/
private static enum PlankSet {
FIRST(new Location[]{Location.create(2797, 9591, 3), Location.create(2797, 9590, 3), Location.create(2797, 9589, 3)}, new Location[]{Location.create(2802, 9591, 3), Location.create(2802, 9590, 3), Location.create(2802, 9589, 3)}), SECOND(new Location[]{Location.create(2764, 9558, 3), Location.create(2764, 9557, 3), Location.create(2764, 9556, 3)}, new Location[]{Location.create(2769, 9558, 3), Location.create(2769, 9557, 3), Location.create(2769, 9556, 3)});
/**
* Constructs a new {@code PlankSet} {@code Object}.
*
* @param entrance The entrance locations for each plank.
* @param exit The exit locations for each plank.
*/
private PlankSet(Location[] entrance, Location[] exit) {
this.entrance = entrance;
this.exit = exit;
}
/**
* The entrance location of the plank.
*/
Location[] entrance;
/**
* The exit location of the plank.
*/
Location[] exit;
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ZoneBuilder.configure(this);
return this;
}
@Override
public Object fireEvent(String identifier, Object... args) {
return null;
}
}
@@ -0,0 +1,419 @@
package content.global.skill.agility.brimhaven;
import core.cache.def.impl.SceneryDefinition;
import core.plugin.Initializable;
import core.game.node.entity.skill.Skills;
import content.global.skill.agility.AgilityHandler;
import core.game.interaction.OptionHandler;
import core.game.node.Node;
import core.game.node.entity.impl.ForceMovement;
import core.game.node.entity.player.Player;
import core.game.node.scenery.Scenery;
import core.game.system.task.Pulse;
import kotlin.Unit;
import core.game.world.GameWorld;
import core.game.world.map.Direction;
import core.game.world.map.Location;
import core.game.world.update.flag.context.Animation;
import core.plugin.Plugin;
/**
* The brimhaven course handling plugin.
* @author Emperor
*/
@Initializable
public final class BrimhavenCourse extends OptionHandler {
@Override
public boolean handle(final Player player, Node node, String option) {
final Scenery object = (Scenery) node;
Direction dir = object.getDirection();
Location start = player.getLocation();
switch (object.getId()) {
case 3566:
// Rope swing
start = object.getLocation().transform(dir.getStepX() << 1, dir.getStepY() << 1, 0);
Location end = object.getLocation().transform(-dir.getStepX() * 3, -dir.getStepY() * 3, 0);
if (AgilityHandler.hasFailed(player, 1, 0.1)) {
AgilityHandler.failWalk(player, 2, start, start.transform(-dir.getStepX(), -dir.getStepY(), 0), player.getLocation().transform(0, 0, -3), Animation.create(1105), 26, getHitAmount(player), "You missed the rope!").setEndAnimation(Animation.RESET);
return true;
}
AgilityHandler.forceWalk(player, -1, start, end, Animation.create(751), 25, getExp(player, 20.0), null);
GameWorld.getPulser().submit(new Pulse(1, player) {
boolean finish;
@Override
public boolean pulse() {
if (!finish) {
player.getPacketDispatch().sendSceneryAnimation(object, Animation.create(1052));
finish = true;
return false;
}
player.getPacketDispatch().sendSceneryAnimation(object, Animation.create(-1));
return true;
}
});
return true;
case 3578:
// Pillars
handlePillarObstacle(player, object);
return true;
case 3565:
// Low wall
dir = Direction.getLogicalDirection(player.getLocation(), object.getLocation());
start = player.getLocation();
if (AgilityHandler.hasFailed(player, 1, 0.05)) {
end = start.transform(dir);
AgilityHandler.failWalk(player, 2, start, end, end, Animation.create(1106), 15, getHitAmount(player), "You lost your balance!");
AgilityHandler.forceWalk(player, -1, end, player.getLocation(), ForceMovement.WALK_ANIMATION, 10, 0.0, null, 4);
return true;
}
AgilityHandler.forceWalk(player, -1, start, start.transform(dir.getStepX() * 3, dir.getStepY() * 3, 0), Animation.create(1252), 6, getExp(player, 8.0), null);
return true;
case 3553:
case 3557:
handleLogBalance(player, object);
return true;
case 3570:
case 3571:
case 3572:
handlePlankObstacle(player, object);
return true;
case 3559:
case 3561:
handleBalancingLedge(player, object);
return true;
case 3564:
handleMonkeyBars(player, object);
return true;
case 3551:
handleBalancingRope(player, object);
return true;
case 3583:
handleHandHolds(player, object);
return true;
}
return false;
}
/**
* Handles the hand holds obstacle.
* @param player The player.
* @param object The object.
*/
private static void handleHandHolds(final Player player, final Scenery object) {
if (player.getSkills().getLevel(Skills.AGILITY) < 20) {
player.getPacketDispatch().sendMessage("You need an agility of at least 20 to get past this obstacle!");
return;
}
int mod = 0;
Direction direction = object.getDirection();
int x = object.getLocation().getX();
int y = object.getLocation().getY();
if ((x == 2785 && y == 9544) || (x == 2759 && y == 9566) || (x == 2792 && y == 9592)) {
mod = 4;
direction = Direction.get(direction.toInteger() + 2 & 3);
}
final int m = mod;
player.lock(5);
final Direction dir = direction;
final Direction faceDirection = Direction.get(object.getDirection().toInteger() - 1 & 3);
final Location start = player.getLocation();
player.getAppearance().setAnimations(Animation.create(1118 + m));
player.getAppearance().sync();
AgilityHandler.climb(player, -1, new Animation(1117 + m), start.transform(dir), 0.0, null);
player.logoutListeners.put("brimcourse", p -> {
p.setLocation(start);
return Unit.INSTANCE;
});
GameWorld.getPulser().submit(new Pulse(3, player) {
Location last = start.transform(dir);
int count;
@Override
public boolean pulse() {
if (++count == 1) {
if (AgilityHandler.hasFailed(player, 1, 0.15)) {
player.getAppearance().setAnimations();
player.getAppearance().sync();
AgilityHandler.fail(player, 2, last.transform(0, 0, -3), Animation.create(1119 + m), getHitAmount(player), "You missed a hand hold!");
player.logoutListeners.remove("brimcourse");
return true;
}
} else if (count == 6) {
player.getAppearance().setAnimations();
player.getAppearance().sync();
AgilityHandler.forceWalk(player, -1, last, last.transform(dir), Animation.create(1120 + m), 5, getExp(player, 22.0), null).setDirection(faceDirection);
player.logoutListeners.remove("brimcourse");
return true;
}
player.logoutListeners.remove("brimcourse");
AgilityHandler.forceWalk(player, -1, last, last = last.transform(dir), Animation.create(1118 + m), 5, 0.0, null).setDirection(faceDirection);
return false;
}
});
}
/**
* Handles the balancing rope obstacle.
* @param player The player.
* @param object The balancing rope object.
*/
private static void handleBalancingRope(final Player player, Scenery object) {
final Direction dir = object.getDirection();
boolean failed = AgilityHandler.hasFailed(player, 1, 0.1);
if (failed) {
Location end = player.getLocation().transform(dir);
AgilityHandler.forceWalk(player, -1, player.getLocation(), end, Animation.create(762), 10, 0.0, null);
GameWorld.getPulser().submit(new Pulse(2, player) {
@Override
public boolean pulse() {
Direction d = Direction.get((dir.toInteger() + 3) % 4);
AgilityHandler.fail(player, 2, player.getLocation().transform(d.getStepX() << 1, d.getStepY() << 1, -3), Animation.create(764), getHitAmount(player), "You lost your balance!");
return true;
}
});
return;
}
AgilityHandler.walk(player, -1, player.getLocation(), player.getLocation().transform(dir.getStepX() * 7, dir.getStepY() * 7, 0), Animation.create(155), getExp(player, 10.0), null);
}
/**
* Handles the monkey bars obstacle.
* @param player The player.
* @param object The object.
*/
private static void handleMonkeyBars(final Player player, Scenery object) {
player.lock(5);
final Direction dir = Direction.get((object.getDirection().toInteger() + 2) % 4);
player.getAppearance().setAnimations(Animation.create(745));
final Location start = player.getLocation();
ForceMovement.run(player, start.transform(dir), start.transform(dir.getStepX() << 1, dir.getStepY() << 1, 0), Animation.create(742), Animation.create(744));
player.logoutListeners.put("brimcourse", p -> {
p.setLocation(start);
return Unit.INSTANCE;
});
GameWorld.getPulser().submit(new Pulse(2, player) {
boolean failed;
int count;
@Override
public boolean pulse() {
if (++count == 1) {
if (failed = AgilityHandler.hasFailed(player, 1, 0.15)) {
setDelay(1);
player.animate(Animation.create(743));
return false;
}
setDelay(7);
AgilityHandler.walk(player, -1, player.getLocation().transform(dir), player.getLocation().transform(dir.getStepX() * 7, dir.getStepY() * 7, 0), Animation.create(662), 0.0, null);
} else if (count == 2) {
if (failed) {
player.getAppearance().setAnimations();
player.getAppearance().sync();
AgilityHandler.fail(player, 2, player.getLocation().transform(0, 0, -3), Animation.create(768), getHitAmount(player), "You missed a hand hold!");
player.logoutListeners.remove("brimcourse");
return true;
}
player.logoutListeners.remove("brimcourse");
AgilityHandler.forceWalk(player, -1, player.getLocation(), player.getLocation().transform(dir), Animation.create(743), 10, getExp(player, 14.0), null);
return true;
}
return false;
}
});
}
/**
* Handles the balancing ledge obstacle.
* @param player The player.
* @param object The object.
*/
private static void handleBalancingLedge(final Player player, Scenery object) {
final int diff = object.getId() == 3561 ? 0 : 1;
Location start = player.getLocation();
final Direction dir = Direction.getLogicalDirection(start, object.getLocation());
Location end = object.getLocation();
double xp = 0.0;
if (AgilityHandler.hasFailed(player, 1, 0.15)) {
player.lock(3);
GameWorld.getPulser().submit(new Pulse(2, player) {
@Override
public boolean pulse() {
Direction d = Direction.get((dir.toInteger() + 1) % 4);
AgilityHandler.fail(player, 1, player.getLocation().transform(d.getStepX(), d.getStepY(), -3), Animation.create(761 - diff), getHitAmount(player), "You lost your balance!");
return true;
}
});
} else {
xp = 16.0;
end = object.getLocation().transform(dir.getStepX() * 6, dir.getStepY() * 6, 0);
}
AgilityHandler.walk(player, -1, player.getLocation(), end, Animation.create(157 - diff), getExp(player, xp), null);
}
/**
* Handles the plank obstacle.
* @param player The player.
* @param object The object.
*/
private static void handlePlankObstacle(final Player player, Scenery object) {
final Direction dir = Direction.getLogicalDirection(player.getLocation(), object.getLocation());
final Location start = player.getLocation();
Location end = start.transform(dir.getStepX() * 7, dir.getStepY() * 7, 0);
player.faceLocation(end);
if (object.getCharge() == 500) { // Plank is broken
player.lock(7);
AgilityHandler.walk(player, -1, start, start.transform(dir.getStepX() * 2, dir.getStepY() * 2, 0), new Animation(1426), 0.0, null);
GameWorld.getPulser().submit(new Pulse(3) {
boolean finish;
@Override
public boolean pulse() {
if (!finish) {
setDelay(2);
AgilityHandler.fail(player, 1, player.getLocation().transform(0, 0, -3), Animation.create(189), getHitAmount(player), "You stepped on a broken piece of plank!");
finish = true;
return false;
}
AgilityHandler.walk(player, -1, player.getLocation(), start.transform(dir), null, 0.0, null);
return true;
}
});
return;
}
AgilityHandler.walk(player, -1, start, end, ForceMovement.WALK_ANIMATION, getExp(player, 6.0), null);
}
/**
* Handles the pillars obstacle.
* @param player The player.
* @param object The object.
*/
private static void handlePillarObstacle(final Player player, Scenery object) {
final Direction dir = Direction.getLogicalDirection(player.getLocation(), object.getLocation());
AgilityHandler.forceWalk(player, -1, player.getLocation(), object.getLocation(), Animation.create(741), 10, 0, null);
final Location start = player.getLocation();
player.logoutListeners.put("brimcourse", p -> {
p.setLocation(start);
return Unit.INSTANCE;
});
player.lock(12);
GameWorld.getPulser().submit(new Pulse(2, player) {
int count = 0;
@Override
public boolean pulse() {
if (count == 0 && AgilityHandler.hasFailed(player, 1, 0.15)) {
Direction d = Direction.get((dir.toInteger() + 3) % 4);
player.unlock();
player.lock(2);
AgilityHandler.fail(player, 2, player.getLocation().transform(d.getStepX() << 1, d.getStepY() << 1, -3), Animation.create(764), getHitAmount(player), "You lost your balance!");
player.logoutListeners.remove("brimcourse");
return true;
}
AgilityHandler.forceWalk(player, -1, player.getLocation(), player.getLocation().transform(dir), Animation.create(741), 10, count == 5 ? getExp(player, 18.0) : 0, null);
player.logoutListeners.remove("brimcourse");
return ++count == 6;
}
});
}
/**
* Handles the log balance obstacle.
* @param player The player.
* @param object The log balance object.
*/
private static void handleLogBalance(final Player player, Scenery object) {
final Direction dir = Direction.getLogicalDirection(player.getLocation(), object.getLocation());
boolean failed = AgilityHandler.hasFailed(player, 1, 0.1);
if (failed) {
Location end = player.getLocation().transform(dir);
AgilityHandler.forceWalk(player, -1, player.getLocation(), end, Animation.create(762), 10, 0.0, null);
GameWorld.getPulser().submit(new Pulse(2, player) {
@Override
public boolean pulse() {
Direction d = Direction.get((dir.toInteger() + 3) % 4);
AgilityHandler.fail(player, 2, player.getLocation().transform(d.getStepX() << 1, d.getStepY() << 1, -3), Animation.create(764), getHitAmount(player), "You lost your balance!");
return true;
}
});
return;
}
AgilityHandler.walk(player, -1, player.getLocation(), player.getLocation().transform(dir.getStepX() * 7, dir.getStepY() * 7, 0), Animation.create(155), getExp(player, 12.0), null);
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
SceneryDefinition.forId(3566).getHandlers().put("option:swing-on", this);
SceneryDefinition.forId(3578).getHandlers().put("option:jump-on", this);
SceneryDefinition.forId(3565).getHandlers().put("option:climb-over", this);
SceneryDefinition.forId(3553).getHandlers().put("option:walk-on", this);
SceneryDefinition.forId(3557).getHandlers().put("option:walk-on", this);
SceneryDefinition.forId(3570).getHandlers().put("option:walk-on", this);
SceneryDefinition.forId(3571).getHandlers().put("option:walk-on", this);
SceneryDefinition.forId(3572).getHandlers().put("option:walk-on", this);
SceneryDefinition.forId(3559).getHandlers().put("option:walk-across", this);
SceneryDefinition.forId(3561).getHandlers().put("option:walk-across", this);
SceneryDefinition.forId(3564).getHandlers().put("option:swing-across", this);
SceneryDefinition.forId(3551).getHandlers().put("option:walk-on", this);
SceneryDefinition.forId(3583).getHandlers().put("option:climb-across", this);
return this;
}
@Override
public Location getDestination(Node node, Node n) {
Scenery object = (Scenery) n;
Direction dir = object.getDirection();
switch (object.getId()) {
case 3566:
return n.getLocation().transform(dir.getStepX() << 1, dir.getStepY() << 1, 0);
case 3564:
if (n.getLocation().getX() == 2771 && n.getLocation().getY() == 9570) {
return Location.create(2772, 9569, 3);
}
if (n.getLocation().getX() == 2771 && n.getLocation().getY() == 9577) {
return Location.create(2772, 9578, 3);
}
if (n.getLocation().getX() == 2793 && n.getLocation().getY() == 9566) {
return Location.create(2794, 9567, 3);
}
if (n.getLocation().getX() == 2793 && n.getLocation().getY() == 9559) {
return Location.create(2794, 9558, 3);
}
if (n.getLocation().getX() == 2781 && n.getLocation().getY() == 9545) {
return Location.create(2782, 9546, 3);
}
if (n.getLocation().getX() == 2774 && n.getLocation().getY() == 9545) {
return Location.create(2773, 9546, 3);
}
break;
case 3551:
return n.getLocation();
}
return null;
}
/**
* Gets the exp.
* @param player the player.
* @param exp the exp.
* @return the exp.
*/
private static double getExp(Player player, double exp) {
return player.getAchievementDiaryManager().getKaramjaGlove() > 1 ? exp + (exp * 0.10) : exp;
}
/**
* Gets the amount of damage to deal.
* @param player The player.
* @return The amount of damage.
*/
private static int getHitAmount(Player player) {
int hit = player.getSkills().getLifepoints() / 12;
if (hit < 2) {
hit = 2;
}
return hit;
}
}
@@ -0,0 +1,101 @@
package content.global.skill.agility.brimhaven;
import core.game.node.entity.skill.Skills;
import content.global.skill.agility.AgilityHandler;
import core.game.node.entity.Entity;
import core.game.node.entity.impl.Projectile;
import core.game.node.entity.player.Player;
import core.game.system.task.MovementHook;
import core.game.system.task.Pulse;
import kotlin.Unit;
import core.game.world.GameWorld;
import core.game.world.map.Direction;
import core.game.world.map.Location;
import core.game.world.update.flag.context.Animation;
import core.net.packet.PacketRepository;
import core.net.packet.context.CameraContext;
import core.net.packet.context.CameraContext.CameraType;
import core.net.packet.out.CameraViewPacket;
import core.tools.RandomFunction;
/**
* Handles the darts trap.
* @author Emperor
*/
public final class DartTrap implements MovementHook {
@Override
public boolean handle(Entity e, final Location l) {
final Direction dir = e.getDirection();
final Player player = (Player) e;
final Location start = l.transform(-dir.getStepX(), -dir.getStepY(), 0);
e.lock(6);
if(e.isPlayer())
{
e.asPlayer().logoutListeners.put("dart-trap", p -> {
p.setLocation(start);
return Unit.INSTANCE;
});
}
final Location startProj = l.transform(dir.getStepX() * 5, dir.getStepY() * 5, 0);
GameWorld.getPulser().submit(new Pulse(2, e) {
boolean failed;
int count;
@Override
public boolean pulse() {
if (++count == 1) {
if (failed = AgilityHandler.hasFailed(player, 40, 0.15)) {
if (player.getSkills().getLevel(Skills.AGILITY) < 40) {
player.getPacketDispatch().sendMessage("You need an agility of at least 40 to get past this trap!");
}
Projectile.create(startProj, l, 270, 0, 10, 46, 85, 5, 11).send();
setDelay(3);
} else {
PacketRepository.send(CameraViewPacket.class, new CameraContext(player, CameraType.POSITION, startProj.getX() + (dir.getStepX() * 4), startProj.getY() + (dir.getStepY() * 4), 350, 1, 100));
PacketRepository.send(CameraViewPacket.class, new CameraContext(player, CameraType.ROTATION, l.getX(), l.getY(), 350, 1, 100));
Projectile.create(startProj, l.transform(-dir.getStepX() * 4, -dir.getStepY() * 4, 0), 270, 0, 0, 46, 200, 5, 11).send();
}
} else if (count == 2) {
if (failed) {
int hit = player.getSkills().getLifepoints() / 12;
if (hit < 2) {
hit = 2;
}
setDelay(1);
AgilityHandler.failWalk(player, 1, l, start, start, Animation.create(1114), 10, hit, null).setDirection(dir);
} else {
if (dir.toInteger() % 2 != 0) {
int mod = dir == Direction.WEST ? -1 : 1;
PacketRepository.send(CameraViewPacket.class, new CameraContext(player, CameraType.POSITION, l.getX() - (5 * mod), l.getY() - (5 * mod), 400, 8, 6));
PacketRepository.send(CameraViewPacket.class, new CameraContext(player, CameraType.ROTATION, l.getX() + (2 * mod), l.getY(), 350, 8, 1));
} else {
int mod = dir == Direction.SOUTH ? -1 : 1;
PacketRepository.send(CameraViewPacket.class, new CameraContext(player, CameraType.POSITION, l.getX() + (5 * mod), l.getY() - (5 * mod), 400, 8, 6));
PacketRepository.send(CameraViewPacket.class, new CameraContext(player, CameraType.ROTATION, l.getX(), l.getY() + (2 * mod), 350, 8, 1));
}
player.lock(7);
player.animate(new Animation(1110, 20));
setDelay(5);
}
} else if (count == 3) {
if (failed) {
player.getPacketDispatch().sendMessage("You were hit by some darts, something on them makes you feel dizzy!");
player.getSkills().updateLevel(Skills.AGILITY, -(2 + RandomFunction.randomize(2)), 0);
player.logoutListeners.remove("dart-trap");
return true;
}
setDelay(2);
AgilityHandler.walk(player, -1, l, l.transform(dir.getStepX() << 1, dir.getStepY() << 1, 0), null, 30.0, null);
} else if (count == 4) {
PacketRepository.send(CameraViewPacket.class, new CameraContext(player, CameraType.RESET, 0, 0, 0, 0, 0));
player.logoutListeners.remove("dart-trap");
return true;
}
return false;
}
});
return false;
}
}
@@ -0,0 +1,59 @@
package content.global.skill.agility.brimhaven;
import core.game.node.entity.skill.Skills;
import content.global.skill.agility.AgilityHandler;
import core.game.node.entity.Entity;
import core.game.node.entity.player.Player;
import core.game.system.task.MovementHook;
import core.game.system.task.Pulse;
import kotlin.Unit;
import core.game.world.GameWorld;
import core.game.world.map.Direction;
import core.game.world.map.Location;
import core.game.world.map.RegionManager;
import core.game.world.update.flag.context.Animation;
/**
* Handles floor spikes trap.
* @author Emperor
*/
public final class FloorSpikes implements MovementHook {
@Override
public boolean handle(Entity e, final Location l) {
final Direction dir = e.getDirection();
final Player player = (Player) e;
final Location start = l.transform(-dir.getStepX(), -dir.getStepY(), 0);
e.lock(5);
if(e.isPlayer())
{
((Player) e).logoutListeners.put("floor-spikes", p -> {
p.setLocation(start);
return Unit.INSTANCE;
});
}
GameWorld.getPulser().submit(new Pulse(3, e) {
@Override
public boolean pulse() {
player.getPacketDispatch().sendSceneryAnimation(RegionManager.getObject(l), Animation.create(1111));
if (AgilityHandler.hasFailed(player, 20, 0.25)) {
if (player.getSkills().getLevel(Skills.AGILITY) < 20) {
player.getPacketDispatch().sendMessage("You need an agility of at least 20 to get past this trap!");
}
int hit = player.getSkills().getLifepoints() / 12;
if (hit < 2) {
hit = 2;
}
AgilityHandler.failWalk(player, 1, player.getLocation(), start, start, Animation.create(1114), 10, hit, "You were hit by some floor spikes!").setDirection(dir);
;
} else {
AgilityHandler.forceWalk(player, -1, l, l.transform(dir.getStepX() << 1, dir.getStepY() << 1, 0), Animation.create(1115), 20, 26, null);
}
player.logoutListeners.remove("floor-spikes");
return true;
}
});
return false;
}
}
@@ -0,0 +1,59 @@
package content.global.skill.agility.brimhaven;
import core.game.node.entity.skill.Skills;
import content.global.skill.agility.AgilityHandler;
import core.game.node.entity.Entity;
import core.game.node.entity.player.Player;
import core.game.system.task.MovementHook;
import core.game.system.task.Pulse;
import kotlin.Unit;
import core.game.world.GameWorld;
import core.game.world.map.Direction;
import core.game.world.map.Location;
import core.game.world.update.flag.context.Animation;
import core.game.world.update.flag.context.Graphics;
/**
* Handles the pressure pad trap.
* @author Emperor
*/
public final class PressurePad implements MovementHook {
@Override
public boolean handle(Entity e, final Location dest) {
final Direction dir = e.getDirection();
final Player player = (Player) e;
final Location start = dest.transform(-dir.getStepX(), -dir.getStepY(), 0);
e.lock(5);
if(e.isPlayer())
{
((Player) e).logoutListeners.put("pressure-pad", p -> {
p.setLocation(start);
return Unit.INSTANCE;
});
}
GameWorld.getPulser().submit(new Pulse(3, e) {
@Override
public boolean pulse() {
Graphics.send(Graphics.create(271), dest);
if (AgilityHandler.hasFailed(player, 20, 0.25)) {
if (player.getSkills().getLevel(Skills.AGILITY) < 20) {
player.getPacketDispatch().sendMessage("You need an agility of at least 20 to get past this trap!");
}
int hit = player.getSkills().getLifepoints() / 12;
if (hit < 2) {
hit = 2;
}
AgilityHandler.failWalk(player, 1, player.getLocation(), start, start, Animation.create(1114), 10, hit, "You were hit by some falling rocks!").setDirection(dir);
;
} else {
AgilityHandler.forceWalk(player, -1, dest, dest.transform(dir.getStepX() << 1, dir.getStepY() << 1, 0), Animation.create(1115), 20, 26, null);
}
player.logoutListeners.remove("pressure-pad");
return true;
}
});
return false;
}
}
@@ -0,0 +1,73 @@
package content.global.skill.agility.brimhaven;
import core.game.node.entity.skill.Skills;
import content.global.skill.agility.AgilityHandler;
import core.game.node.entity.Entity;
import core.game.node.entity.player.Player;
import core.game.system.task.MovementHook;
import core.game.system.task.Pulse;
import kotlin.Unit;
import core.game.world.GameWorld;
import core.game.world.map.Direction;
import core.game.world.map.Location;
import core.game.world.map.RegionManager;
import core.game.world.update.flag.context.Animation;
/**
* Handles the spinning blades trap.
* @author Emperor
*/
public final class SpinningBlades implements MovementHook {
@Override
public boolean handle(Entity e, final Location l) {
final Direction dir = e.getDirection();
final Player player = (Player) e;
final Location start = l.transform(-dir.getStepX(), -dir.getStepY(), 0);
e.lock(5);
if(e.isPlayer())
{
((Player) e).logoutListeners.put("spin-blades", p -> {
p.setLocation(start);
return Unit.INSTANCE;
});
}
GameWorld.getPulser().submit(new Pulse(3, e) {
@Override
public boolean pulse() {
sendObjectAnimation(player, l);
if (AgilityHandler.hasFailed(player, 40, 0.15)) {
if (player.getSkills().getLevel(Skills.AGILITY) < 40) {
player.getPacketDispatch().sendMessage("You need an agility of at least 40 to get past this trap!");
}
int hit = player.getSkills().getLifepoints() / 12;
if (hit < 2) {
hit = 2;
}
AgilityHandler.failWalk(player, 1, player.getLocation(), start, start, Animation.create(1114), 10, hit, "You were hit by the spinning blades.").setDirection(dir);
} else {
AgilityHandler.forceWalk(player, -1, l, l.transform(dir.getStepX() << 1, dir.getStepY() << 1, 0), Animation.create(1115), 20, 26, null);
}
player.logoutListeners.remove("spin-blades");
return true;
}
});
return false;
}
/**
* Sends the object animation for the spinning blades.
* @param player The player.
* @param l The location.
*/
private static void sendObjectAnimation(Player player, Location l) {
if (l.equals(Location.create(2778, 9579, 3))) {
l = Location.create(2777, 9580, 3);
} else if (l.equals(Location.create(2783, 9574, 3))) {
l = Location.create(2782, 9573, 3);
} else if (l.equals(Location.create(2778, 9557, 3))) {
l = Location.create(2777, 9556, 3);
}
player.getPacketDispatch().sendSceneryAnimation(RegionManager.getObject(l), Animation.create(1107));
}
}
@@ -0,0 +1,560 @@
package content.global.skill.agility.pyramid;
import core.cache.def.impl.VarbitDefinition;
import core.cache.def.impl.SceneryDefinition;
import core.game.global.action.ClimbActionHandler;
import core.plugin.Initializable;
import core.game.node.entity.skill.Skills;
import content.global.skill.agility.AgilityCourse;
import content.global.skill.agility.AgilityHandler;
import core.game.node.Node;
import core.game.node.entity.impl.ForceMovement;
import core.game.node.entity.player.Player;
import core.game.node.item.Item;
import core.game.node.scenery.Scenery;
import core.game.system.task.Pulse;
import core.game.world.GameWorld;
import core.game.world.map.Direction;
import core.game.world.map.Location;
import core.game.world.update.flag.context.Animation;
import core.plugin.ClassScanner;
/**
* Handles the agility pryamid course.
* @author Vexia
*/
@Initializable
public final class AgilityPyramidCourse extends AgilityCourse {
/**
* The pyramid top item.
*/
private static final Item PYRAMID_TOP = new Item(6970);
/**
* The config id to use.
*/
private static final int CONFIG_ID = 640;
/**
* The jump gap location data.
*/
private static final Location[][] GAP_LOCATIONS = new Location[][] { { new Location(3356, 2847, 2), Location.create(3357, 2847, 2), Location.create(3356, 2846, 2), Location.create(3357, 2846, 2), Location.create(3356, 2849, 2), Location.create(3357, 2849, 2) }, { new Location(3364, 2833, 2), Location.create(3364, 2834, 2), Location.create(3366, 2834, 2), Location.create(3366, 2833, 2), Location.create(3363, 2834, 2), Location.create(3363, 2833, 2) }, { new Location(3370, 2841, 3), new Location(3371, 2841, 3), Location.create(3370, 2840, 3), Location.create(3371, 2840, 3), Location.create(3370, 2843, 3), Location.create(3371, 2843, 3) }, { new Location(3040, 4697, 2), Location.create(3041, 4697, 2), Location.create(3041, 4696, 2), Location.create(3040, 4696, 2), Location.create(3041, 4699, 2), Location.create(3040, 4699, 2) }, { new Location(3048, 4695, 2), Location.create(3049, 4695, 2), Location.create(3048, 4694, 2), Location.create(3049, 4694, 2), Location.create(3048, 4697, 2), Location.create(3049, 4697, 2) }, { Location.create(3046, 4697, 3), Location.create(3047, 4697, 3), Location.create(3046, 4696, 3), Location.create(3047, 4696, 3), Location.create(3046, 4699, 3), Location.create(3047, 4699, 3) } };
/**
* The ledge crossing location data.
*/
private static final Location[][] LEDGE_LOCATIONS = new Location[][] { { new Location(3366, 2851, 1), new Location(3364, 2851, 1), Location.create(3368, 2851, 1), Location.create(3363, 2851, 1), Location.create(3367, 2851, 1), Location.create(3364, 2851, 1) }, { new Location(3362, 2831, 1), new Location(3360, 2831, 1), Location.create(3364, 2832, 1), Location.create(3359, 2832, 1), Location.create(3360, 2832, 1), Location.create(3363, 2832, 1) }, { new Location(3372, 2837, 2), new Location(3372, 2839, 2), Location.create(3372, 2841, 2), Location.create(3372, 2836, 2), Location.create(3372, 2837, 2), Location.create(3372, 2840, 2) }, { new Location(3358, 2843, 3), new Location(3358, 2845, 3), Location.create(3359, 2842, 3), Location.create(3359, 2847, 3), Location.create(3359, 2846, 3), Location.create(3359, 2843, 3) } };
/**
* The gap crossing location data.
*/
private static final Location[][] GAP_CROSS_LOCATIONS = new Location[][] { { new Location(3368, 2831, 1), new Location(3370, 2831, 1), Location.create(3372, 2832, 1), Location.create(3367, 2832, 1), Location.create(3371, 2832, 1), Location.create(3368, 2832, 1) }, { new Location(3356, 2837, 2), new Location(3356, 2839, 2), Location.create(3357, 2841, 2), Location.create(3357, 2836, 2), Location.create(3357, 2840, 2), Location.create(3357, 2837, 2) }, { new Location(3360, 2849, 2), new Location(3362, 2849, 2), Location.create(3359, 2849, 2), Location.create(3364, 2849, 2), Location.create(3363, 2849, 2), Location.create(3360, 2849, 2) } };
/**
* Constructs a new {@code AgilityPyramidCourse} {@code Object}.
*/
public AgilityPyramidCourse() {
this(null);
}
/**
* Constructs a new {@code AgilityPyramidCourse} {@code Object}.
* @param player the player.
*/
public AgilityPyramidCourse(Player player) {
super(player, 5, 0);
}
@Override
public void configure() {
SceneryDefinition.forId(16535).getHandlers().put("option:climb", this);
SceneryDefinition.forId(16536).getHandlers().put("option:climb", this);
SceneryDefinition.forId(10851).getHandlers().put("option:climb", this);
SceneryDefinition.forId(10855).getHandlers().put("option:enter", this);
SceneryDefinition.forId(10856).getHandlers().put("option:enter", this);
SceneryDefinition.forId(10860).getHandlers().put("option:cross", this);
SceneryDefinition.forId(10861).getHandlers().put("option:cross", this);
SceneryDefinition.forId(10862).getHandlers().put("option:cross", this);
SceneryDefinition.forId(10863).getHandlers().put("option:cross", this);
SceneryDefinition.forId(10864).getHandlers().put("option:cross", this);
SceneryDefinition.forId(10868).getHandlers().put("option:cross", this);
SceneryDefinition.forId(10867).getHandlers().put("option:cross", this);
SceneryDefinition.forId(10882).getHandlers().put("option:cross", this);
SceneryDefinition.forId(10883).getHandlers().put("option:cross", this);
SceneryDefinition.forId(10884).getHandlers().put("option:cross", this);
SceneryDefinition.forId(10885).getHandlers().put("option:cross", this);
SceneryDefinition.forId(10886).getHandlers().put("option:cross", this);
SceneryDefinition.forId(10887).getHandlers().put("option:cross", this);
SceneryDefinition.forId(10888).getHandlers().put("option:cross", this);
SceneryDefinition.forId(10889).getHandlers().put("option:cross", this);
SceneryDefinition.forId(10859).getHandlers().put("option:jump", this);
SceneryDefinition.forId(10857).getHandlers().put("option:climb-up", this);
SceneryDefinition.forId(10858).getHandlers().put("option:climb-down", this);
SceneryDefinition.forId(10865).getHandlers().put("option:climb-over", this);
RollingBlock.BlockSets.values();
ClassScanner.definePlugin(new MovingBlockNPC());
ClassScanner.definePlugin(new AgilityPyramidZone());
}
@Override
public boolean handle(final Player player, Node node, String option) {
getCourse(player); // Sets the extension.
final Scenery object = (Scenery) node;
if (object.getLocation().getDistance(player.getLocation()) >= 3) {
player.getPacketDispatch().sendMessage("I can't reach that!");
return true;
}
switch (object.getId()) {
case 16535:
case 16536:
handleRockClimb(player, object);
break;
case 10865:
handleLowWall(player, object);
break;
case 10888:
case 10889:
case 10860:
case 10886:
case 10887:
handleLedge(player, object);
break;
case 10868:
case 10867:
handlePlank(player, object);
break;
case 10882:
case 10883:
case 10884:
case 10885:
case 10861:
case 10862:
case 10863:
case 10864:
handleGapCross(player, object);
break;
case 10857:
case 10858:
handleStairs(player, object);
break;
case 10851:
handlePyramidTop(player, object);
break;
case 10859:
handleJumpGap(player, object);
break;
case 10855:
case 10856:
addConfig(player, 10869, 0, true);
if (player.getConfigManager().get(640) == 505 || player.getConfigManager().get(640) == 515) {
player.getSkills().addExperience(Skills.AGILITY, 300, true);
}
player.getDialogueInterpreter().sendDialogue("You climb down the steep passage. It leads to the base of the", "pyramid.");
player.getProperties().setTeleportLocation(Location.create(3364, 2830, 0));
player.getSavedData().getActivityData().setTopGrabbed(false);
break;
}
return true;
}
/**
* Handles the stairs.
* @param player the player.
* @param object the object.
*/
private void handleStairs(final Player player, final Scenery object) {
Direction dir = Direction.getLogicalDirection(player.getLocation(), object.getLocation());
Location dest = null;
if (dir == Direction.NORTH) {
dest = object.getLocation().transform(0, 2, 1);
} else if (dir == Direction.SOUTH) {
dest = object.getLocation().transform(0, -1, -1);
}
if (object.getLocation().equals(Location.create(3360, 2837, 3))) {
dest = Location.create(3040, 4695, 2);
} else if (object.getLocation().equals(Location.create(3040, 4693, 2))) {
dest = Location.create(3360, 2836, 3);
} else if (object.getLocation().equals(new Location(3354, 2831, 0))) {
addConfig(player, 10869, 0, true);
}
ClimbActionHandler.climb(player, null, dest);
}
/**
* Handles the rock climbing obstacle.
* @param player the player.
* @param object the object.
*/
private void handleRockClimb(final Player player, final Scenery object) {
final boolean scale = player.getLocation().getX() < object.getLocation().getX();
final Location end = object.getLocation().transform(scale ? 2 : -2, 0, 0);
if (object.getId() == 16536 && player.getSkills().getStaticLevel(Skills.AGILITY) < 30) {
player.getPacketDispatch().sendMessage("You must be level 30 agility or higher to climb down the rocks.");
return;
}
if (!scale) {
ForceMovement.run(player, player.getLocation(), end, Animation.create(740), Animation.create(740), Direction.WEST, 13).setEndAnimation(Animation.RESET);
} else {
ForceMovement.run(player, player.getLocation(), end, Animation.create(1148), Animation.create(1148), Direction.WEST, 13).setEndAnimation(Animation.RESET);
}
}
/**
* Handles the low wall obstacle.
* @param player the player.
* @param object the object.
*/
private void handleLowWall(final Player player, final Scenery object) {
Direction d = Direction.getDirection(player.getLocation(), object.getLocation());
final boolean fail = player.getSkills().getLevel(Skills.AGILITY) >= 75 ? false : hasFailed(player) ;
if (player.getLocation().equals(Location.create(3355, 2848, 1)) || player.getLocation().equals(Location.create(3359, 2838, 3))) {
d = Direction.NORTH;
} else if (player.getLocation().equals(Location.create(3355, 2850, 1)) || player.getLocation().equals(Location.create(3359, 2840, 3))) {
d = Direction.SOUTH;
} else if (player.getLocation().equals(Location.create(3046, 4694, 2)) || player.getLocation().equals(Location.create(3355, 2850, 1)) || player.getLocation().equals(Location.create(3041, 4702, 2)) || player.getLocation().equals(new Location(3369, 2834, 2))) {
d = Direction.EAST;
} else if (player.getLocation().equals(Location.create(3048, 4694, 2)) || player.getLocation().equals(Location.create(3371, 2834, 2)) || player.getLocation().equals(Location.create(3043, 4702, 2))) {
d = Direction.WEST;
}
player.lock(4);
player.getPacketDispatch().sendMessage("You climb the low wall...");
if (fail) {
Location end = player.getLocation().transform(d, 1);
player.lock(3);
AgilityHandler.failWalk(player, 2, player.getLocation(), end, end, Animation.create(1106), 15, getHitAmount(player), "You lost your balance!");
AgilityHandler.forceWalk(player, -1, end, player.getLocation(), ForceMovement.WALK_ANIMATION, 10, 0.0, null, 4);
return;
}
AgilityHandler.forceWalk(player, 0, player.getLocation(), player.getLocation().transform(d, 2), Animation.create(1252), 6, 8, "... and make it over.");
player.animate(Animation.RESET, 4);
}
/**
* Handles the ledge crossing obstacle.
* @param player the player.
* @param object the object.
*/
private void handleLedge(final Player player, final Scenery object) {
Direction d = Direction.getLogicalDirection(player.getLocation(), getLedgeLocation(player, object));
final Direction dir = d;
final int diff = object.getRotation() == 3 && dir == Direction.EAST ? 1 : object.getRotation() == 3 && dir == Direction.WEST ? 0 : d == Direction.EAST || (d == Direction.SOUTH && object.getRotation() != 0) || d == Direction.NORTH ? 0 : 1;
final boolean fail = player.getSkills().getLevel(Skills.AGILITY) < 75 && hasFailed(player);
final Location end = player.getLocation().transform(dir.getStepX() * (fail ? 3 : 5), dir.getStepY() * (fail ? 3 : 5), 0);
player.getPacketDispatch().sendMessage("You put your foot on the ledge and try to edge across...");
if (fail) {
player.lock(4);
AgilityHandler.walk(player, -1, player.getLocation(), end, Animation.create(157 - diff), 0.0, "You slip and fall to the level below.");
GameWorld.getPulser().submit(new Pulse(3, player) {
@Override
public boolean pulse() {
Location dest = end;
int x = 0, y = 0;
switch (dir) {
case NORTH:
case SOUTH:
if (object.getRotation() == 2) {
x = 2;
} else {
x = -2;
}
break;
case WEST:
case EAST:
if (object.getRotation() == 3) {
y = -2;
} else if (object.getRotation() == 1) {
y = 2;
}
break;
default:
break;
}
AgilityHandler.fail(player, 1, transformLevel(dest.transform(x, y, 0)), Animation.create(761 - diff), 10, null);
return true;
}
});
return;
}
AgilityHandler.walk(player, 3, player.getLocation(), end, Animation.create(157 - diff), 52, "You skillfully edge across the gap.");
}
/**
* Handles the plank crossin obstacle.
* @param player the player.
* @param object the object.
*/
private void handlePlank(final Player player, final Scenery object) {
final boolean custom = object.getLocation().equals(new Location(3365, 2835, 3)) || object.getLocation().equals(new Location(3370, 2835, 3));
final Direction dir = custom ? Direction.EAST : Direction.getLogicalDirection(player.getLocation(), object.getLocation());
final boolean fail = player.getSkills().getLevel(Skills.AGILITY) >= 75 ? false : hasFailed(player) ;
final Location end = object.getLocation().transform(object.getId() != 10868 ? dir : dir.getOpposite(), fail ? 2 : 5);
AgilityHandler.walk(player, fail ? -1 : 1, player.getLocation(), end, Animation.create(155), fail ? 0.0 : 56.4, fail ? null : "You walk carefully across the slippery plank...");
if (fail) {
GameWorld.getPulser().submit(new Pulse(2, player) {
@Override
public boolean pulse() {
final Location dest = transformLevel(end.transform(!custom ? 2 : 0, custom ? -2 : 0, 0));
AgilityHandler.failWalk(player, 2, end, dest, dest, Animation.create(764), 10, 10, null);
return true;
}
});
}
}
/**
* Handles the gab crossing obstacle.
* @param player the player.
* @param object the object.
*/
private void handleJumpGap(Player player, Scenery object) {
final Direction dir = Direction.getDirection(player.getLocation(), getGapLocation(player, object));
final boolean fail = player.getSkills().getLevel(Skills.AGILITY) >= 75 ? false : hasFailed(player) ;
player.getPacketDispatch().sendMessage("You jump the gap...");
if (fail) {
final boolean regular = object.getRotation() == 0 || object.getRotation() == 3;
Location end = player.getLocation().transform(dir, 1);
Location dest = object.getLocation().transform(dir, 1);
if (!regular) {
dest = dest.transform(dir == Direction.NORTH || dir == Direction.SOUTH ? 2 : 0, dir == Direction.SOUTH ? 1 : 0, 0);
} else {
dest = dest.transform(dir == Direction.NORTH || dir == Direction.SOUTH ? -1 : dir == Direction.WEST ? 1 : 0, dir == Direction.SOUTH ? 1 : dir == Direction.WEST || dir == Direction.EAST ? -1 : 0, 0);
}
dest = transformLevel(dest);
player.lock(8);
AgilityHandler.forceWalk(player, -1, player.getLocation(), end, Animation.create(3068), 10, 0.0, "... and miss your footing.");
AgilityHandler.fail(player, 8, dest, null, 8, null);
return;
}
player.lock(4);
AgilityHandler.forceWalk(player, 2, player.getLocation(), player.getLocation().transform(dir, 3), Animation.create(3067), 20, 22, null);
}
/**
* Handles the gap cross obstacle.
* @param player the player.
* @param object the object.
*/
private void handleGapCross(final Player player, final Scenery object) {
final Direction dir = Direction.getLogicalDirection(player.getLocation(), getGapCrossLocation(player, object));
final boolean fail = player.getSkills().getLevel(Skills.AGILITY) >= 75 ? false : hasFailed(player) ;
final Location end = player.getLocation().transform(dir, fail ? 4 : 5);
final int rot = object.getRotation();
int mod = player.getLocation().equals(new Location(3359, 2849, 2)) ? 0 : player.getLocation().equals(new Location(3357, 2841, 2)) ? 1 : player.getLocation().equals(new Location(3367, 2832, 1)) ? 1 : player.getLocation().equals(new Location(3372, 2832, 1)) ? 0 : object.getLocation().equals(new Location(3370, 2831, 1)) ? 0 : rot == 1 && dir == Direction.EAST ? 0 : rot == 3 && (dir == Direction.WEST || dir == Direction.EAST) ? 1 : rot == 0 && dir == Direction.SOUTH ? 1 : dir == Direction.WEST && rot != 3 || dir == Direction.EAST ? 1 : 0;
final Animation animation = Animation.create(387 - mod);
if (fail) {
Location dest = object.getLocation().transform(dir, 1);
dest = rot == 1 && dir == Direction.EAST ? dest.transform(1, 2, 0) : rot == 1 && dir == Direction.WEST ? dest.transform(0, -2, 0) : dest.transform(dir == Direction.NORTH || dir == Direction.SOUTH ? -1 : dir == Direction.WEST ? 1 : 0, dir == Direction.SOUTH ? 1 : dir == Direction.WEST || dir == Direction.EAST ? -1 : 0, 0);
AgilityHandler.walk(player, -1, player.getLocation(), end, animation, 10, null);
AgilityHandler.fail(player, 3, transformLevel(dest), null, 8, null);
// player.animate(Animation.create(3056 - mod), 2);
GameWorld.getPulser().submit(new Pulse(3, player) {
@Override
public boolean pulse() {
player.getAppearance().setDefaultAnimations();
player.getAppearance().sync();
return true;
}
});
return;
}
AgilityHandler.walk(player, 4, player.getLocation(), end, animation, 22, null);
}
/**
* Handles the pyramid top obstacle.
* @param player the player.
* @param object the object.
*/
private void handlePyramidTop(final Player player, final Scenery object) {
if(player.getSavedData().getActivityData().isTopGrabbed() == true){
player.getPacketDispatch().sendMessage("You've already claimed this!");
return;
} else {
player.animate(Animation.create(3063));
GameWorld.getPulser().submit(new Pulse(3, player) {
@Override
public boolean pulse() {
player.getSkills().addExperience(Skills.AGILITY, 1000);
if (player.getConfigManager().get(640) == 505 || player.getConfigManager().get(640) == 515) {
player.getPacketDispatch().sendMessage("You find nothing on top of the pyramid.");
return true;
}
addConfig(player, 10869, 1, true);
player.getSavedData().getActivityData().setTopGrabbed(true);
player.getInventory().add(PYRAMID_TOP, player);
player.getDialogueInterpreter().sendItemMessage(PYRAMID_TOP, "You find a golden pyramid!");
return true;
}
});
}
}
/**
* Transforms a pyramid level.
* @param location the location.
* @return the location.
*/
public static Location transformLevel(Location location) {
int xDiff = 320;
int yDiff = 1856;
if (location.getRegionId() == 12105 && location.getZ() == 2) {
return new Location(location.getX() + xDiff, location.getY() - yDiff, 3);
}
return location.transform(0, 0, -1);
}
/**
* Gets the gap location.
* @param player the player.
* @param object the obejct.
* @return the location.
*/
private Location getGapLocation(Player player, Scenery object) {
final Location[] data = getLocationData(GAP_LOCATIONS, object.getLocation());
return getClosest(new Location[] { data[0], data[1] }, player.getLocation());
}
/**
* Gets the gap cross location.
* @param player the player.
* @param object the obejct.
* @return the location.
*/
private Location getGapCrossLocation(Player player, Scenery object) {
final Location[] data = getLocationData(GAP_CROSS_LOCATIONS, object.getLocation());
return getClosest(new Location[] { data[4], data[5] }, player.getLocation());
}
/**
* Gets the ledge location.
* @param player the player.
* @param object the object.
* @return the location.
*/
private Location getLedgeLocation(final Player player, final Scenery object) {
final Location[] data = getLocationData(LEDGE_LOCATIONS, object.getLocation());
return getClosest(new Location[] { data[4], data[5] }, player.getLocation());
}
/**
* Gets the closest location.
* @param data the data.
* @param location the location.
* @return the closest location.
*/
private Location getClosest(Location[] data, Location location) {
Location closest = null;
for (Location l : data) {
if (closest == null || l.getDistance(location) < closest.getDistance(location)) {
closest = l;
}
}
return closest;
}
/**
* Gets the location data.
* @param data the data.
* @param location the location.
* @return the data.
*/
private Location[] getLocationData(Location[][] data, Location location) {
for (int i = 0; i < data.length; i++) {
for (Location l : data[i]) {
if (l.equals(location)) {
return data[i];
}
}
}
return null;
}
/**
* Checks if the player has failed.
* @param player the player.
* @return {@code True} if so.
*/
private boolean hasFailed(final Player player) {
return hasFailed(player, 0.009000);
}
/**
* Checks if the player has failed.
* @param player the player.
* @param mod the mod.
* @return {@code True} if so.
*/
private boolean hasFailed(final Player player, double mod) {
return AgilityHandler.hasFailed(player, 10, mod);
}
/**
* Sets the config id.
* @param player the player.
* @param objectId the object.
* @param value the value.
*/
public static void addConfig(final Player player, final int objectId, final int value, boolean save) {
final VarbitDefinition definition = VarbitDefinition.forObjectID(SceneryDefinition.forId(objectId).getVarbitID());
final int oldVal = (definition.getValue(player) << definition.getStartBit());
final int newVal = (value << definition.getStartBit());
player.getConfigManager().set(CONFIG_ID, (player.getConfigManager().get(CONFIG_ID) - oldVal) + newVal, save);
}
/**
* Sets the config id.
* @param player the player.
* @param object the object.
* @param value the value.
* @param save if we save.
*/
public static void addConfig(final Player player, final Scenery object, final int value, boolean save) {
addConfig(player, object.getId(), value, save);
}
@Override
public Location getDestination(Node node, Node n) {
switch (n.getId()) {
case 16535:
case 16536:
return n.getLocation().transform(node.getLocation().getX() < n.getLocation().getX() ? -1 : 1, 0, 0);
case 10865:
return null;
case 10857:
return n.getLocation().transform(0, -1, 0);
case 10858:
return n.getLocation().transform(0, 2, 0);
case 10859:
return getClosest(getLocationData(GAP_LOCATIONS, n.getLocation()), node.getLocation());
case 10860:
case 10886:
case 10887:
case 10888:
case 10889:
return getClosest(getLocationData(LEDGE_LOCATIONS, n.getLocation()), node.getLocation());
case 10868:
case 10867:
return n.getLocation();
case 10882:
case 10883:
case 10884:
case 10885:
case 10861:
case 10862:
case 10863:
case 10864:
if (n.getId() == 10863 && n.getLocation().equals(new Location(3372, 2832, 1))) {
return Location.create(3372, 2832, 1);
}
return getClosest(getLocationData(GAP_CROSS_LOCATIONS, n.getLocation()), node.getLocation());
}
return null;
}
@Override
public AgilityCourse createInstance(Player player) {
return new AgilityPyramidCourse(player);
}
}
@@ -0,0 +1,73 @@
package content.global.skill.agility.pyramid;
import core.game.node.entity.Entity;
import core.game.node.entity.player.Player;
import core.game.system.task.MovementHook;
import core.game.world.map.Direction;
import core.game.world.map.Location;
import core.game.world.map.zone.MapZone;
import core.game.world.map.zone.ZoneBorders;
import core.game.world.map.zone.ZoneBuilder;
import core.plugin.Plugin;
import java.util.HashMap;
import java.util.Map;
/**
* Represents the agility pyramid area.
* @author 'Vexia
* @version 1.0
*/
public final class AgilityPyramidZone extends MapZone implements Plugin<Object> {
/**
* The location based traps.
*/
public static final Map<Location, MovementHook> LOCATION_TRAPS = new HashMap<>();
/**
* Constructs a new {@code AgilityPyramid} {@code Object}.
*/
public AgilityPyramidZone() {
super("agility pyramid", true);
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ZoneBuilder.configure(this);
return this;
}
@Override
public boolean enter(Entity e) {
if (e instanceof Player) {
final Player player = (Player) e;
AgilityPyramidCourse.addConfig(player, 10872, 1, true);
AgilityPyramidCourse.addConfig(player, 10873, 3, true);
}
return super.enter(e);
}
@Override
public boolean move(Entity e, Location loc, Location dest) {
if (!e.getLocks().isMovementLocked() && e instanceof Player) {
MovementHook hook = LOCATION_TRAPS.get(loc);
if (hook != null) {
e.setDirection(Direction.getLogicalDirection(loc, dest));
return hook.handle(e, loc);
}
}
return super.move(e, loc, dest);
}
@Override
public Object fireEvent(String identifier, Object... args) {
return null;
}
@Override
public void configure() {
register(new ZoneBorders(3352, 2826, 3378, 2854));
register(new ZoneBorders(3007, 4672, 3071, 4735));
}
}
@@ -0,0 +1,177 @@
package content.global.skill.agility.pyramid;
import content.global.skill.agility.AgilityHandler;
import core.game.node.entity.Entity;
import core.game.node.entity.npc.AbstractNPC;
import core.game.node.entity.player.Player;
import core.game.system.task.MovementHook;
import core.game.system.task.Pulse;
import core.game.world.GameWorld;
import core.game.world.map.Direction;
import core.game.world.map.Location;
import core.game.world.map.RegionManager;
import core.game.world.update.flag.context.Animation;
/**
* The moving block npc.
* @author 'Vexia
* @version 1.0
*/
public final class MovingBlockNPC extends AbstractNPC {
/**
* The tile locations.
*/
private static final Location[][] LOCATIONS = new Location[][] { { Location.create(3366, 2847, 3), Location.create(3367, 2847, 3), Location.create(3367, 2848, 3), Location.create(3366, 2848, 3), Location.create(3365, 2847, 3), Location.create(3365, 2848, 3), Location.create(3368, 2847, 3), Location.create(3368, 2848, 3) }, { Location.create(3374, 2847, 1), Location.create(3374, 2848, 1), Location.create(3375, 2848, 1), Location.create(3375, 2847, 1), Location.create(3374, 2849, 1), Location.create(3375, 2849, 1), Location.create(3374, 2846, 1), Location.create(3375, 2846, 1) } };
/**
* The next move delay.
*/
private int nextMove;
/**
* If its moving.
*/
private boolean moving;
/**
* Constructs a new {@code MovingBlockNPC} {@code Object}.
*/
public MovingBlockNPC() {
super(-1, null);
}
/**
* Constructs a new {@code MovingBlockNPC} {@code Object}.
* @param id the id.
* @param location the location.
*/
public MovingBlockNPC(int id, Location location) {
super(id, location, false);
}
@Override
public void tick() {
super.tick();
if (nextMove < GameWorld.getTicks() && nextMove != -1) {
Direction dir = getId() == 3124 ? Direction.EAST : Direction.NORTH;
Location loc = getLocation().transform(dir, 2);
getWalkingQueue().reset();
getWalkingQueue().addPath(loc.getX(), loc.getY());
for (Player p : RegionManager.getLocalPlayers(getTileLocations()[0], 2)) {
checkBlock(p);
}
moving = true;
GameWorld.getPulser().submit(new Pulse(1, this) {
int counter;
@Override
public boolean pulse() {
switch (++counter) {
case 1:
for (Player p : RegionManager.getLocalPlayers(getTileLocations()[0], 2)) {
checkBlock(p);
}
break;
case 3:
getWalkingQueue().reset();
getWalkingQueue().addPath(getProperties().getSpawnLocation().getX(), getProperties().getSpawnLocation().getY());
nextMove = GameWorld.getTicks() + 13;
break;
case 5:
moving = false;
return true;
}
return false;
}
});
nextMove = -1;
}
}
@Override
public void init() {
super.init();
final MovingBlockTrap trap = new MovingBlockTrap();
for (Location l : getTileLocations()) {
AgilityPyramidZone.LOCATION_TRAPS.put(l, trap);
}
}
@Override
public AbstractNPC construct(int id, Location location, Object... objects) {
return new MovingBlockNPC(id, location);
}
/**
* Checks if a player is going to get hit by a block.
* @param player the player.
*/
public void checkBlock(final Player player) {
if (player.getAttribute("block-move", -1) > GameWorld.getTicks()) {
return;
}
Location[] locs = getTileLocations();
for (int i = 0; i < 4; i++) {
if (locs[i].equals(player.getLocation())) {
GameWorld.getPulser().submit(new Pulse(1, player) {
@Override
public boolean pulse() {
boolean close = getProperties().getSpawnLocation().getDistance(player.getLocation()) > (getId() == 3124 ? 2 : 2.3);
Location dest = null;
if (getId() == 3124) {
if (player.getLocation().getY() == 2847) {
dest = Location.create(3376, 2847, 1);
} else if (player.getLocation().getY() == 2848) {
dest = Location.create(3376, 2848, 1);
}
} else {
if (player.getLocation().getX() == 3366) {
dest = Location.create(3366, 2849, 3);
} else if (player.getLocation().getX() == 3367) {
dest = Location.create(3367, 2849, 3);
}
}
player.lock(4);
player.setAttribute("block-move", GameWorld.getTicks() + 4);
if(dest != null) {
AgilityHandler.failWalk(player, close ? 1 : 3, player.getLocation(), dest, AgilityPyramidCourse.transformLevel(dest), Animation.create(3066), 10, 8, null, getId() == 3124 ? Direction.WEST : Direction.SOUTH);
}
return true;
}
});
return;
}
}
}
/**
* Gets the tile locations.
* @return the locations.
*/
public Location[] getTileLocations() {
return LOCATIONS[3125 - getId()];
}
@Override
public int[] getIds() {
return new int[] { 3124, 3125 };
}
/**
* The movement hook to handle a moving block.
* @author 'Vexia
* @version 1.0
*/
public final class MovingBlockTrap implements MovementHook {
@Override
public boolean handle(Entity e, Location l) {
if (moving) {
return false;
}
return true;
}
}
}
@@ -0,0 +1,169 @@
package content.global.skill.agility.pyramid;
import content.global.skill.agility.AgilityHandler;
import core.game.node.entity.Entity;
import core.game.node.entity.player.Player;
import core.game.node.scenery.Scenery;
import core.game.system.task.MovementHook;
import core.game.system.task.Pulse;
import kotlin.Unit;
import core.game.world.GameWorld;
import core.game.world.map.Direction;
import core.game.world.map.Location;
import core.game.world.map.RegionManager;
import core.game.world.update.flag.context.Animation;
/**
* Represents the rolling block obstacle.
* @author 'Vexia
* @version 1.0
*/
public final class RollingBlock implements MovementHook {
@Override
public boolean handle(final Entity e, final Location dest) {
final Player player = (Player) e;
final BlockSets set = BlockSets.forLocation(dest);
final Scenery stone = RegionManager.getObject(set.getBlockLocation());
final boolean backwards = isBackwards(stone.getDirection(), player.getDirection(), stone.getRotation());
final boolean fail = backwards || AgilityHandler.hasFailed(player, 2, 0.3);
player.lock(5);
AgilityPyramidCourse.addConfig(player, stone, 1, false);
if(e.isPlayer())
{
((Player) e).logoutListeners.put("rolling-block", p -> {
p.setLocation(e.getLocation().transform(0,0,0));
return Unit.INSTANCE;
});
}
if (fail) {
GameWorld.getPulser().submit(new Pulse(1, player) {
int counter;
@Override
public boolean pulse() {
switch (++counter) {
case 1:
final Location end = player.getLocation().transform(stone.getDirection(), -2);
final int hit = backwards ? 1 : 6;
if (set == BlockSets.FOUR) {
AgilityHandler.failWalk(player, 3, dest, end, AgilityPyramidCourse.transformLevel(end), Animation.create(1116), 10, hit, null);
} else {
AgilityHandler.failWalk(player, -1, dest, AgilityPyramidCourse.transformLevel(end), AgilityPyramidCourse.transformLevel(end), Animation.create(1116), 10, hit, null);
}
break;
case 3:
AgilityPyramidCourse.addConfig(player, stone, 0, true);
player.logoutListeners.remove("rolling-block");
return true;
}
return false;
}
});
return false;
}
AgilityHandler.forceWalk(player, -1, dest, dest.transform(player.getDirection(), 2), Animation.create(1115), 20, 12, null);
GameWorld.getPulser().submit(new Pulse(3, player) {
@Override
public boolean pulse() {
AgilityPyramidCourse.addConfig(player, stone, 0, true);
return true;
}
});
return false;
}
/**
* Checks if the player is going backwards.
* @param direction the object dir.
* @param dir the player dir.
* @return {@code True} if so.
*/
public boolean isBackwards(Direction direction, Direction dir, int rot) {
switch (direction) {
case NORTH:
break;
case SOUTH:
return rot == 2 & dir == Direction.WEST;
case EAST:
return rot == 1 && dir == Direction.SOUTH;
case WEST:
return rot == 3 && dir == Direction.NORTH;
default:
break;
}
return false;
}
/**
* A block set.
* @author 'Vexia
*/
public enum BlockSets {
ONE(Location.create(3354, 2841, 0), Location.create(3354, 2842, 1), Location.create(3355, 2842, 1), Location.create(3355, 2841, 1), Location.create(3354, 2841, 1)), TWO(Location.create(3374, 2835, 0), Location.create(3374, 2835, 1), Location.create(3374, 2836, 1), Location.create(3375, 2836, 1), Location.create(3375, 2835, 1)), THREE(Location.create(3368, 2849, 1), Location.create(3368, 2849, 2), Location.create(3369, 2849, 2), Location.create(3369, 2850, 2), Location.create(3368, 2850, 2)), FOUR(Location.create(3048, 4699, 1), Location.create(3048, 4700, 2), Location.create(3049, 4700, 2), Location.create(3049, 4699, 2), Location.create(3048, 4699, 2)), FIVE(Location.create(3044, 4699, 2), Location.create(3044, 4700, 3), Location.create(3045, 4700, 3), Location.create(3045, 4699, 3), Location.create(3044, 4699, 3));
/**
* The block location.
*/
private final Location blockLocation;
/**
* The tile locations.
*/
private final Location[] tiles;
/**
* Constructs a new {@code BlockSets} {@code Object}.
* @param blockLocation the block location.
* @param tiles the tiles.
*/
private BlockSets(Location blockLocation, Location... tiles) {
this.blockLocation = blockLocation;
this.tiles = tiles;
}
/**
* Gets the set for the location.
* @param location the location.
* @return the block sets.
*/
public static BlockSets forLocation(Location location) {
for (BlockSets set : values()) {
for (Location loc : set.getTiles()) {
if (loc.equals(location)) {
return set;
}
}
}
return null;
}
/**
* Gets the blockLocation.
* @return The blockLocation.
*/
public Location getBlockLocation() {
return blockLocation;
}
/**
* Gets the tiles.
* @return The tiles.
*/
public Location[] getTiles() {
return tiles;
}
/**
* static-block to load block traps.
*/
static {
final RollingBlock block = new RollingBlock();
for (BlockSets set : values()) {
for (Location l : set.getTiles()) {
AgilityPyramidZone.LOCATION_TRAPS.put(l, block);
}
}
}
}
}
@@ -0,0 +1,57 @@
package content.global.skill.agility.shortcuts;
import core.plugin.Initializable;
import content.global.skill.agility.AgilityShortcut;
import core.game.node.Node;
import core.game.node.entity.impl.ForceMovement;
import core.game.node.entity.player.Player;
import core.game.node.scenery.Scenery;
import core.game.world.map.Direction;
import core.game.world.map.Location;
import core.game.world.update.flag.context.Animation;
/**
* Handles the al kharid pit shortcut.
* @author adam
*/
@Initializable
public class AlKharidPitShortcut extends AgilityShortcut {
/**
* Represents the scaling down anmation.
*/
private static final Animation ANIMATION = new Animation(1148);
/**
* Represents the scaling animation.
*/
private static final Animation SCALE = new Animation(740);
/**
* Constructs a new {@Code AlKharidPitShortcut} {@Code Object}
*/
public AlKharidPitShortcut() {
super(new int[] { 9331, 9332 }, 38, 0.0, "climb");
}
@Override
public void run(Player player, Scenery object, String option, boolean failed) {
switch (object.getId()) {
case 9331:
ForceMovement.run(player, player.getLocation(), Location.create(3303, 3315, 0), ANIMATION, ANIMATION, Direction.EAST, 13).setEndAnimation(Animation.RESET);
break;
case 9332:
ForceMovement.run(player, player.getLocation(), Location.create(3307, 3315, 0), SCALE, SCALE, Direction.EAST, 13).setEndAnimation(Animation.RESET);
break;
}
}
@Override
public Location getDestination(Node node, Node n) {
final Scenery object = (Scenery) n;
if (object.getId() == 9331) {
return object.getLocation().transform(1, 0, 0);
}
return null;
}
}
@@ -0,0 +1,70 @@
package content.global.skill.agility.shortcuts;
import content.global.skill.agility.AgilityShortcut;
import content.global.skill.agility.AgilityHandler;
import core.game.node.entity.player.Player;
import core.game.node.scenery.Scenery;
import core.game.world.map.Direction;
import core.game.world.map.Location;
import core.game.world.update.flag.context.Animation;
import core.plugin.Initializable;
import core.plugin.Plugin;
/**
* Handles the bar squeezing shortcut.
* @author Vexia
*/
@Initializable
public class BarSqueezeShortcut extends AgilityShortcut {
/**
* Constructs a new {@Code BarSqueezeShortcut} {@Code Object}
*/
public BarSqueezeShortcut() {
super(new int[] { 9334, 9337 }, 66, 1, "squeeze-through");
}
/**
* Constructs a new {@Code BarSqueezeShortcut} {@Code Object}
* @param ids the ids.
* @param level the level.
* @param exp the exp.
* @param option the option.
*/
public BarSqueezeShortcut(int[] ids, int level, double exp, String option) {
super(ids, level, exp, option);
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
configure(new BarSqueezeShortcut(new int[] { 2186 }, 1, 0.0, "squeeze-through"));
return super.newInstance(arg);
}
@Override
public void run(Player player, Scenery object, String option, boolean failed) {
Direction dir = Direction.getLogicalDirection(player.getLocation(), object.getLocation());
Location start = player.getLocation();
if (object.getId() == 9334 && dir == Direction.NORTH) {
dir = Direction.WEST;
start = Location.create(3424, 3476, 0);
} else if (object.getId() == 9337 && dir == Direction.NORTH) {
dir = Direction.SOUTH;
if (player.getLocation().getY() < object.getLocation().getY()) {
dir = Direction.NORTH;
}
} else if (object.getId() == 2186 && player.getLocation().getY() >= 3161) {
dir = Direction.SOUTH;
}
AgilityHandler.forceWalk(player, -1, start, player.getLocation().transform(dir, 1), Animation.create(2240), 10, 0.0, null);
}
@Override
public boolean checkRequirements(Player player) {
if (!player.getQuestRepository().isComplete("Priest in Peril") && !(player.getLocation().getY() >= 3159 && player.getLocation().getY() <= 3161)) {
player.getDialogueInterpreter().sendDialogue("You need to have completed Priest in Peril in order to do this.");
return false;
}
return super.checkRequirements(player);
}
}
@@ -0,0 +1,202 @@
package content.global.skill.agility.shortcuts
import core.game.node.Node
import core.game.node.scenery.Scenery
import core.game.node.entity.player.Player
import content.global.skill.agility.AgilityHandler
import content.global.skill.agility.AgilityShortcut
import core.game.system.task.Pulse
import core.game.world.GameWorld
import core.game.world.map.Location
import core.game.world.update.flag.context.Animation
import core.game.world.update.flag.player.FaceLocationFlag
import core.plugin.Initializable
import core.plugin.Plugin
/**
* Handles the Basalt Rock shortcut.
* @author Woah
*/
@Initializable
class BasaltRockShortcut : AgilityShortcut {
/**
* Constructs a new {@Code BasaltRockShortcut} {@Code Object}
*/
constructor() : super(intArrayOf(), 0, 0.0, "")
val noJump = "I can't jump from here."
/**
* Constructs a new {@Code BasaltRockShortcut} {@Code Object}
*
* @param ids the ids.
* @param level the level.
* @param experience the experience.
* @param options the options.
*/
constructor(ids: IntArray?, level: Int, experience: Double, vararg options: String?) : super(ids, level, experience, *options)
/**
* Basalt Rock Index : Direction South (Barbarian Outpost) to North (Lighthouse)
* Beach -> Rock 1 -> Rock etc... -> Rocky Shore
* 2522, 3600 R1, 3601, 3602 R2
*/
override fun newInstance(arg: Any?): Plugin<Any> {
configure(content.global.skill.agility.shortcuts.BasaltRockShortcut(intArrayOf(4550), 1, 0.0, "jump-to")) //Beach South*
configure(content.global.skill.agility.shortcuts.BasaltRockShortcut(intArrayOf(4551), 1, 0.0, "jump-across")) //Beach South Rock 1*
configure(content.global.skill.agility.shortcuts.BasaltRockShortcut(intArrayOf(4552), 1, 0.0, "jump-across")) //South Rock 2
configure(content.global.skill.agility.shortcuts.BasaltRockShortcut(intArrayOf(4553), 1, 0.0, "jump-across")) //South Rock 2 (other side)
configure(content.global.skill.agility.shortcuts.BasaltRockShortcut(intArrayOf(4554), 1, 0.0, "jump-across")) //Middle Rock 3
configure(content.global.skill.agility.shortcuts.BasaltRockShortcut(intArrayOf(4555), 1, 0.0, "jump-across")) //Middle Rock 3 (other side)
configure(content.global.skill.agility.shortcuts.BasaltRockShortcut(intArrayOf(4556), 1, 0.0, "jump-across")) //North Rock 4
configure(content.global.skill.agility.shortcuts.BasaltRockShortcut(intArrayOf(4557), 1, 0.0, "jump-across")) //North Rock 4 (other side)
configure(content.global.skill.agility.shortcuts.BasaltRockShortcut(intArrayOf(4558), 1, 0.0, "jump-across")) //Rocky Shore North Rock 5*
configure(content.global.skill.agility.shortcuts.BasaltRockShortcut(intArrayOf(4559), 1, 0.0, "jump-to")) //Rocky Shore North*
return this
}
/**
* This method enables users to jump across rocks by clicking on the one that they want to jump to
* instead of the rock below them
*/
override fun getDestination(n: Node?, node: Node): Location? {
val obj = node as Scenery
if (obj.id == 4550) {
return Location.create(2522, 3597, 0) //Beach South*
} else if (obj.id == 4551) {
return Location.create(2522, 3595, 0) //Beach South Rock 1*
} else if (obj.id == 4552) {
return Location.create(2522, 3602, 0) //South Rock 2
} else if (obj.id == 4553) {
return Location.create(2522, 3600, 0) //South Rock 2 (other side)
} else if (obj.id == 4554) {
return Location.create(2516, 3611, 0) //Middle Rock 3
} else if (obj.id == 4555) {
return Location.create(2518, 3611, 0) //Middle Rock 3 (other side)
} else if (obj.id == 4556) {
return Location.create(2514, 3615, 0) //North Rock 4
} else if (obj.id == 4557) {
return Location.create(2514, 3613, 0) //North Rock 4 (other side)
} else if (obj.id == 4558) {
return Location.create(2514, 3619, 0) //Rocky Shore North Rock 5*
} else if (obj.id == 4559) {
return Location.create(2514, 3617, 0) //Rocky Shore North*
}
return super.getDestination(obj, node)
}
override fun run(player: Player, obj: Scenery, option: String, failed: Boolean) {
GameWorld.Pulser.submit(object : Pulse(1, player) {
override fun pulse(): Boolean {
when (obj.id) {
4550 -> {
if (player.location.y <= 3596) {
player.sendMessage(noJump)
} else {
player.lock(3)
AgilityHandler.forceWalk(player, -1, Location.create(2522, 3597, 0), Location.create(2522, 3595, 0), Animation.create(769), 20, 0.0, null, 1)
}
return true
}
4551 -> {
if (player.location == Location.create(2522, 3597, 0)) {
player.sendMessage(noJump)
} else {
player.lock(3)
AgilityHandler.forceWalk(player, -1, Location.create(2522, 3595, 0), Location.create(2522, 3597, 0), Animation.create(769), 20, 0.0, null, 1)
}
return true
}
4552 -> {
if (player.location == Location.create(2522, 3600, 0)) {
player.sendMessage(noJump)
} else {
player.lock(3)
AgilityHandler.forceWalk(player, -1, Location.create(2522, 3602, 0), Location.create(2522, 3600, 0), Animation.create(769), 20, 0.0, null)
}
return true
}
4553 -> {
if (player.location == Location.create(2522, 3602, 0)) {
player.sendMessage(noJump)
} else {
player.lock(3)
AgilityHandler.forceWalk(player, -1, Location.create(2522, 3600, 0), Location.create(2522, 3602, 0), Animation.create(769), 20, 0.0, null)
}
return true
}
4554 -> {
if (player.location == Location.create(2518, 3611, 0)) {
player.sendMessage(noJump)
} else {
player.lock(3)
player.faceLocation(FaceLocationFlag.getFaceLocation(player, Location.create(2518, 3611, 0)))
AgilityHandler.forceWalk(player, -1, Location.create(2516, 3611, 0), Location.create(2518, 3611, 0), Animation.create(769), 20, 0.0, null, 1)
}
return true
}
4555 -> {
if (player.location == Location.create(2516, 3611, 0)) {
player.sendMessage(noJump)
} else {
player.lock(3)
player.faceLocation(FaceLocationFlag.getFaceLocation(player, Location.create(2516, 3611, 0)))
AgilityHandler.forceWalk(player, -1, Location.create(2518, 3611, 0), Location.create(2516, 3611, 0), Animation.create(769), 20, 0.0, null, 1)
}
return true
}
4556 -> {
if (player.location == Location.create(2514, 3613, 0)) {
player.sendMessage(noJump)
} else {
player.lock(3)
AgilityHandler.forceWalk(player, -1, Location.create(2514, 3615, 0), Location.create(2514, 3613, 0), Animation.create(769), 20, 0.0, null)
}
return true
}
4557 -> {
if (player.location == Location.create(2514, 3615, 0)) {
player.sendMessage(noJump)
} else {
player.lock(3)
AgilityHandler.forceWalk(player, -1, Location.create(2514, 3613, 0), Location.create(2514, 3615, 0), Animation.create(769), 20, 0.0, null)
}
return true
}
4558 -> {
if (player.location == Location.create(2514, 3617, 0)) {
player.sendMessage(noJump)
} else {
player.lock(3)
AgilityHandler.forceWalk(player, -1, Location.create(2514, 3619, 0), Location.create(2514, 3617, 0), Animation.create(769), 20, 0.0, null)
}
return true
}
4559 -> {
if (player.location.y >= 3618) {
player.sendMessage(noJump)
} else {
player.lock(3)
AgilityHandler.forceWalk(player, -1, Location.create(2514, 3617, 0), Location.create(2514, 3619, 0), Animation.create(769), 20, 0.0, null, 1)
}
return true
}
}
return false
}
})
}
}
@@ -0,0 +1,114 @@
package content.global.skill.agility.shortcuts
import core.api.*
import core.game.node.entity.player.Player
import core.game.node.entity.skill.Skills
import core.game.system.task.Pulse
import core.game.world.map.Location
import core.game.world.update.flag.context.Animation
import org.rs09.consts.Items
import org.rs09.consts.Scenery
import core.game.interaction.IntType
import core.game.interaction.InteractionListener
/**
* Handles the Catherby to Taverley grapple shortcut
* @author Byte
*/
class CatherbyGrappleShortcut : InteractionListener {
companion object {
private val START_LOCATION: Location = Location.create(2866, 3429, 0)
private val END_LOCATION: Location = Location.create(2869,3430,0)
private val REQUIREMENTS = hashMapOf(
Skills.AGILITY to 32,
Skills.RANGE to 35,
Skills.STRENGTH to 35
)
private val VALID_CROSSBOWS = intArrayOf(
Items.MITH_CROSSBOW_9181,
Items.ADAMANT_CROSSBOW_9183,
Items.RUNE_CROSSBOW_9185,
Items.DORGESHUUN_CBOW_8880
)
}
private var rocks = getScenery(Location.create(2869,3429, 0))
override fun defineListeners() {
flagInstant() // execute listeners instantly without determining path
on(Scenery.ROCKS_17042, IntType.SCENERY, "grapple") { player, _ ->
if (isPlayerInRangeToGrapple(player)) {
forceWalk(player, content.global.skill.agility.shortcuts.CatherbyGrappleShortcut.Companion.START_LOCATION, "smart")
} else {
sendMessage(player, "Nothing interesting happens.")
return@on true
}
if (!doesPlayerHaveRequiredItemsEquipped(player)) {
sendDialogue(player, "You need a Mithril crossbow and a Mithril grapple in order to do this.")
return@on true
}
if (!doesPlayerHaveRequiredLevels(player)) {
sendDialogueLines(player,
"You need at least " +
content.global.skill.agility.shortcuts.CatherbyGrappleShortcut.Companion.REQUIREMENTS[Skills.AGILITY] + " " + Skills.SKILL_NAME[Skills.AGILITY] + ", " +
content.global.skill.agility.shortcuts.CatherbyGrappleShortcut.Companion.REQUIREMENTS[Skills.RANGE] + " " + Skills.SKILL_NAME[Skills.RANGE] + ", ",
"and " +
content.global.skill.agility.shortcuts.CatherbyGrappleShortcut.Companion.REQUIREMENTS[Skills.STRENGTH] + " " + Skills.SKILL_NAME[Skills.STRENGTH] + " to use this shortcut."
)
return@on true
}
lock(player, 15)
submitWorldPulse(object : Pulse(2) {
var counter = 0
override fun pulse() : Boolean {
when (counter++) {
1 -> {
face(player, content.global.skill.agility.shortcuts.CatherbyGrappleShortcut.Companion.END_LOCATION)
// Audit: shows player climbing (probably a wall), need a cliff climb animation
animate(player, Animation(4455))
}
3 -> {
// Audit: shows grapple on rocks, but there is no rope
replaceScenery(rocks!!, rocks!!.id + 1, 10)
}
8 -> {
teleport(player, content.global.skill.agility.shortcuts.CatherbyGrappleShortcut.Companion.END_LOCATION)
}
9 -> {
sendMessage(player, "You successfully grapple the rock and climb the cliffside.")
unlock(player)
return true
}
}
return false
}
})
return@on true
}
}
private fun doesPlayerHaveRequiredItemsEquipped(player: Player): Boolean {
return isEquipped(player, Items.MITH_GRAPPLE_9419) && areAnyEquipped(player, *content.global.skill.agility.shortcuts.CatherbyGrappleShortcut.Companion.VALID_CROSSBOWS)
}
private fun doesPlayerHaveRequiredLevels(player: Player): Boolean {
for ((skill, requiredLevel) in content.global.skill.agility.shortcuts.CatherbyGrappleShortcut.Companion.REQUIREMENTS) {
if (!hasLevelDyn(player, skill, requiredLevel)) {
return false
}
}
return true
}
private fun isPlayerInRangeToGrapple(player: Player): Boolean {
return inBorders(player, content.global.skill.agility.shortcuts.CatherbyGrappleShortcut.Companion.START_LOCATION.x - 2, content.global.skill.agility.shortcuts.CatherbyGrappleShortcut.Companion.START_LOCATION.y - 2, content.global.skill.agility.shortcuts.CatherbyGrappleShortcut.Companion.START_LOCATION.x, content.global.skill.agility.shortcuts.CatherbyGrappleShortcut.Companion.START_LOCATION.y)
}
}
@@ -0,0 +1,36 @@
package content.global.skill.agility.shortcuts;
import content.global.skill.agility.AgilityShortcut;
import core.game.node.entity.impl.ForceMovement;
import core.game.node.entity.player.Player;
import core.game.node.scenery.Scenery;
import core.game.world.map.Location;
import core.game.world.update.flag.context.Animation;
import core.plugin.Initializable;
/**
* Handles a crumbling wall.
* @author Vexia
*/
@Initializable
public class CrumblingWallShortcut extends AgilityShortcut {
/**
* Represents the locations used in this force movement.
*/
private static final Location[] LOCATIONS = new Location[] { new Location(2936, 3355, 0), new Location(2934, 3355, 0) };
/**
* Constructs a new {@Code CrumblingWallShortcut} {@Code
* Object}
*/
public CrumblingWallShortcut() {
super(new int[] { 11844 }, 5, 0.0, "climb-over");
}
@Override
public void run(Player player, Scenery object, String option, boolean failed) {
ForceMovement.run(player, player.getLocation().getX() >= 2936 ? LOCATIONS[0] : LOCATIONS[1], player.getLocation().getX() >= 2936 ? LOCATIONS[1] : LOCATIONS[0], Animation.create(839), 10);
}
}
@@ -0,0 +1,145 @@
package content.global.skill.agility.shortcuts;
import core.cache.def.impl.SceneryDefinition;
import core.game.component.Component;
import org.rs09.consts.Items;
import core.game.interaction.OptionHandler;
import core.game.node.Node;
import core.game.node.entity.impl.ForceMovement;
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.system.task.Pulse;
import core.game.world.GameWorld;
import core.game.world.map.Location;
import core.game.world.update.flag.context.Animation;
import core.game.world.update.flag.context.Graphics;
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;
import core.game.node.entity.skill.Skills;
import java.util.HashMap;
import java.util.Map;
/**
* Represents the plugin used to handle the grappling of the falador wall.
*
* @author 'Vexia
* @version 1.0
*/
@Initializable
public final class FaladorGrapplePlugin extends OptionHandler {
private static final HashMap<Integer, Integer> REQUIREMENTS = new HashMap<>();
private static String requirementsString;
static {
REQUIREMENTS.putIfAbsent(Skills.AGILITY, 11);
REQUIREMENTS.putIfAbsent(Skills.RANGE, 19);
REQUIREMENTS.putIfAbsent(Skills.STRENGTH, 37);
requirementsString = "You need at least "
+ REQUIREMENTS.get(Skills.AGILITY) + " " + Skills.SKILL_NAME[Skills.AGILITY] + ", "
+ REQUIREMENTS.get(Skills.RANGE) + " " + Skills.SKILL_NAME[Skills.RANGE] + ", and "
+ REQUIREMENTS.get(Skills.STRENGTH) + " " + Skills.SKILL_NAME[Skills.STRENGTH]
+ " to use this shortcut.";
}
private static final int[] CBOWS = new int[]{
Items.MITH_CROSSBOW_9181,
Items.ADAMANT_CROSSBOW_9183,
Items.RUNE_CROSSBOW_9185,
Items.DORGESHUUN_CBOW_8880
};
private static final Item MITH_GRAPPLE = new Item(9419);
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
SceneryDefinition.forId(17049).getHandlers().put("option:grapple", this);
SceneryDefinition.forId(17050).getHandlers().put("option:grapple", this);
SceneryDefinition.forId(17051).getHandlers().put("option:jump", this);
SceneryDefinition.forId(17052).getHandlers().put("option:jump", this);
return this;
}
@Override
public boolean handle(final Player player, final Node node, String option) {
Location destination;
Location current = player.getLocation();
switch (option) {
case "jump":
ForceMovement.run(player,
current,
node.asScenery().getId() == 17051
? Location.create(3033, 3390, 0)
: Location.create(3032, 3388, 0),
new Animation(7268),
10);
break;
case "grapple":
destination = node.asScenery().getId() == 17049
? Location.create(3033, 3389, 1)
: Location.create(3032, 3391, 1);
for (Map.Entry<Integer, Integer> e : REQUIREMENTS.entrySet()) {
if (player.getSkills().getLevel(e.getKey()) < e.getValue()) {
player.getDialogueInterpreter().sendDialogue(requirementsString);
return true;
}
}
if (!player.getEquipment().containsAtLeastOneItem(CBOWS) || !player.getEquipment().containsItem(MITH_GRAPPLE)) {
player.getDialogueInterpreter().sendDialogue("You need a Mithril crossbow and a Mithril grapple in order to do this.");
return true;
}
player.lock();
GameWorld.getPulser().submit(new Pulse(1, player) {
int counter = 1;
Component tab;
@Override
public boolean pulse() {
switch (counter++) {
case 1:
player.faceLocation(destination);
player.visualize(new Animation(4455), new Graphics(760, 100));
break;
case 8:
tab = player.getInterfaceManager().getSingleTab();
player.getInterfaceManager().openOverlay(new Component(115));
PacketRepository.send(MinimapState.class, new MinimapStateContext(player, 2));
player.getInterfaceManager().removeTabs(0, 1, 2, 3, 4, 5, 6, 11, 12);
break;
case 13:
player.getProperties().setTeleportLocation(destination);
break;
case 14:
player.getInterfaceManager().restoreTabs();
if (tab != null) {
player.getInterfaceManager().openTab(tab);
}
PacketRepository.send(MinimapState.class, new MinimapStateContext(player, 0));
player.getInterfaceManager().closeOverlay();
player.getInterfaceManager().close();
player.unlock();
player.getAchievementDiaryManager().finishTask(player, DiaryType.FALADOR, 1, 2);
return true;
}
return false;
}
});
break;
}
return true;
}
@Override
public Location getDestination(final Node moving, final Node destination) {
return destination.asScenery().getId() == 17050 ? Location.create(3032, 3388, 0) : null;
}
}
@@ -0,0 +1,65 @@
package content.global.skill.agility.shortcuts;
import content.global.skill.agility.AgilityShortcut;
import core.game.node.Node;
import core.game.node.entity.impl.ForceMovement;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.diary.DiaryType;
import core.game.node.scenery.Scenery;
import core.game.system.task.Pulse;
import core.game.world.GameWorld;
import core.game.world.map.Location;
import core.game.world.update.flag.context.Animation;
import core.plugin.Initializable;
/**
* Handles the fence jump shortcut.
* @author Vexia
*/
@Initializable
public class FenceJumpShortcut extends AgilityShortcut {
/**
* Represents the running animation.
*/
private static final Animation RUNNING_ANIM = new Animation(1995);
/**
* Represents the jumping animation.
*/
private static final Animation JUMP_ANIM = new Animation(1603);
/**
* Represents the related locations used in this shortcut. format: (start,
* start, end, end
*/
private static final Location[] LOCATIONS = new Location[] { new Location(3240, 3331, 0), new Location(3240, 3338, 0), Location.create(3240, 3334, 0), Location.create(3240, 3335, 0) };
/**
* Constructs a new {@Code FenceJumpShortcut} {@Code Object}
*/
public FenceJumpShortcut() {
super(new int[] { 9300 }, 13, 0.0, "jump-over");
}
@Override
public void run(final Player player, Scenery object, String option, boolean failed) {
player.faceLocation(object.getLocation());
GameWorld.getPulser().submit(new Pulse(2, player) {
@Override
public boolean pulse() {
player.animate(JUMP_ANIM);
player.getAchievementDiaryManager().finishTask(player, DiaryType.VARROCK, 0, 5);
return true;
}
});
ForceMovement.run(player, player.getLocation().getY() >= 3335 ? LOCATIONS[1] : LOCATIONS[0], player.getLocation().getY() >= 3335 ? LOCATIONS[2] : LOCATIONS[3], RUNNING_ANIM, 18);
}
@Override
public Location getDestination(Node node, Node n) {
Player player = node.asPlayer();
return player.getLocation().getY() >= 3335 ? LOCATIONS[1] : LOCATIONS[0];
}
}
@@ -0,0 +1,145 @@
package content.global.skill.agility.shortcuts;
import core.cache.def.impl.SceneryDefinition;
import core.game.component.Component;
import org.rs09.consts.Items;
import core.game.interaction.OptionHandler;
import core.game.node.Node;
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.system.task.Pulse;
import core.game.world.GameWorld;
import core.game.world.map.Direction;
import core.game.world.map.Location;
import core.game.world.map.RegionManager;
import core.game.world.update.flag.context.Animation;
import core.plugin.Initializable;
import core.plugin.Plugin;
import core.game.node.entity.skill.Skills;
import java.util.HashMap;
import java.util.Map;
@Initializable
public class KaramjaGrapple extends OptionHandler {
private static final HashMap<Integer, Integer> REQUIREMENTS = new HashMap<>();
private static final String requirementsString;
static {
REQUIREMENTS.putIfAbsent(Skills.AGILITY, 53);
REQUIREMENTS.putIfAbsent(Skills.RANGE, 42);
REQUIREMENTS.putIfAbsent(Skills.STRENGTH, 21);
requirementsString = "You need at least "
+ REQUIREMENTS.get(Skills.AGILITY) + " " + Skills.SKILL_NAME[Skills.AGILITY] + ", "
+ REQUIREMENTS.get(Skills.RANGE) + " " + Skills.SKILL_NAME[Skills.RANGE] + ", and "
+ REQUIREMENTS.get(Skills.STRENGTH) + " " + Skills.SKILL_NAME[Skills.STRENGTH]
+ " to use this shortcut.";
}
private static final int[] CBOWS = new int[]{
Items.MITH_CROSSBOW_9181,
Items.ADAMANT_CROSSBOW_9183,
Items.RUNE_CROSSBOW_9185,
Items.DORGESHUUN_CBOW_8880
};
private static final Item MITH_GRAPPLE = new Item(9419);
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
SceneryDefinition.forId(17074).getHandlers().put("option:grapple", this);
// island tree 17074 +1 rope loop, +2 grappled one way, +3 grappled other way
// north tree 17056 +1 rope loop, +2 grappled
// south tree 17059 +1 rope loop, +2 grappled
return this;
}
@Override
public boolean handle(Player player, Node node, String option) {
Location destination;
Location current = player.getLocation();
Scenery startTree, endTree;
Direction direction;
if (current.getY() > 3134) { // starting at north side
startTree = RegionManager.getObject(Location.create(2874, 3144, 0));
endTree = RegionManager.getObject(Location.create(2873, 3125, 0));
destination = Location.create(2874, 3127, 0);
direction = Direction.SOUTH;
} else {
startTree = RegionManager.getObject(Location.create(2873, 3125, 0));
endTree = RegionManager.getObject(Location.create(2874, 3144, 0));
destination = Location.create(2874, 3142, 0);
direction = Direction.NORTH;
}
Scenery islandTree = RegionManager.getObject(Location.create(2873, 3134, 0));
switch (option) {
case "grapple":
for (Map.Entry<Integer, Integer> e : REQUIREMENTS.entrySet()) {
if (player.getSkills().getLevel(e.getKey()) < e.getValue()) {
player.getDialogueInterpreter().sendDialogue(requirementsString);
return true;
}
}
if (!player.getEquipment().containsAtLeastOneItem(CBOWS) || !player.getEquipment().containsItem(MITH_GRAPPLE)) {
player.getDialogueInterpreter().sendDialogue("You need a Mithril crossbow and a Mithril grapple in order to do this.");
return true;
}
player.lock();
GameWorld.getPulser().submit(new Pulse(1, player) {
int counter = 1;
Component tab;
@Override
public boolean pulse() {
switch (counter++) {
// TODO animations not implemented.
// See ~11min in https://www.youtube.com/watch?v=qpB53rzYqrA
// don't know how to get ropes to show up. The tree objects have grapples and stuff but don't look like the video and aren't the right directions
// splash gfx are 68 and 69, not sure why there are two
// not sure what swimming animation is, could be 4464 thru 4468
case 1:
player.faceLocation(player.getLocation().transform(direction));
player.animate(new Animation(4230));
break;
case 3:
//player.getPacketDispatch().sendPositionedGraphic(67, 10, 0, player.getLocation().transform(direction, 5)); //
break;
case 4:
//ObjectBuilder.replace(startTree, startTree.transform(startTree.getId() + 1), 10);
//ObjectBuilder.replace(islandTree, islandTree.transform(islandTree.getId() + 1), 10);
break;
case 5:
break;
case 13:
player.getProperties().setTeleportLocation(destination);
break;
case 14:
player.unlock();
player.getAchievementDiaryManager().finishTask(player, DiaryType.KARAMJA, 2, 6);
return true;
}
return false;
}
});
break;
}
return true;
}
@Override
public Location getDestination(final Node moving, final Node destination) {
// Run between tree and water before firing grapple
if (moving.getLocation().getY() > 3134) { // starting at north side
return Location.create(2874, 3142, 0);
} else {
return Location.create(2874, 3127, 0);
}
}
}
@@ -0,0 +1,87 @@
package content.global.skill.agility.shortcuts;
import core.game.node.entity.player.link.diary.DiaryType;
import core.plugin.Initializable;
import content.global.skill.agility.AgilityHandler;
import content.global.skill.agility.AgilityShortcut;
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.game.world.update.flag.context.Animation;
import core.plugin.Plugin;
/**
* Handles the log balance shortcut.
* @author Vexia
*/
@Initializable
public class LogBalanceShortcut extends AgilityShortcut {
/**
* The start and ending location.
*/
private Location start;
/**
* The ending and start location.
*/
private Location end;
/**
* Constructs a new {@Code LogBalanceShortcut} {@Code Object}
* @param ids the ids.
* @param level the level.
* @param experience the experience.
* @param options the options.
*/
public LogBalanceShortcut(int[] ids, int level, double experience, Location start, Location end, String... options) {
super(ids, level, experience, options);
this.start = start;
this.end = end;
}
/**
* Constructs a new {@Code LogBalanceShortcut} {@Code Object}
*/
public LogBalanceShortcut() {
super(new int[] {}, 0, 0.0);
}
@Override
public Plugin<Object> newInstance(Object arg) {
configure(new LogBalanceShortcut(new int[] { 2296 }, 20, 5, new Location(2598, 3477, 0), Location.create(2603, 3477, 0), "walk-across"));
// Sinclair mansion to Rellekka. 9324 is on the south side of the stream going north.
configure(new LogBalanceShortcut(new int[] { 9322, 9324 }, 48, 1, Location.create(2722, 3592, 0), Location.create(2722, 3596, 0), "walk-across"));
configure(new LogBalanceShortcut(new int[] { 35997, 35999 }, 33, 1, Location.create(2602, 3336, 0), Location.create(2598, 3336, 0), "walk-across"));
configure(new LogBalanceShortcut(new int[] { 2332 }, 1, 1, Location.create(2910, 3049, 0), Location.create(2906, 3049, 0), "cross"));
configure(new LogBalanceShortcut(new int[] { 3933 }, 45, 1, Location.create(2290, 3232, 0), Location.create(2290, 3239, 0), "cross"));
configure(new LogBalanceShortcut(new int[] { 3932 }, 45, 1, Location.create(2258, 3250, 0), Location.create(2264, 3250, 0), "cross"));
configure(new LogBalanceShortcut(new int[] { 3931 }, 45, 1, Location.create(2202, 3237, 0), Location.create(2196, 3237, 0), "cross"));
return this;
}
@Override
public void run(Player player, Scenery object, String option, boolean failed) {
Location destination = start;
if (player.getLocation().getDistance(start) < player.getLocation().getDistance(end)) {
destination = end;
}
AgilityHandler.walk(player, -1, player.getLocation(), destination, Animation.create(155), getExperience(), null);
// Seers Achievement Diary
if (destination.equals(new Location(2722,3596,0))
&& !player.getAchievementDiaryManager().getDiary(DiaryType.SEERS_VILLAGE).isComplete(1,0)) {
player.getAchievementDiaryManager().getDiary(DiaryType.SEERS_VILLAGE).updateTask(player,1,0,true);
}
}
@Override
public Location getDestination(Node node, Node n) {
if (node.getLocation().getDistance(start) < node.getLocation().getDistance(end)) {
return start;
}
return end;
}
}
@@ -0,0 +1,130 @@
package content.global.skill.agility.shortcuts;
import core.plugin.Initializable;
import content.global.skill.agility.AgilityHandler;
import content.global.skill.agility.AgilityShortcut;
import core.game.node.Node;
import core.game.node.entity.impl.ForceMovement;
import core.game.node.entity.player.Player;
import core.game.node.scenery.Scenery;
import core.game.system.task.Pulse;
import kotlin.Unit;
import core.game.world.GameWorld;
import core.game.world.map.Direction;
import core.game.world.map.Location;
import core.game.world.update.flag.context.Animation;
import core.plugin.Plugin;
import core.tools.RandomFunction;
/**
* Handles the monkey bar shortcut.
* @author Vexia
*/
@Initializable
public class MonkeyBarShortcut extends AgilityShortcut {
/**
* Represents the location cache data for the monkey bars.
*/
private static final Location[][] MBAR_LOCATIONS = new Location[][] { { new Location(3120, 9969, 0), Location.create(3121, 9969, 0) }, { new Location(3119, 9969, 0), Location.create(3120, 9969, 0) }, { new Location(3120, 9964, 0), Location.create(3121, 9964, 0) }, { Location.create(3120, 9963, 0), Location.create(3120, 9964, 0) }, { new Location(2598, 9489, 0), new Location(2597, 9488, 0) }, { new Location(2598, 9489, 0), new Location(2600, 9488, 0) }, { new Location(2598, 9494, 0), new Location(2597, 9495, 0) }, { new Location(2599, 9494, 0), new Location(2600, 9495, 0) } };
/**
* Constructs a new {@Code MonkeyBarShortcut} {@Code Object}
*/
public MonkeyBarShortcut() {
super(new int[] { 29375 }, 1, 14.0, "swing across");
}
/**
* Constructs a new {@Code MonkeyBarShortcut} {@Code Object}
* @param ids the ids.
* @param level the level.
* @param experience the exp.
* @param option the option.
*/
public MonkeyBarShortcut(int[] ids, int level, double experience, String option) {
super(ids, level, experience, option);
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
configure(new MonkeyBarShortcut(new int[] { 2321 }, 57, 20, "swing across"));
return super.newInstance(arg);
}
@Override
public void run(final Player player, final Scenery object, String option, boolean failed) {
player.lock(5);
Direction direct = Direction.get((object.getDirection().toInteger() + 2) % 4);
if (object.getId() == 29375) {
if (direct == Direction.SOUTH && player.getLocation().getY() < 9969) {
direct = Direction.NORTH;
} else if (direct == Direction.NORTH && player.getLocation().getY() >= 9969) {
direct = Direction.SOUTH;
}
} else if (object.getId() == 2321) {
if (player.getLocation().getY() >= 9494) {
direct = Direction.SOUTH;
} else {
direct = Direction.NORTH;
}
}
player.getAppearance().setAnimations(Animation.create(745));
final Location start = player.getLocation();
final Direction dir = direct;
ForceMovement.run(player, start.transform(dir), start.transform(dir.getStepX() << 1, dir.getStepY() << 1, 0), Animation.create(742), Animation.create(744));
player.logoutListeners.put("monkey-bar", p -> {
p.setLocation(start);
return Unit.INSTANCE;
});
GameWorld.getPulser().submit(new Pulse(2, player) {
int count;
boolean failed;
@Override
public boolean pulse() {
if (++count == 1) {
if (object.getId() == 2321 && (failed = AgilityHandler.hasFailed(player, 57, 0.01))) {
setDelay(1);
player.animate(Animation.create(743));
return false;
}
setDelay(4);
AgilityHandler.walk(player, -1, player.getLocation().transform(dir), player.getLocation().transform(dir.getStepX() * 4, dir.getStepY() * 4, 0), Animation.create(662), 0.0, null);
} else if (count == 2) {
if (failed) {
player.getAppearance().setAnimations();
player.getAppearance().sync();
AgilityHandler.fail(player, 2, new Location(2599, 9564, 0), Animation.create(768), RandomFunction.random(1, 3), null);
player.logoutListeners.remove("monkey-bar");
return true;
}
AgilityHandler.forceWalk(player, -1, player.getLocation(), player.getLocation().transform(dir), Animation.create(743), 10, getExperience(), null);
player.logoutListeners.remove("monkey-bar");
return true;
}
return false;
}
});
}
@Override
public Location getDestination(Node n, Node node) {
if (node.getLocation().equals(new Location(2598, 9489, 0))) {
return new Location(2597, 9488, 0);
} else if (node.getLocation().equals(new Location(2598, 9494, 0))) {
return new Location(2597, 9495, 0);
} else if (node.getLocation().equals(new Location(2599, 9489, 0))) {
return new Location(2600, 9488, 0);
}
for (Location[] locations : MBAR_LOCATIONS) {
if (n.getLocation().equals(locations[0])) {
return locations[1];
}
}
if (node.getLocation().equals(new Location(2598, 9489, 0)) || node.getLocation().equals(new Location(2599, 9489, 0))) {
return new Location(2600, 9495, 0);
}
return null;
}
}
@@ -0,0 +1,161 @@
package content.global.skill.agility.shortcuts
import core.game.node.scenery.Scenery
import core.game.node.entity.player.Player
import core.game.node.entity.player.link.diary.DiaryType
import content.global.skill.agility.AgilityHandler
import content.global.skill.agility.AgilityShortcut
import core.game.system.task.Pulse
import core.game.world.GameWorld
import core.game.world.update.flag.context.Animation
import core.plugin.Initializable
import core.plugin.Plugin
/**
* Handles a pipe shortcut.
* Quick overview of what's included:
* Pipe interactions, locations, animations
* Quick OBJ lookup for pipe shortcut (ps):
* ps2290, ps5099, ps5100, ps9293, ps20210, ps29370
* Animations used:
* 10578: pipe enter(Due to tweening this one may cause issues, player standing up/it showing through the pipe, use 10580 instead)
* 10579: pipe exit, 10580: pipe enter + exit
* @author Woah
*/
@Initializable
class PipeShortcut : AgilityShortcut {
/**
* Constructs a new {@Code PipeShortcut} {@Code Object}
*/
constructor() : super(intArrayOf(), 0, 0.0, "")
/**
* Constructs a new {@Code PipeShortcut} {@Code Object}
*
* @param ids the ids.
* @param level the level.
* @param experience the experience.
* @param options the options.
*/
constructor(ids: IntArray?, level: Int, experience: Double, vararg options: String?) : super(ids, level, experience, *options)
/**
* These are all the pipes that are deemed "Shortcuts"
* Note: Barbarian Outpost is included in this list because it is not apart of the
* Barbarian Outpost Agility Course.
*/
override fun newInstance(arg: Any?): Plugin<Any> {
configure(PipeShortcut(intArrayOf(2290), 49, 0.0, "squeeze-through")) //Yanille Dungeon
configure(PipeShortcut(intArrayOf(5099), 22, 8.5, "squeeze-through")) //Brimhaven Dungeon Pipe Red Dragons -> Black Demons
configure(PipeShortcut(intArrayOf(5100), 34, 10.0, "squeeze-through")) //Brimhaven Dungeon Pipe Moss Giants -> Moss Giants
configure(PipeShortcut(intArrayOf(9293), 70, 10.0, "squeeze-through")) //Taverley Dungeon
configure(PipeShortcut(intArrayOf(20210), 35, 10.0, "squeeze-through")) //Barbarian Outpost
configure(PipeShortcut(intArrayOf(29370), 51, 10.0, "squeeze-through")) //Edgeville Dungeon
return this
}
/**
* Run for the main fire event
* Use this for unlocking achievement diaries + any other unlocks
*/
override fun run(player: Player, obj: Scenery, option: String, failed: Boolean) {
if (obj.id == 29370)
player.achievementDiaryManager.finishTask(player, DiaryType.VARROCK, 2, 1)
/**
* Pulse that starts the object interaction when clicked on one of these shortcuts
*/
GameWorld.Pulser.submit(object : Pulse(1, player) {
override fun pulse(): Boolean {
when (obj.id) {
/**
* Quick breakdown of how Agility.forcewalk is used for pipe shortcuts:
* AgilityHandler.forceWalk(player, -1, player.location, pipeDestination(player, obj, 6), Animation.create(10580), 10, 0.0, null)
*
* player = player, the player that is being force-walked
* -1 = course index, should this be counted as an agility course +1?
* player.location, gets the player location (start of pipe)
* pipeDestination(player, obj, 6) = custom made for pipes, player = player, obj is getting the scenery location, 6 is the amount to move forward. || More info found in AgilityShortcut.java
* Animation.create(10580) = what animation we should play when the user is interacting with that object
* 10 = speed at which the player moves through the object
* 0.0 = experience that we should award the player on successful completion* SET EXPERIENCE IN METHOD newInstance
* null = message that should be displayed when entering the object
*/
/**
* Yanille Dungeon pipe (Obj id: 2290) LOC: (2577, 9506, 0)
* Taverley Dungeon pipe (Obj id: 9293) LOC: (2887, 9799, 0)
* Diagram:
* This one is pretty standard, does not to have X/Y checks because the pipe is built into the wall
* Player lock (standard 5 ticks for a 7 long pipe)
* Plays the get into + crawl + jump out of pipe animation
*/
2290, 9293 -> {
player.lock(7)
AgilityHandler.forceWalk(player, -1, player.location, pipeDestination(player, obj, 6), Animation.create(10580), 10, 0.0, null)
player.animate(Animation(844), 4)
player.animate(Animation(10579), 5)
return true
}
/**
* //Brimhaven Dungeon Pipe Red Dragons -> Black Demons (Obj id: 5099) LOC: (2698, 9498, 0)
* //Brimhaven Dungeon Pipe Moss Giants -> Moss Giants (Obj id: 5100) LOC: (2655, 9567, 0)
* Diagram:
* This one is pretty standard, does not to have X/Y checks because the pipe is built into the wall
* Player lock (standard 5 ticks for a 7 long pipe)
* Plays the get into + crawl + jump out of pipe animation
*/
5099, 5100 -> {
player.lock(5)
AgilityHandler.forceWalk(player, -1, player.location, pipeDestination(player, obj, 7), Animation.create(10580), 10, 0.0, null)
player.animate(Animation(844), 5)
player.animate(Animation(10579), 6)
return true
}
/**
* Barbarian Outpost Pipe (Obj id: 20210) LOC: (2552, 3560, 0)
* Diagram:
* If statement checks to see if the player is on the same X Axis as the pipe, by not having this here a player could enter
* the pipe at an angle and would be shot through the walls (kinda funny to watch)
* Player lock (standard 3 ticks for a 3 long pipe)
* plays the all-in-one animation for getting into + out of pipe
*/
20210 -> {
if (player.location.x != 2552) {
player.packetDispatch.sendMessage("I can't get into this pipe at that angle.")
return true
}
player.lock(3)
AgilityHandler.forceWalk(player, -1, player.location, pipeDestination(player, obj, 3), Animation.create(10580), 15, 0.0, null)
return true
}
/**
* Edgeville Dungeon Pipe (Obj id: 29370) LOC: (3150, 9906, 0)
* Diagram:
* If statement checks to see if the player is on the same Y Axis as the pipe, by not having this here a player could enter
* the pipe at an angle and would be shot through the walls
* Player lock (standard 7 ticks for a 6 long pipe)
* Plays the get into + crawl + jump out of pipe animation
*/
29370 -> {
if (player.location.y != 9906) {
player.packetDispatch.sendMessage("I can't get into this pipe at that angle.")
return true
}
player.lock(7)
AgilityHandler.forceWalk(player, -1, player.location, pipeDestination(player, obj, 6), Animation.create(10580), 10, 0.0, null)
player.animate(Animation(844), 4)
player.animate(Animation(10579), 5)
return true
}
}
return false
}
})
}
}
@@ -0,0 +1,126 @@
package content.global.skill.agility.shortcuts
import core.game.node.scenery.Scenery
import core.game.node.entity.impl.ForceMovement
import core.game.node.entity.player.Player
import core.game.node.entity.skill.Skills
import content.global.skill.agility.AgilityShortcut
import core.game.world.map.Direction
import core.game.world.map.Location
import core.game.world.update.flag.context.Animation
import core.plugin.Initializable
/**
* Handles the rock climbing shortcut.
* @author Sir Kermit
*/
@Initializable
class RockClimbShortcut
/**
* Constructs a new {@Code RockClimbShortcut} {@Code Object}
*/
: AgilityShortcut(intArrayOf(
9335,
9336,
2231,
26327,
26328,
26324,
26323,
19849,
9296,
9297
), 1, 0.0, "climb")
{
override fun run(player: Player, `object`: Scenery, option: String, failed: Boolean) {
//Scaling down
val ANIMATION = Animation(1148)
//Scaling Up
val SCALE = Animation(740)
//Gets level for Arandar climbs
val req = if (player.location.equals(2346, 3300, 0) || player.location.equals(2344, 3294, 0)){
59
}else if (player.location.equals(2338, 3281, 0) || player.location.equals(2338, 3286, 0)){
85
}else if (player.location.equals(2332, 3252, 0) || player.location.equals(2338, 3253, 0)){
68
}else{0}
when (`object`.id) {
2231 -> if (player.location.x <= 2791) {
ForceMovement.run(player, `object`.location, `object`.location.transform(3, 0, 0), SCALE, SCALE, Direction.WEST, 13).endAnimation = Animation.RESET
} else {
ForceMovement.run(player, `object`.location, `object`.location.transform(-3, 0, 0), ANIMATION, ANIMATION, Direction.WEST, 13).endAnimation = Animation.RESET
}
//Eagles Peak
19849 -> if (player.location.x <= 2322) {
if (player.skills.hasLevel(Skills.AGILITY, 25)) {
ForceMovement.run(player, player.location, Location.create(2324, 3497, 0), SCALE, SCALE, Direction.SOUTH, 13).endAnimation = Animation.RESET
} else {
player.dialogueInterpreter.sendDialogue("You need an Agility level of at least 25 to do this.")
}
} else {
if (player.skills.hasLevel(Skills.AGILITY, 25)) {
ForceMovement.run(player, player.location, Location.create(2322, 3502, 0), ANIMATION, ANIMATION, Direction.SOUTH, 13).endAnimation = Animation.RESET
} else {
player.dialogueInterpreter.sendDialogue("You need an Agility level of at least 25 to do this.")
}
}
9335 -> ForceMovement.run(player, player.location, Location.create(3427, 3478, 0), SCALE, SCALE, Direction.WEST, 13).endAnimation = Animation.RESET
9336 -> ForceMovement.run(player, player.location, Location.create(3424, 3476, 0), ANIMATION, ANIMATION, Direction.WEST, 13).endAnimation = Animation.RESET
//GodWars Shortcut
26327 -> if (player.skills.hasLevel(Skills.AGILITY, 60)) {
ForceMovement.run(player, player.location, Location.create(2942, 3768, 0), SCALE, SCALE, Direction.WEST, 13).endAnimation = Animation.RESET
} else {
player.dialogueInterpreter.sendDialogue("You need an Agility level of at least 60 to do this.")
}
//GodWars Shortcut
26328 -> if (player.skills.hasLevel(Skills.AGILITY, 60)) {
ForceMovement.run(player, player.location, Location.create(2950, 3767, 0), ANIMATION, ANIMATION, Direction.WEST, 13).endAnimation = Animation.RESET
} else {
player.dialogueInterpreter.sendDialogue("You need an Agility level of at least 60 to do this.")
}
//GodWars Shortcut
26324 -> if (player.skills.hasLevel(Skills.AGILITY, 60)) {
ForceMovement.run(player, player.location, Location.create(2928, 3757, 0), SCALE, SCALE, Direction.NORTH, 13).endAnimation = Animation.RESET
} else {
player.dialogueInterpreter.sendDialogue("You need an Agility level of at least 60 to do this.")
}
//GodWars Shortcut
26323 -> if (player.skills.hasLevel(Skills.AGILITY, 60)) {
ForceMovement.run(player, player.location, Location.create(2927, 3761, 0), ANIMATION, ANIMATION, Direction.NORTH, 13).endAnimation = Animation.RESET
} else {
player.dialogueInterpreter.sendDialogue("You need an Agility level of at least 60 to do this.")
}
//Arandar
9297 -> if (player.skills.hasLevel(Skills.AGILITY, 59) && req == 59) {
ForceMovement.run(player, player.location, Location.create(2346, 3300, 0), SCALE, SCALE, Direction.NORTH, 13).endAnimation = Animation.RESET
} else if (player.skills.hasLevel(Skills.AGILITY, 85) && req == 85) {
ForceMovement.run(player, player.location, Location.create(2338, 3281, 0), SCALE, SCALE, Direction.SOUTH, 13).endAnimation = Animation.RESET
} else if (player.skills.hasLevel(Skills.AGILITY, 68) && req == 68) {
ForceMovement.run(player, player.location, Location.create(2332, 3252, 0), SCALE, SCALE, Direction.WEST, 13).endAnimation = Animation.RESET
} else {
player.dialogueInterpreter.sendDialogue("You need an Agility level of at least $req to do this.")
}
//Arandar
9296 -> if (player.skills.hasLevel(Skills.AGILITY, 59) && req == 59) {
ForceMovement.run(player, player.location, Location.create(2344, 3294, 0), ANIMATION, ANIMATION, Direction.NORTH, 13).endAnimation = Animation.RESET
} else if (player.skills.hasLevel(Skills.AGILITY, 85) && req == 85) {
ForceMovement.run(player, player.location, Location.create(2338, 3286, 0), ANIMATION, ANIMATION, Direction.SOUTH, 13).endAnimation = Animation.RESET
} else if (player.skills.hasLevel(Skills.AGILITY, 68) && req == 68) {
ForceMovement.run(player, player.location, Location.create(2338, 3253, 0), ANIMATION, ANIMATION, Direction.WEST, 13).endAnimation = Animation.RESET
} else {
player.dialogueInterpreter.sendDialogue("You need an Agility level of at least $req to do this.")
}
}
}
}
@@ -0,0 +1,45 @@
package content.global.skill.agility.shortcuts;
import core.game.interaction.NodeUsageEvent;
import core.game.interaction.UseWithHandler;
import core.game.node.entity.player.Player;
import core.game.node.scenery.Scenery;
import core.game.world.map.Location;
import core.game.world.update.flag.context.Animation;
import core.plugin.Initializable;
import core.plugin.Plugin;
import content.global.skill.agility.AgilityHandler;
@Initializable
public class RopeSwing extends UseWithHandler {
@Override
public boolean handle(NodeUsageEvent event) {
System.out.println("Trying to handle.");
if(event.getUsedWith() instanceof Scenery){
Scenery object = event.getUsedWith().asScenery();
int objId = object.getId();
assert event.getUsedItem() != null;
int usedId = event.getUsedItem().getId();
Player player = event.getPlayer();
if(objId == 2327 && usedId == 954){
if (!player.getLocation().withinDistance(object.getLocation(), 2)) {
player.sendMessage("I can't reach that.");
return true;
}
player.getPacketDispatch().sendSceneryAnimation(object, Animation.create(497), true);
AgilityHandler.forceWalk(player, 0, player.getLocation(), Location.create(2505, 3087, 0), Animation.create(751), 50, 22, "You skillfully swing across.", 1);
return true;
}
}
return false;
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
addHandler(2327,OBJECT_TYPE,this);
return this;
}
}
@@ -0,0 +1,85 @@
package content.global.skill.agility.shortcuts
import core.cache.def.impl.SceneryDefinition
import core.game.interaction.OptionHandler
import core.game.node.Node
import core.game.node.entity.impl.ForceMovement
import core.game.node.entity.player.Player
import core.game.node.entity.skill.Skills
import core.game.system.task.Pulse
import core.game.world.map.Location
import core.game.world.update.flag.context.Animation
import core.plugin.Initializable
import core.plugin.Plugin
/**
* Handles the stepping stone shortcut.
* @author Ceikry
*/
@Initializable
class SteppingStoneShortcut : OptionHandler() {
private val stones = HashMap<Location,SteppingStoneInstance>()
internal class SteppingStoneInstance(val pointA: Location, val pointB: Location, val option: String, val levelReq: Int)
override fun handle(player: Player?, node: Node?, option: String?): Boolean {
player ?: return false
val stone = stones[player.location]
stone ?: return false
if(player.skills.getLevel(Skills.AGILITY) < stone.levelReq){
player.sendMessage("You need an agility level of ${stone.levelReq} for this shortcut.")
return true
}
val finalDest = when(player.location){
stone.pointA -> stone.pointB
stone.pointB -> stone.pointA
else -> player.location
}
val offset = getOffset(player,finalDest)
player.debug("Offset: ${offset.first},${offset.second}")
player.pulseManager.run(object : Pulse(2){
override fun pulse(): Boolean {
val there = player.location == finalDest
if(!there){
ForceMovement.run(player,player.location,player.location.transform(offset.first,offset.second,0), ANIMATION,10)
}
return there
}
})
return true
}
fun getOffset(player: Player, location: Location): Pair<Int,Int>{
var diffX = location.x - player.location.x
var diffY = location.y - player.location.y
if(diffX > 1) diffX = 1
if(diffX < -1) diffX = -1
if(diffY > 1) diffY = 1
if(diffY < -1) diffY = -1
return Pair(diffX,diffY)
}
fun configure(objects: IntArray, pointA: Location, pointB: Location, option: String, levelReq: Int){
val instance = SteppingStoneInstance(pointA,pointB, option, levelReq)
objects.forEach {
SceneryDefinition.forId(it).handlers["option:$option"] = this
}
stones.put(pointA,instance)
stones.put(pointB, instance)
}
override fun newInstance(arg: Any?): Plugin<Any> {
configure(intArrayOf(2335,2333),Location.create(2925,2947,0),Location.create(2925,2951,0),"cross",30)
configure(intArrayOf(9315),Location.create(3149, 3363, 0),Location.create(3154, 3363, 0),"jump-onto",31)
return this
}
companion object {
/**
* Represents the animation to use.
*/
private val ANIMATION = Animation(741)
}
}
@@ -0,0 +1,108 @@
package content.global.skill.agility.shortcuts;
import core.game.activity.ActivityManager;
import core.game.node.entity.impl.PulseType;
import core.plugin.Initializable;
import content.global.skill.agility.AgilityShortcut;
import core.game.interaction.MovementPulse;
import core.game.node.entity.impl.ForceMovement;
import core.game.node.entity.player.Player;
import core.game.node.scenery.Scenery;
import core.game.system.task.Pulse;
import core.game.world.GameWorld;
import core.game.world.map.Direction;
import core.game.world.map.Location;
import core.game.world.update.flag.context.Animation;
/**
* Handles a stile shortcut.
* @author Vexia
*/
@Initializable
public class StileShortcut extends AgilityShortcut {
/**
* Constructs a new {@Code StileShortcut} {@Code Object}
*/
public StileShortcut() {
super(new int[] { 993, 3730, 7527, 12982, 19222, 22302, 29460, 33842, 34776, 39508, 39509, 39510 }, 1, 0.0, false, 0.0, new String[] { "climb-over" });
}
@Override
public void run(final Player player, final Scenery object, String option, boolean failed) {
player.getWalkingQueue().reset();
Location loc = getLocation(player, object, true);
player.getWalkingQueue().addPath(loc.getX(), loc.getY());
player.getPulseManager().run(new MovementPulse(player, loc) {
@Override
public boolean pulse() {
climb(player, object);
return true;
}
}, PulseType.STANDARD);
}
/**
* Method used to climb the stile.
* @param player the player.
* @param object the object.
*/
public static void climb(final Player player, final Scenery object) {
player.lock(1);
int delay = 0;
GameWorld.getPulser().submit(new Pulse(delay, player) {
@Override
public boolean pulse() {
ForceMovement movement = new ForceMovement(player, getLocation(player, object, true), getLocation(player, object, false), Animation.create(839)) {
@Override
public void stop() {
super.stop();
if (object.getId() == 19222) {// falconry.
handleFalconry(player, object);
}
}
};
movement.run(player, 5);
return true;
}
});
}
/**
* Method used to get the end location.
* @param player the player.
* @param object the object.
* @param start if getting the start loc.
* @return the location.
*/
public static Location getLocation(final Player player, final Scenery object, boolean start) {
if ((object.getDirection() == Direction.NORTH || object.getDirection() == Direction.SOUTH)) {
if (player.getLocation().getY() <= object.getLocation().getY()) {
return start ? object.getLocation() : object.getLocation().transform(0, 1, 0);
} else {
return start ? object.getLocation().transform(0, 1, 0) : object.getLocation();
}
} else {
if (player.getLocation().getX() <= object.getLocation().getX()) {
return start ? object.getLocation() : object.getLocation().transform(1, 0, 0);
} else {
return start ? object.getLocation().transform(1, 0, 0) : object.getLocation();
}
}
}
/**
* Method used to handle the falconry stile.
* @param player the player.
* @param object the object.
*/
private static void handleFalconry(final Player player, Scenery object) {
if (player.getLocation().equals(Location.create(2371, 3621, 0))) {
ActivityManager.start(player, "falconry", false);
} else {
ActivityManager.getActivity("falconry").leave(player, false);
}
}
}
@@ -0,0 +1,78 @@
package content.global.skill.agility.shortcuts;
import core.cache.def.impl.SceneryDefinition;
import core.plugin.Initializable;
import core.plugin.Plugin;
import content.global.skill.agility.AgilityShortcut;
import core.game.node.Node;
import core.game.node.entity.impl.ForceMovement;
import core.game.node.entity.player.Player;
import core.game.node.scenery.Scenery;
import core.game.system.task.Pulse;
import core.game.world.GameWorld;
import core.game.world.map.Location;
import core.game.world.update.flag.context.Animation;
/**
* Handles the strange floor shortcut.
* @author Vexia
*/
@Initializable
public class StrangeFloorShortcut extends AgilityShortcut {
/**
* Represents the running animation.
*/
private static final Animation RUNNING_ANIM = new Animation(1995);
/**
* Represents the jumping animation.
*/
private static final Animation JUMP_ANIM = new Animation(1603);
/**
* Constructs a new {@Code StrangeFloorShortcut} {@Code
* Object}
*/
public StrangeFloorShortcut() {
super(new int[] { 9294 }, 80, 0.0, "jump-over");
}
@Override
public void run(final Player player, Scenery object, String option, boolean failed) {
GameWorld.getPulser().submit(new Pulse(1, player) {
@Override
public boolean pulse() {
player.getAnimator().forceAnimation(JUMP_ANIM);
return true;
}
});
GameWorld.getPulser().submit(new Pulse(2, player) {
@Override
public boolean pulse() {
player.getAnimator().forceAnimation(RUNNING_ANIM);
return true;
}
});
ForceMovement.run(player, player.getLocation().getX() >= 2880 ? Location.create(2881, 9813, 0) : Location.create(2877, 9813, 0), player.getLocation().getX() >= 2880 ? Location.create(2877, 9813, 0) : Location.create(2881, 9813, 0), RUNNING_ANIM, 13);
}
@Override
public Location getDestination(Node node, Node n) {
return node.getLocation().getX() >= 2880 ? Location.create(2881, 9813, 0) : Location.create(2877, 9813, 0);
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
configure(this);
return this;
}
@Override
public void configure(AgilityShortcut shortcut) {
SceneryDefinition.forId(getIds()[0]).getHandlers().put("option:jump-over",this);
}
}
@@ -0,0 +1,135 @@
package content.global.skill.agility.shortcuts;
import core.game.node.entity.player.link.diary.DiaryType;
import content.global.skill.agility.AgilityShortcut;
import core.game.node.Node;
import core.game.node.entity.impl.ForceMovement;
import core.game.node.entity.player.Player;
import core.game.node.scenery.Scenery;
import core.game.system.task.Pulse;
import core.game.world.GameWorld;
import core.game.world.map.Direction;
import core.game.world.map.Location;
import core.game.world.update.flag.context.Animation;
import core.plugin.Initializable;
import core.plugin.Plugin;
/**
* Handles a tunnel shortcut.
* @author Vexia
*/
@Initializable
public class TunnelShortcut extends AgilityShortcut {
/**
* The climbing down animation.
*/
private static final Animation CLIMB_DOWN = Animation.create(2589);
/**
* The crawling through animation.
*/
private static final Animation CRAWL_THROUGH = Animation.create(2590);
/**
* The climbing up animation.
*/
private static final Animation CLIMB_UP = Animation.create(2591);
/**
* The increment offset.
*/
private int offset;
/**
* Constructs a new {@Code TunnelShortcut} {@Code Object}
*/
public TunnelShortcut() {
super(new int[] {}, 0, 0.0);
}
/**
* Constructs a new {@Code TunnelShortcut} {@Code Object}
* @param ids the ids.
* @param level the level.
* @param experience the experience.
* @param options the options.
*/
public TunnelShortcut(int[] ids, int level, double experience, int offset, String... options) {
super(ids, level, experience, options);
this.offset = offset;
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
configure(new TunnelShortcut(new int[] { 9309, 9310 }, 26, 0.0, 0, "climb-into"));
configure(new TunnelShortcut(new int[] { 9302, 9301 }, 16, 0.0, 1, "climb-into", "climb-under"));
configure(new TunnelShortcut(new int[] { 14922 }, 1, 0.0, 1, "enter"));
return this;
}
@Override
public void run(final Player player, Scenery object, String option, boolean failed) {
player.lock(6);
final Scenery o = object;
final Location start = player.getLocation();
final Direction dir = Direction.getDirection(start, o.getLocation());
if (object.getLocation().getX() == 2575) {
offset = 1;
}
ForceMovement.run(player, start, o.getLocation(), CLIMB_DOWN, 8);
GameWorld.getPulser().submit(new Pulse(1, player) {
int count;
@Override
public boolean pulse() {
switch (++count) {
case 2:
player.animate(CRAWL_THROUGH);
player.getProperties().setTeleportLocation(start.transform(dir, 2 + offset));
break;
case 5:
ForceMovement.run(player, player.getLocation(), start.transform(dir, 4 + offset), CLIMB_UP, 19);
break;
case 6:
player.animate(ForceMovement.WALK_ANIMATION);
if ((object.getId() == 9309 || object.getId() == 9310) && !player.getAchievementDiaryManager().getDiary(DiaryType.FALADOR).isComplete(1,1)) {
player.getAchievementDiaryManager().getDiary(DiaryType.FALADOR).updateTask(player, 1, 1, true);
}
return true;
}
return false;
}
});
}
@Override
public Location getDestination(Node node, Node n) {
if (n.getId() == 14922) {
return n.getLocation().transform(getObjectDirection(n.asScenery().getDirection()), 1);
}
return getStart(n.getLocation(), n.getDirection());
}
/**
* Gets the start location.
* @param location the location.
* @param dir the dir.
* @return the location.
*/
public Location getStart(Location location, Direction dir) {
switch (dir) {
case NORTH:
break;
case SOUTH:
break;
case EAST:
return location.transform(0, location.getY() == 3111 ? 1 : -1, 0);
case WEST:
return location.transform(0, 1, 0);
default:
return location;
}
return location;
}
}
@@ -0,0 +1,126 @@
package content.global.skill.agility.shortcuts;
import core.cache.def.impl.SceneryDefinition;
import core.game.component.Component;
import org.rs09.consts.Items;
import core.game.interaction.OptionHandler;
import core.game.node.Node;
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.map.Location;
import core.game.world.map.RegionManager;
import core.game.world.update.flag.context.Animation;
import core.plugin.Initializable;
import core.plugin.Plugin;
import core.game.node.entity.skill.Skills;
import java.util.HashMap;
import java.util.Map;
@Initializable
public class WaterOrbGrapple extends OptionHandler {
private static final HashMap<Integer, Integer> REQUIREMENTS = new HashMap<>();
private static final String requirementsString;
static {
REQUIREMENTS.putIfAbsent(Skills.AGILITY, 36);
REQUIREMENTS.putIfAbsent(Skills.RANGE, 39);
REQUIREMENTS.putIfAbsent(Skills.STRENGTH, 22);
requirementsString = "You need at least "
+ REQUIREMENTS.get(Skills.AGILITY) + " " + Skills.SKILL_NAME[Skills.AGILITY] + ", "
+ REQUIREMENTS.get(Skills.RANGE) + " " + Skills.SKILL_NAME[Skills.RANGE] + ", and "
+ REQUIREMENTS.get(Skills.STRENGTH) + " " + Skills.SKILL_NAME[Skills.STRENGTH]
+ " to use this shortcut.";
}
private static final int[] CBOWS = new int[]{
Items.MITH_CROSSBOW_9181,
Items.ADAMANT_CROSSBOW_9183,
Items.RUNE_CROSSBOW_9185,
Items.DORGESHUUN_CBOW_8880
};
private static final Item MITH_GRAPPLE = new Item(9419);
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
SceneryDefinition.forId(17062).getHandlers().put("option:grapple", this);
return this;
}
@Override
public boolean handle(Player player, Node node, String option) {
Location destination;
Location current = player.getLocation();
Scenery rock = RegionManager.getObject(Location.create(2841, 3426, 0));
Scenery tree = RegionManager.getObject(Location.create(2841, 3434, 0));
switch (option) {
case "grapple":
destination = Location.create(2841, 3433, 0);
for (Map.Entry<Integer, Integer> e : REQUIREMENTS.entrySet()) {
if (player.getSkills().getLevel(e.getKey()) < e.getValue()) {
player.getDialogueInterpreter().sendDialogue(requirementsString);
return true;
}
}
if (!player.getEquipment().containsAtLeastOneItem(CBOWS) || !player.getEquipment().containsItem(MITH_GRAPPLE)) {
player.getDialogueInterpreter().sendDialogue("You need a Mithril crossbow and a Mithril grapple in order to do this.");
return true;
}
player.lock();
GameWorld.getPulser().submit(new Pulse(1, player) {
int counter = 1;
Component tab;
@Override
public boolean pulse() {
switch (counter++) {
// TODO this animation sequence is wrong. sendPositionedGraphic doesn't work correctly, and rest of water crossing not well implemented
// See 4:24 in https://www.youtube.com/watch?v=O90y-N_vwTc
// rope gfx is 67
// splash gfx are 68 and 69, not sure why there are two
// not sure what swimming animation is, could be 4464 thru 4468
case 1:
player.faceLocation(destination);
player.animate(new Animation(4230));
break;
case 3:
player.getPacketDispatch().sendPositionedGraphic(67, 10, 0, Location.create(2840,3427,0)); //
break;
case 4:
SceneryBuilder.replace(rock, rock.transform(rock.getId() + 1), 10);
SceneryBuilder.replace(tree, tree.transform(tree.getId() + 1), 10);
break;
case 5:
break;
case 13:
player.getProperties().setTeleportLocation(destination);
break;
case 14:
player.unlock();
player.getAchievementDiaryManager().finishTask(player, DiaryType.SEERS_VILLAGE, 2, 10);
return true;
}
return false;
}
});
break;
}
return true;
}
@Override
public Location getDestination(final Node moving, final Node destination) {
// Run between rock and stream before firing grapple
return Location.create(2841, 3427, 0);
}
}
@@ -0,0 +1,121 @@
package content.global.skill.agility.shortcuts;
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.impl.ForceMovement;
import core.game.node.entity.player.Player;
import core.game.node.item.Item;
import core.game.system.task.Pulse;
import core.game.world.GameWorld;
import core.game.world.map.Location;
import core.game.world.update.flag.context.Animation;
import core.game.world.update.flag.context.Graphics;
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;
import core.game.node.entity.skill.Skills;
import java.util.HashMap;
import java.util.Map;
@Initializable
public class YanilleGrapple extends OptionHandler {
private static final HashMap<Integer, Integer> REQUIREMENTS = new HashMap<>();
private static String requirementsString;
static {
REQUIREMENTS.putIfAbsent(Skills.AGILITY, 39);
REQUIREMENTS.putIfAbsent(Skills.RANGE, 21);
REQUIREMENTS.putIfAbsent(Skills.STRENGTH, 38);
requirementsString = "You need at least "
+ REQUIREMENTS.get(Skills.AGILITY) + " " + Skills.SKILL_NAME[Skills.AGILITY] + ", "
+ REQUIREMENTS.get(Skills.RANGE) + " " + Skills.SKILL_NAME[Skills.RANGE] + ", and "
+ REQUIREMENTS.get(Skills.STRENGTH) + " " + Skills.SKILL_NAME[Skills.STRENGTH]
+ " to use this shortcut.";
}
private static final Item MITH_CBOW = new Item(9181);
private static final Item MITH_GRAPPLE = new Item(9419);
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
SceneryDefinition.forId(17047).getHandlers().put("option:grapple", this);
SceneryDefinition.forId(17048).getHandlers().put("option:jump", this);
return this;
}
@Override
public boolean handle(Player player, Node node, String option) {
Location destination;
Location current = player.getLocation();
switch (option) {
case "jump":
ForceMovement.run(player,
current,
current.getY() < 3074 ? Location.create(2556,3072,0) : Location.create(2556,3075,0),
new Animation(7268),
10);
break;
case "grapple":
destination = current.getY() < 3073
? Location.create(2556, 3073, 1)
: Location.create(2556, 3074, 1);
for (Map.Entry<Integer, Integer> e : REQUIREMENTS.entrySet()) {
if (player.getSkills().getLevel(e.getKey()) < e.getValue()) {
player.getDialogueInterpreter().sendDialogue(requirementsString);
return true;
}
}
if (!player.getEquipment().containsItem(MITH_CBOW) || !player.getEquipment().containsItem(MITH_GRAPPLE)) {
player.getDialogueInterpreter().sendDialogue("You need a Mithril crossbow and a Mithril grapple in order to do this.");
return true;
}
player.lock();
GameWorld.getPulser().submit(new Pulse(1, player) {
int counter = 1;
Component tab;
@Override
public boolean pulse() {
switch (counter++) {
case 1:
player.faceLocation(destination);
player.visualize(new Animation(4455), new Graphics(760, 100));
break;
case 8:
tab = player.getInterfaceManager().getSingleTab();
player.getInterfaceManager().openOverlay(new Component(115));
PacketRepository.send(MinimapState.class, new MinimapStateContext(player, 2));
player.getInterfaceManager().removeTabs(0, 1, 2, 3, 4, 5, 6, 11, 12);
break;
case 13:
player.getProperties().setTeleportLocation(destination);
break;
case 14:
player.getInterfaceManager().restoreTabs();
if (tab != null) {
player.getInterfaceManager().openTab(tab);
}
PacketRepository.send(MinimapState.class, new MinimapStateContext(player, 0));
player.getInterfaceManager().closeOverlay();
player.getInterfaceManager().close();
player.unlock();
return true;
}
return false;
}
});
break;
}
return true;
}
}
@@ -0,0 +1,42 @@
package content.global.skill.agility.shortcuts;
import core.plugin.Initializable;
import core.game.node.entity.skill.Skills;
import content.global.skill.agility.AgilityShortcut;
import core.game.node.entity.impl.ForceMovement;
import core.game.node.entity.player.Player;
import core.game.node.scenery.Scenery;
import core.game.world.map.Direction;
import core.game.world.map.Location;
import core.game.world.update.flag.context.Animation;
/**
* Handles the zanaris cosmic altar shortcuts for runecrafters.
* @author Splinter
*/
@Initializable
public class ZanarisSqueezeShortcut extends AgilityShortcut {
/**
* Represents the squeeze animation.
*/
private static final Animation ANIMATION = new Animation(2240);
/**
* Constructs a new {@Code ZanarisSqueezeShortcut} {@Code Object}
*/
public ZanarisSqueezeShortcut() {
super(new int[] { 12127 }, 46, 0.0, "squeeze-past");
}
@Override
public void run(Player player, Scenery object, String option, boolean failed) {
if (player.getSkills().getLevel(Skills.AGILITY) < 66 && (object.getLocation().equals(new Location(2408, 4395)) || object.getLocation().equals(new Location(2415, 4402)))) {
player.getDialogueInterpreter().sendDialogue("You need an Agility level of at least 66 to negotiate this obstacle.");
return;
}
Location to = player.getLocation().getY() < object.getLocation().getY() ? object.getLocation().transform(0, 1, 0) : object.getLocation().transform(0, -1, 0);
Direction dir = player.getLocation().getY() < object.getLocation().getY() ? Direction.NORTH : Direction.SOUTH;
ForceMovement.run(player, player.getLocation(), to, ANIMATION, ANIMATION, dir, 13).setEndAnimation(Animation.RESET);
}
}
@@ -0,0 +1,526 @@
package content.global.skill.construction;
import core.game.world.update.flag.context.Animation;
import java.util.ArrayList;
import java.util.List;
/**
* Represents a building hotspot.
* @author Emperor
*
*/
public enum BuildHotspot {
/**
* Low level garden hotspots.
*/
CENTREPIECE_1(15361, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.PORTAL, Decoration.ROCK, Decoration.POND, Decoration.IMP_STATUE, Decoration.SMALL_OBELISK, Decoration.DUNGEON_ENTRANCE),
BIG_TREE_1(15362, BuildHotspotType.INDIVIDUAL, BuildingUtils.PLANT_ANIM, Decoration.BIG_DEAD_TREE, Decoration.BIG_TREE, Decoration.BIG_OAK_TREE, Decoration.BIG_WILLOW_TREE, Decoration.BIG_MAPLE_TREE, Decoration.BIG_YEW_TREE, Decoration.BIG_MAGIC_TREE),
TREE_1(15363, BuildHotspotType.INDIVIDUAL, BuildingUtils.PLANT_ANIM, Decoration.DEAD_TREE, Decoration.TREE, Decoration.OAK_TREE, Decoration.WILLOW_TREE, Decoration.MAPLE_TREE, Decoration.YEW_TREE, Decoration.MAGIC_TREE),
BIG_PLANT_1(15364, BuildHotspotType.INDIVIDUAL, BuildingUtils.PLANT_ANIM, Decoration.FERN, Decoration.BUSH, Decoration.TALL_PLANT),
BIG_PLANT_2(15365, BuildHotspotType.INDIVIDUAL, BuildingUtils.PLANT_ANIM, Decoration.SHORT_PLANT, Decoration.LARGE_LEAF_PLANT, Decoration.HUGE_PLANT),
SMALL_PLANT_1(15366, BuildHotspotType.INDIVIDUAL, BuildingUtils.PLANT_ANIM, Decoration.PLANT, Decoration.SMALL_FERN, Decoration.FERN_SP),
SMALL_PLANT_2(15367, BuildHotspotType.INDIVIDUAL, BuildingUtils.PLANT_ANIM, Decoration.DOCK_LEAF, Decoration.THISTLE, Decoration.REEDS),
/**
* Low level Parlor hotspots.
*/
CHAIRS_1(15410, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.CRUDE_CHAIR,Decoration.WOODEN_CHAIR, Decoration.ROCKING_CHAIR, Decoration.OAK_CHAIR, Decoration.OAK_ARMCHAIR, Decoration.TEAK_ARMCHAIR, Decoration.MAHOGANY_ARMCHAIR),
CHAIRS_2(15411, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.CRUDE_CHAIR, Decoration.WOODEN_CHAIR,Decoration.ROCKING_CHAIR, Decoration.OAK_CHAIR, Decoration.OAK_ARMCHAIR, Decoration.TEAK_ARMCHAIR, Decoration.MAHOGANY_ARMCHAIR),
CHAIRS_3(15412, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.CRUDE_CHAIR, Decoration.WOODEN_CHAIR,Decoration.ROCKING_CHAIR, Decoration.OAK_CHAIR, Decoration.OAK_ARMCHAIR, Decoration.TEAK_ARMCHAIR, Decoration.MAHOGANY_ARMCHAIR),
FIREPLACE(15418, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.CLAY_FIREPLACE, Decoration.STONE_FIREPLACE,Decoration.MARBLE_FIREPLACE),
FIREPLACE2(15267, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.CLAY_FIREPLACE, Decoration.STONE_FIREPLACE,Decoration.MARBLE_FIREPLACE),
CURTAINS(15419, BuildHotspotType.RECURSIVE, BuildingUtils.BUILD_MID_ANIM, Decoration.TORN_CURTAINS, Decoration.CURTAINS, Decoration.OPULENT_CURTAINS),
BOOKCASE(15416, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_HIGH_ANIM, Decoration.WOODEN_BOOKCASE, Decoration.OAK_BOOKCASE, Decoration.MAHOGANY_BOOKCASE),
RUG(15415, BuildHotspotType.LINKED, BuildingUtils.BUILD_LOW_ANIM, Decoration.BROWN_RUG_CORNER, Decoration.RED_RUG_CORNER, Decoration.OPULENT_RUG_CORNER),
RUG2(15414, BuildHotspotType.LINKED, BuildingUtils.BUILD_LOW_ANIM, Decoration.BROWN_RUG_END, Decoration.RED_RUG_END, Decoration.OPULENT_RUG_END),
RUG3(15413, BuildHotspotType.LINKED, BuildingUtils.BUILD_LOW_ANIM, Decoration.BROWN_RUG_CENTER, Decoration.RED_RUG_CENTER, Decoration.OPULENT_RUG_CENTER),
/**
* Low level Kitchen hotspots.
*/
LARDER(15403, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_HIGH_ANIM, Decoration.WOODEN_LARDER, Decoration.OAK_LARDER,Decoration.TEAK_LARDER),
SINK(15404, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.PUMP_AND_DRAIN, Decoration.PUMP_AND_TUB, Decoration.SINK),
KITCHEN_TABLE(15405, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.KITCHEN_WOODEN_TABLE,Decoration.KITCHEN_OAK_TABLE, Decoration.KITCHEN_TEAK_TABLE),
CAT_BLANKET(15402, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.CAT_BLANKET, Decoration.CAT_BASKET,Decoration.CAST_BASKET_CUSHIONED),
STOVE(15398, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.BASIC_FIREPIT, Decoration.FIREPIT_WITH_HOOK, Decoration.FIREPIT_WITH_POT, Decoration.SMALL_OVEN, Decoration.LARGE_OVEN, Decoration.BASIC_RANGE, Decoration.FANCY_RANGE),
SHELVES(15400, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_HIGH_ANIM, Decoration.WOODEN_SHELVES_1,Decoration.WOODEN_SHELVES_2, Decoration.WOODEN_SHELVES_3,Decoration.OAK_SHELVES_1, Decoration.OAK_SHELVES_2, Decoration.TEAK_SHELVES_1, Decoration.TEAK_SHELVES_2),
SHELVES_2(15399, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_HIGH_ANIM, Decoration.WOODEN_SHELVES_1,Decoration.WOODEN_SHELVES_2, Decoration.WOODEN_SHELVES_3,Decoration.OAK_SHELVES_1, Decoration.OAK_SHELVES_2,Decoration.TEAK_SHELVES_1, Decoration.TEAK_SHELVES_2),
BARRELS(15401, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.BASIC_BEER_BARREL, Decoration.CIDER_BARREL,Decoration.ASGARNIAN_ALE_BARREL, Decoration.GREENMANS_ALE_BARREL,Decoration.DRAGON_BITTER_BARREL, Decoration.CHEFS_DELIGHT_BARREL),
/**
* Low-level Dining hotspots.
*/
FIREPLACE_DINING(15301, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.CLAY_FIREPLACE, Decoration.STONE_FIREPLACE, Decoration.MARBLE_FIREPLACE),
DINING_TABLE(15298, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.DINING_TABLE_WOOD, Decoration.DINING_TABLE_OAK, Decoration.DINING_TABLE_CARVED_OAK, Decoration.DINING_TABLE_TEAK,Decoration.DINING_TABLE_CARVED_TEAK, Decoration.DINING_TABLE_MAHOGANY,Decoration.DINING_TABLE_OPULENT),
DINING_CURTAINS(15302, BuildHotspotType.RECURSIVE, BuildingUtils.BUILD_MID_ANIM, Decoration.TORN_CURTAINS, Decoration.CURTAINS, Decoration.OPULENT_CURTAINS),
DINING_BENCH_1(15300, BuildHotspotType.RECURSIVE, BuildingUtils.BUILD_MID_ANIM, Decoration.BENCH_WOODEN, Decoration.BENCH_OAK, Decoration.BENCH_CARVED_OAK, Decoration.BENCH_TEAK, Decoration.BENCH_CARVED_TEAK, Decoration.BENCH_MAHOGANY, Decoration.BENCH_GILDED),
DINING_BENCH_2(15299, BuildHotspotType.RECURSIVE, BuildingUtils.BUILD_MID_ANIM, Decoration.BENCH_WOODEN, Decoration.BENCH_OAK, Decoration.BENCH_CARVED_OAK, Decoration.BENCH_TEAK, Decoration.BENCH_CARVED_TEAK, Decoration.BENCH_MAHOGANY,Decoration.BENCH_GILDED),
ROPE_BELL_PULL(15304, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_HIGH_ANIM, Decoration.ROPE_PULL, Decoration.BELL_PULL, Decoration.FANCY_BELL_PULL),
WALL_DECORATION(15303, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_HIGH_ANIM, Decoration.OAK_DECORATION, Decoration.TEAK_DECORATION, Decoration.GILDED_DECORATION),
/**
* 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),
TOOL1(15443, BuildHotspotType.INDIVIDUAL, 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.INDIVIDUAL, 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.INDIVIDUAL, 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.INDIVIDUAL, 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.INDIVIDUAL, 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),
/**
* Bedroom hotspots.
*/
BED(15260, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.WOODEN_BED, Decoration.OAK_BED, Decoration.LARGE_OAK_BED, Decoration.TEAK_BED, Decoration.LARGE_TEAK_BED, Decoration.FOUR_POSTER, Decoration.GILDED_FOUR_POSTER),
CLOCK(15268, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_HIGH_ANIM, Decoration.OAK_CLOCK, Decoration.TEAK_CLOCK, Decoration.GILDED_CLOCK),
DRESSER(15262, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.SHAVING_STAND, Decoration.OAK_SHAVING_STAND, Decoration.OAK_DRESSER, Decoration.TEAK_DRESSER, Decoration.FANCY_TEAK_DRESSER, Decoration.MAHOGANY_DRESSER, Decoration.GILDED_DRESSER),
DRAWERS(15261, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.SHOE_BOX, Decoration.OAK_DRAWERS, Decoration.OAK_WARDROBE, Decoration.TEAK_DRAWERS, Decoration.TEAK_WARDROBE, Decoration.MAHOGANY_WARDROBE, Decoration.GILDED_WARDROBE),
BEDROOM_CURTAINS(15263, BuildHotspotType.RECURSIVE, BuildingUtils.BUILD_MID_ANIM, Decoration.TORN_CURTAINS, Decoration.CURTAINS, Decoration.OPULENT_CURTAINS),
BEDROOM_RUG(15264, BuildHotspotType.LINKED, BuildingUtils.BUILD_LOW_ANIM, Decoration.BROWN_RUG_CENTER, Decoration.RED_RUG_CENTER, Decoration.OPULENT_RUG_CENTER),
BEDROOM_RUG2(15265, BuildHotspotType.LINKED, BuildingUtils.BUILD_LOW_ANIM, Decoration.BROWN_RUG_END, Decoration.RED_RUG_END, Decoration.OPULENT_RUG_END),
BEDROOM_RUG3(15266, BuildHotspotType.LINKED, BuildingUtils.BUILD_LOW_ANIM, Decoration.BROWN_RUG_CORNER, Decoration.RED_RUG_CORNER, Decoration.OPULENT_RUG_CORNER),
/**
* Skill hall hotspots.
*/
ARMOUR_SPACE(15385, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.MITHRIL_ARMOUR, Decoration.ADAMANT_ARMOUR, Decoration.RUNE_ARMOUR),
ARMOUR_SPACE2(15384, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.MITHRIL_ARMOUR, Decoration.ADAMANT_ARMOUR, Decoration.RUNE_ARMOUR),
HEAD_TROPHY(15382, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_HIGH_ANIM, Decoration.CRAWLING_HAND, Decoration.COCKATRICE_HEAD, Decoration.BASILISK_HEAD, Decoration.KURASK_HEAD, Decoration.ABYSSAL_DEMON_HEAD, Decoration.KBD_HEAD, Decoration.KQ_HEAD),
RUNE_CASE(15386, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.RUNE_CASE1, Decoration.RUNE_CASE2),
FISHING_TROPHY(15383, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_HIGH_ANIM, Decoration.MOUNTED_BASS, Decoration.MOUNTED_SWORDFISH, Decoration.MOUNTED_SHARK),
HALL_RUG(15377, BuildHotspotType.LINKED, BuildingUtils.BUILD_LOW_ANIM, Decoration.BROWN_RUG_CENTER, Decoration.RED_RUG_CENTER, Decoration.OPULENT_RUG_CENTER),
HALL_RUG2(15378, BuildHotspotType.LINKED, BuildingUtils.BUILD_LOW_ANIM, Decoration.BROWN_RUG_END, Decoration.RED_RUG_END, Decoration.OPULENT_RUG_END),
HALL_RUG3(15379, BuildHotspotType.LINKED, BuildingUtils.BUILD_LOW_ANIM, Decoration.BROWN_RUG_CORNER, Decoration.RED_RUG_CORNER, Decoration.OPULENT_RUG_CORNER),
/**
* Games room hotspots.
*/
RANGING_GAME(15346, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.HOOP_AND_STICK, Decoration.DARTBOARD, Decoration.ARCHERY_TARGET),
ATTACK_STONE(15344, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.CLAY_STONE, Decoration.LIMESTONE_STONE, Decoration.MARBLE_STONE),
PRIZE_CHEST(15343, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.OAK_CHEST, Decoration.TEAK_CHEST, Decoration.MAHOGANY_CHEST),
ELEMENTAL_BALANCE(15345, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.BALANCE_1, Decoration.BALANCE_2, Decoration.BALANCE_3),
GAME_SPACE(15342, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.JESTER, Decoration.TREASURE_HUNT, Decoration.HANGMAN),
/**
* Portal room hotspots.
*/
TELEPORT_FOCUS(15409, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.TELEPORT_FOCUS, Decoration.GREATER_TELEPORT_FOCUS, Decoration.SCRYING_POOL),
PORTAL1(15406, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.TEAK_PORTAL, Decoration.MAHOGANY_PORTAL, Decoration.MARBLE_PORTAL,
Decoration.TEAK_VARROCK_PORTAL,
Decoration.MAHOGANY_VARROCK_PORTAL,
Decoration.MARBLE_VARROCK_PORTAL,
Decoration.TEAK_LUMBRIDGE_PORTAL,
Decoration.MAHOGANY_LUMBRIDGE_PORTAL,
Decoration.MARBLE_LUMBRIDGE_PORTAL,
Decoration.TEAK_FALADOR_PORTAL,
Decoration.MAHOGANY_FALADOR_PORTAL,
Decoration.MARBLE_FALADOR_PORTAL,
Decoration.TEAK_CAMELOT_PORTAL,
Decoration.MAHOGANY_CAMELOT_PORTAL,
Decoration.MARBLE_CAMELOT_PORTAL,
Decoration.TEAK_ARDOUGNE_PORTAL,
Decoration.MAHOGANY_ARDOUGNE_PORTAL,
Decoration.MARBLE_ARDOUGNE_PORTAL,
Decoration.TEAK_YANILLE_PORTAL,
Decoration.MAHOGANY_YANILLE_PORTAL,
Decoration.MARBLE_YANILLE_PORTAL,
Decoration.TEAK_KHARYRLL_PORTAL,
Decoration.MAHOGANY_KHARYRLL_PORTAL,
Decoration.MARBLE_KHARYRLL_PORTAL),
PORTAL2(15407, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.TEAK_PORTAL, Decoration.MAHOGANY_PORTAL, Decoration.MARBLE_PORTAL,
Decoration.TEAK_VARROCK_PORTAL,
Decoration.MAHOGANY_VARROCK_PORTAL,
Decoration.MARBLE_VARROCK_PORTAL,
Decoration.TEAK_LUMBRIDGE_PORTAL,
Decoration.MAHOGANY_LUMBRIDGE_PORTAL,
Decoration.MARBLE_LUMBRIDGE_PORTAL,
Decoration.TEAK_FALADOR_PORTAL,
Decoration.MAHOGANY_FALADOR_PORTAL,
Decoration.MARBLE_FALADOR_PORTAL,
Decoration.TEAK_CAMELOT_PORTAL,
Decoration.MAHOGANY_CAMELOT_PORTAL,
Decoration.MARBLE_CAMELOT_PORTAL,
Decoration.TEAK_ARDOUGNE_PORTAL,
Decoration.MAHOGANY_ARDOUGNE_PORTAL,
Decoration.MARBLE_ARDOUGNE_PORTAL,
Decoration.TEAK_YANILLE_PORTAL,
Decoration.MAHOGANY_YANILLE_PORTAL,
Decoration.MARBLE_YANILLE_PORTAL,
Decoration.TEAK_KHARYRLL_PORTAL,
Decoration.MAHOGANY_KHARYRLL_PORTAL,
Decoration.MARBLE_KHARYRLL_PORTAL),
PORTAL3(15408, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.TEAK_PORTAL, Decoration.MAHOGANY_PORTAL, Decoration.MARBLE_PORTAL,
Decoration.TEAK_VARROCK_PORTAL,
Decoration.MAHOGANY_VARROCK_PORTAL,
Decoration.MARBLE_VARROCK_PORTAL,
Decoration.TEAK_LUMBRIDGE_PORTAL,
Decoration.MAHOGANY_LUMBRIDGE_PORTAL,
Decoration.MARBLE_LUMBRIDGE_PORTAL,
Decoration.TEAK_FALADOR_PORTAL,
Decoration.MAHOGANY_FALADOR_PORTAL,
Decoration.MARBLE_FALADOR_PORTAL,
Decoration.TEAK_CAMELOT_PORTAL,
Decoration.MAHOGANY_CAMELOT_PORTAL,
Decoration.MARBLE_CAMELOT_PORTAL,
Decoration.TEAK_ARDOUGNE_PORTAL,
Decoration.MAHOGANY_ARDOUGNE_PORTAL,
Decoration.MARBLE_ARDOUGNE_PORTAL,
Decoration.TEAK_YANILLE_PORTAL,
Decoration.MAHOGANY_YANILLE_PORTAL,
Decoration.MARBLE_YANILLE_PORTAL,
Decoration.TEAK_KHARYRLL_PORTAL,
Decoration.MAHOGANY_KHARYRLL_PORTAL,
Decoration.MARBLE_KHARYRLL_PORTAL),
/**
* Quest Hall hotspots.
*/
GUILD_TROPHY(15394, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.ANTIDRAGON_SHIELD, Decoration.AMULET_OF_GLORY, Decoration.CAPE_OF_LEGENDS),
PORTRAIT(15392, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_HIGH_ANIM, Decoration.KING_ARTHUR, Decoration.ELENA, Decoration.GIANT_DWARF, Decoration.MISCELLANIANS),
LANDSCAPE(15393, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_HIGH_ANIM, Decoration.LUMBRIDGE, Decoration.THE_DESERT, Decoration.MORYTANIA, Decoration.KARAMJA, Decoration.ISAFDAR),
SWORD(15395, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_HIGH_ANIM, Decoration.SILVERLIGHT, Decoration.EXCALIBUR, Decoration.DARKLIGHT),
MAP(15396, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_HIGH_ANIM, Decoration.SMALL_MAP, Decoration.MEDIUM_MAP, Decoration.LARGE_MAP),
BOOKCASE2(15397, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_HIGH_ANIM, Decoration.WOODEN_BOOKCASE, Decoration.OAK_BOOKCASE, Decoration.MAHOGANY_BOOKCASE),
/**
* Manegerie Hotspots
*/
OBELISK(44911, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.MINI_OBELISK),
PET_FEEDER(44910, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.OAK_PET_FEEDER, Decoration.TEAK_PET_FEEDER, Decoration.MAHOGANY_PET_FEEDER),
PET_HOUSE(44909, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.OAK_PET_HOUSE, Decoration.TEAK_PET_HOUSE, Decoration.MAHOGANY_PET_HOUSE, Decoration.CONSECRATED_PET_HOUSE, Decoration.DESECRATED_PET_HOUSE, Decoration.NATURAL_PET_HOUSE),
HABITAT_1(44907, BuildHotspotType.LINKED, BuildingUtils.BUILD_MID_ANIM, Decoration.GARDEN_HABITAT, Decoration.JUNGLE_HABITAT, Decoration.DESERT_HABITAT, Decoration.POLAR_HABITAT, Decoration.VOLCANIC_HABITAT),
HABITAT_2(44908, BuildHotspotType.LINKED, BuildingUtils.BUILD_MID_ANIM, Decoration.GARDEN_HABITAT, Decoration.JUNGLE_HABITAT, Decoration.DESERT_HABITAT, Decoration.POLAR_HABITAT, Decoration.VOLCANIC_HABITAT),
/**
* Combat room hotspots.
*/
WALL_DECORATION2(15297, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_HIGH_ANIM, Decoration.OAK_DECORATION, Decoration.TEAK_DECORATION, Decoration.GILDED_DECORATION),
STORAGE_SPACE(15296, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.GLOVE_RACK, Decoration.WEAPONS_RACK, Decoration.EXTRA_WEAPONS_RACK),
CR_RING(15277, BuildHotspotType.LINKED, BuildingUtils.BUILD_MID_ANIM, Decoration.BOXING_RING, Decoration.FENCING_RING, Decoration.COMBAT_RING, Decoration.NOTHING, Decoration.NOTHING2),
CR_CORNER(15278, BuildHotspotType.LINKED, BuildingUtils.BUILD_MID_ANIM, Decoration.BOXING_RING, Decoration.FENCING_RING, Decoration.COMBAT_RING, Decoration.NOTHING, Decoration.NOTHING2),
CR_CORNER2(15279, BuildHotspotType.LINKED, BuildingUtils.BUILD_MID_ANIM, Decoration.BOXING_RING, Decoration.FENCING_RING, Decoration.COMBAT_RING, Decoration.NOTHING, Decoration.NOTHING2),
CR_RING3(15280, BuildHotspotType.LINKED, BuildingUtils.BUILD_MID_ANIM, Decoration.BOXING_RING, Decoration.FENCING_RING, Decoration.COMBAT_RING, Decoration.NOTHING, Decoration.MAGIC_BARRIER),
CR_CORNER3(15281, BuildHotspotType.LINKED, BuildingUtils.BUILD_MID_ANIM, Decoration.BOXING_RING, Decoration.FENCING_RING, Decoration.COMBAT_RING, Decoration.NOTHING, Decoration.NOTHING2),
CR_CORNER4(15282, BuildHotspotType.LINKED, BuildingUtils.BUILD_MID_ANIM, Decoration.BOXING_RING, Decoration.FENCING_RING, Decoration.COMBAT_RING, Decoration.NOTHING, Decoration.NOTHING2),
CR_INVISIBLE_WALL(15283, BuildHotspotType.LINKED, BuildingUtils.BUILD_MID_ANIM, Decoration.INVISIBLE_WALL, Decoration.INVISIBLE_WALL, Decoration.INVISIBLE_WALL, Decoration.INVISIBLE_WALL, Decoration.MAGIC_BARRIER),
CR_INVISIBLE_WALL2(15284, BuildHotspotType.LINKED, BuildingUtils.BUILD_MID_ANIM, Decoration.INVISIBLE_WALL2, Decoration.INVISIBLE_WALL2, Decoration.INVISIBLE_WALL2, Decoration.INVISIBLE_WALL2, Decoration.MAGIC_BARRIER),
CR_INVISIBLE_WALL3(15285, BuildHotspotType.LINKED, BuildingUtils.BUILD_MID_ANIM, Decoration.INVISIBLE_WALL3, Decoration.INVISIBLE_WALL3, Decoration.INVISIBLE_WALL3, Decoration.INVISIBLE_WALL3, Decoration.MAGIC_BARRIER),
CR_RING4(15286, BuildHotspotType.LINKED, BuildingUtils.BUILD_MID_ANIM, Decoration.BOXING_RING, Decoration.FENCING_RING, Decoration.COMBAT_RING, Decoration.NOTHING, Decoration.NOTHING2),
CR_RING2(15287, BuildHotspotType.LINKED, BuildingUtils.BUILD_MID_ANIM, Decoration.BOXING_RING, Decoration.FENCING_RING, Decoration.COMBAT_RING, Decoration.NOTHING, Decoration.MAGIC_BARRIER),
CR_FLOOR(15288, BuildHotspotType.LINKED, BuildingUtils.BUILD_MID_ANIM, Decoration.BOXING_MAT_SIDE, Decoration.FENCING_MAT_SIDE, Decoration.COMBAT_MAT_SIDE, Decoration.BALANCE_BEAM_CENTER, Decoration.NOTHING2),
CR_FLOOR2(15289, BuildHotspotType.LINKED, BuildingUtils.BUILD_MID_ANIM, Decoration.BOXING_MAT_CORNER, Decoration.FENCING_MAT_CORNER, Decoration.COMBAT_MAT_CORNER, Decoration.BALANCE_BEAM_RIGHT, Decoration.NOTHING2),
CR_FLOOR3(15290, BuildHotspotType.LINKED, BuildingUtils.BUILD_MID_ANIM, Decoration.BOXING_MAT_CORNER, Decoration.FENCING_MAT_CORNER, Decoration.COMBAT_MAT_CORNER, Decoration.BALANCE_BEAM_LEFT, Decoration.RANGING_PEDESTALS),
CR_FLOOR4(15291, BuildHotspotType.LINKED, BuildingUtils.BUILD_MID_ANIM, Decoration.BOXING_MAT_SIDE, Decoration.FENCING_MAT_SIDE, Decoration.COMBAT_MAT_SIDE, Decoration.NOTHING, Decoration.NOTHING2),
CR_FLOOR5(15292, BuildHotspotType.LINKED, BuildingUtils.BUILD_MID_ANIM, Decoration.BOXING_MAT, Decoration.FENCING_MAT, Decoration.COMBAT_MAT, Decoration.NOTHING, Decoration.NOTHING2),
CR_FLOOR6(15293, BuildHotspotType.LINKED, BuildingUtils.BUILD_MID_ANIM, Decoration.BOXING_MAT_SIDE, Decoration.FENCING_MAT_SIDE, Decoration.COMBAT_MAT_SIDE, Decoration.NOTHING, Decoration.NOTHING2),
CR_FLOOR7(15294, BuildHotspotType.LINKED, BuildingUtils.BUILD_MID_ANIM, Decoration.BOXING_MAT_CORNER, Decoration.FENCING_MAT_CORNER, Decoration.COMBAT_MAT_CORNER, Decoration.NOTHING, Decoration.NOTHING2),
CR_FLOOR8(15295, BuildHotspotType.LINKED, BuildingUtils.BUILD_MID_ANIM, Decoration.BOXING_MAT_CORNER, Decoration.FENCING_MAT_CORNER, Decoration.COMBAT_MAT_CORNER, Decoration.NOTHING, Decoration.RANGING_PEDESTALS),
/**
* Quest hall hotspots.
*/
Q_HALL_RUG(15387, BuildHotspotType.LINKED, BuildingUtils.BUILD_LOW_ANIM, Decoration.BROWN_RUG_CENTER, Decoration.RED_RUG_CENTER, Decoration.OPULENT_RUG_CENTER),
Q_HALL_RUG2(15388, BuildHotspotType.LINKED, BuildingUtils.BUILD_LOW_ANIM, Decoration.BROWN_RUG_END, Decoration.RED_RUG_END, Decoration.OPULENT_RUG_END),
Q_HALL_RUG3(15389, BuildHotspotType.LINKED, BuildingUtils.BUILD_LOW_ANIM, Decoration.BROWN_RUG_CORNER, Decoration.RED_RUG_CORNER, Decoration.OPULENT_RUG_CORNER),
/**
* Study hotspots.
*/
GLOBE(15421, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.GLOBE, Decoration.ORNAMENTAL_GLOBE, Decoration.LUNAR_GLOBE, Decoration.CELESTIAL_GLOBE, Decoration.ARMILLARY_SPHERE, Decoration.SMALL_ORREY, Decoration.LARGE_ORREY),
LECTERN(15420, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.OAK_LECTERN, Decoration.EAGLE_LECTERN, Decoration.DEMON_LECTERN, Decoration.TEAK_EAGLE_LECTERN, Decoration.TEAK_DEMON_LECTERN, Decoration.MAHOGANY_EAGLE_LECTERN, Decoration.MAHOGANY_DEMON_LECTERN),
CRYSTAL_BALL(15422, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.CRYSTAL_BALL, Decoration.ELEMENTAL_SPHERE, Decoration.CRYSTAL_OF_POWER),
BOOKCASE3(15425, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_HIGH_ANIM, Decoration.WOODEN_BOOKCASE, Decoration.OAK_BOOKCASE, Decoration.MAHOGANY_BOOKCASE),
WALL_CHART(15423, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_HIGH_ANIM, Decoration.ALCHEMICAL_CHART, Decoration.ASTRONOMICAL_CHART, Decoration.INFERNAL_CHART),
TELESCOPE(15424, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.TELESCOPE1, Decoration.TELESCOPE2, Decoration.TELESCOPE3),
/**
* Costume room hotspots.
*/
TREASURE_CHEST(18813, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.OAK_TREASURE_CHEST, Decoration.TEAK_TREASURE_CHEST, Decoration.MAHOGANY_TREASURE_CHEST),
ARMOUR_CASE(18815, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.OAK_ARMOUR_CASE, Decoration.TEAK_ARMOUR_CASE, Decoration.MGANY_ARMOUR_CASE),
MAGIC_WARDROBE(18811, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_HIGH_ANIM, Decoration.OAK_MAGIC_WARDROBE, Decoration.C_OAK_MAGIC_WARDROBE, Decoration.TEAK_MAGIC_WARDROBE, Decoration.C_TEAK_MAGIC_WARDROBE, Decoration.MGANY_MAGIC_WARDROBE, Decoration.GILDED_MAGIC_WARDROBE, Decoration.MARBLE_MAGIC_WARDROBE),
CAPE_RACK(18810, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.OAK_CAPE_RACK, Decoration.TEAK_CAPE_RACK, Decoration.MGANY_CAPE_RACK, Decoration.GILDED_CAPE_RACK, Decoration.MARBLE_CAPE_RACK, Decoration.MAGIC_CAPE_RACK),
TOY_BOX(18812, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.OAK_TOY_BOX, Decoration.TEAK_TOY_BOX, Decoration.MAHOGANY_TOY_BOX),
COSTUME_BOX(18814, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.OAK_COSTUME_BOX, Decoration.TEAK_COSTUME_BOX, Decoration.MAHOGANY_COSTUME_BOX),
/**
* Chapel hotspots.
*/
ALTAR(15270, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.OAK_ALTAR, Decoration.TEAK_ALTAR, Decoration.CLOTH_ALTAR, Decoration.MAHOGANY_ALTAR, Decoration.LIMESTONE_ALTAR, Decoration.MARBLE_ALTAR, Decoration.GILDED_ALTAR),
STATUE(15275, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.SMALL_STATUE, Decoration.MEDIUM_STATUE, Decoration.LARGE_STATUE),
MUSICAL(15276, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_HIGH_ANIM, Decoration.WINDCHIMES, Decoration.BELLS, Decoration.ORGAN),
ICON(15269, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.SARADOMIN_SYMBOL, Decoration.ZAMORAK_SYMBOL, Decoration.GUTHIX_SYMBOL, Decoration.SARADOMIN_ICON, Decoration.ZAMORAK_ICON, Decoration.GUTHIX_ICON, Decoration.ICON_OF_BOB),
BURNERS(15271, BuildHotspotType.RECURSIVE, BuildingUtils.BUILD_MID_ANIM, Decoration.STEEL_TORCHES, Decoration.WOODEN_TORCHES, Decoration.STEEL_CANDLESTICKS, Decoration.GOLD_CANDLESTICKS, Decoration.INCENSE_BURNERS, Decoration.MAHOGANY_BURNERS, Decoration.MARBLE_BURNERS),
CHAPEL_WINDOW(new int[] { 13730, 13728, 13732, 13729, 13733, 13731}, BuildHotspotType.RECURSIVE, BuildingUtils.BUILD_HIGH_ANIM, Decoration.SHUTTERED_WINDOW, Decoration.DECORATIVE_WINDOW, Decoration.STAINED_GLASS),
CHAPEL_RUG(15273, BuildHotspotType.LINKED, BuildingUtils.BUILD_LOW_ANIM, Decoration.BROWN_RUG_END, Decoration.RED_RUG_END, Decoration.OPULENT_RUG_END),
CHAPEL_RUG2(15274, BuildHotspotType.LINKED, BuildingUtils.BUILD_LOW_ANIM, Decoration.BROWN_RUG_CORNER, Decoration.RED_RUG_CORNER, Decoration.OPULENT_RUG_CORNER),
/**
* Formal garden hotspots.
*/
CENTREPIECE_2(15368, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.PORTAL, Decoration.GAZEBO, Decoration.DUNGEON_ENTRANCE, Decoration.SMALL_FOUNTAIN, Decoration.LARGE_FOUNTAIN, Decoration.POSH_FOUNTAIN),
FENCING(15369, BuildHotspotType.RECURSIVE, BuildingUtils.BUILD_HIGH_ANIM, Decoration.BOUNDARY_STONES, Decoration.WOODEN_FENCE, Decoration.STONE_WALL, Decoration.IRON_RAILINGS, Decoration.PICKET_FENCE, Decoration.GARDEN_FENCE, Decoration.MARBLE_WALL),
SMALL_PLANT1(15375, BuildHotspotType.INDIVIDUAL, BuildingUtils.PLANT_ANIM, Decoration.SUNFLOWER, Decoration.MARIGOLDS, Decoration.ROSES),
BIG_PLANT1(15373, BuildHotspotType.INDIVIDUAL, BuildingUtils.PLANT_ANIM, Decoration.SUNFLOWER_BIG, Decoration.MARIGOLDS_BIG, Decoration.ROSES_BIG),
SMALL_PLANT2(15376, BuildHotspotType.INDIVIDUAL, BuildingUtils.PLANT_ANIM, Decoration.ROSEMARY, Decoration.DAFFODILS, Decoration.BLUEBELLS),
BIG_PLANT2(15374, BuildHotspotType.INDIVIDUAL, BuildingUtils.PLANT_ANIM, Decoration.ROSEMARY_BIG, Decoration.DAFFODILS_BIG, Decoration.BLUEBELLS_BIG),
HEDGE1(15370, BuildHotspotType.LINKED, BuildingUtils.PLANT_ANIM, Decoration.THORNY_HEDGE1, Decoration.NICE_HEDGE1, Decoration.SMALL_BOX_HEDGE1, Decoration.TOPIARY_HEDGE1, Decoration.FANCY_HEDGE1, Decoration.TALL_FANCY_HEDGE1, Decoration.TALL_BOX_HEDGE1),
HEDGE2(15371, BuildHotspotType.LINKED, BuildingUtils.PLANT_ANIM, Decoration.THORNY_HEDGE2, Decoration.NICE_HEDGE2, Decoration.SMALL_BOX_HEDGE2, Decoration.TOPIARY_HEDGE2, Decoration.FANCY_HEDGE2, Decoration.TALL_FANCY_HEDGE2, Decoration.TALL_BOX_HEDGE2),
HEDGE3(15372, BuildHotspotType.LINKED, BuildingUtils.PLANT_ANIM, Decoration.THORNY_HEDGE3, Decoration.NICE_HEDGE3, Decoration.SMALL_BOX_HEDGE3, Decoration.TOPIARY_HEDGE3, Decoration.FANCY_HEDGE3, Decoration.TALL_FANCY_HEDGE3, Decoration.TALL_BOX_HEDGE3),
/**
* Throne room hotspots.
*/
THRONE(15426, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.OAK_THRONE, Decoration.TEAK_THRONE, Decoration.MAHOGANY_THRONE, Decoration.GILDED_THRONE, Decoration.SKELETON_THRONE, Decoration.CRYSTAL_THRONE, Decoration.DEMONIC_THRONE),
LEVER(15435, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.OAK_LEVER, Decoration.TEAK_LEVER, Decoration.MAHOGANY_LEVER),
FLOOR(new int[] { 15427, 15428, 15429, 15430, 15431, 15432 }, BuildHotspotType.RECURSIVE, BuildingUtils.BUILD_LOW_ANIM, Decoration.FLOOR_DECORATION, Decoration.STEEL_CAGE, Decoration.FLOOR_TRAP, Decoration.MAGIC_CIRCLE, Decoration.MAGIC_CAGE),
SEATING1(15436, BuildHotspotType.RECURSIVE, BuildingUtils.BUILD_MID_ANIM, Decoration.CARVED_TEAK_BENCH, Decoration.MAHOGANY_BENCH, Decoration.GILDED_BENCH),
SEATING2(15437, BuildHotspotType.RECURSIVE, BuildingUtils.BUILD_MID_ANIM, Decoration.CARVED_TEAK_BENCH, Decoration.MAHOGANY_BENCH, Decoration.GILDED_BENCH),
TRAPDOOR(15438, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_LOW_ANIM, Decoration.OAK_TRAPDOOR, Decoration.TEAK_TRAPDOOR, Decoration.MAHOGANY_TRAPDOOR),
DECORATION(15434, BuildHotspotType.CREST, BuildingUtils.BUILD_HIGH_ANIM, Decoration.OAK_DECO, Decoration.TEAK_DECO, Decoration.GILDED_DECO, Decoration.ROUND_SHIELD, Decoration.SQUARE_SHIELD, Decoration.KITE_SHIELD),
/**
* Oubliette hotspots.
*/
FLOOR_MID(15347, BuildHotspotType.LINKED, BuildingUtils.BUILD_LOW_ANIM, Decoration.SPIKES_MID, Decoration.TENTACLE_MID, Decoration.FP_FLOOR_MID, Decoration.ROCNAR_FLOOR_MID),
FLOOR_SIDE(15348, BuildHotspotType.LINKED, BuildingUtils.BUILD_LOW_ANIM, Decoration.SPIKES_SIDE, Decoration.TENTACLE_SIDE, Decoration.FP_FLOOR_SIDE, Decoration.ROCNAR_FLOOR_SIDE),
FLOOR_CORNER(15349, BuildHotspotType.LINKED, BuildingUtils.BUILD_LOW_ANIM, Decoration.SPIKES_CORNER, Decoration.TENTACLE_CORNER, Decoration.FP_FLOOR_CORNER, Decoration.ROCNAR_FLOOR_CORNER),
OUBLIETTE_FLOOR(15350, BuildHotspotType.LINKED, BuildingUtils.BUILD_LOW_ANIM, Decoration.SPIKES_FL, Decoration.TENTACLE_FL, Decoration.FLAME_PIT, Decoration.ROCNAR_FL),
OUBLIETTE_FLOOR_1(15351, BuildHotspotType.LINKED, BuildingUtils.BUILD_LOW_ANIM, Decoration.SPIKES_FL, Decoration.TENTACLE_FL, Decoration.FLAME_PIT, Decoration.ROCNAR),
PRISON(15352, BuildHotspotType.LINKED, BuildingUtils.BUILD_HIGH_ANIM, Decoration.OAK_CAGE, Decoration.OAK_STEEL_CAGE, Decoration.STEEL_CAGE_OU, Decoration.SPIKED_CAGE, Decoration.BONE_CAGE),
PRISON_DOOR(15353, BuildHotspotType.LINKED, BuildingUtils.BUILD_HIGH_ANIM, Decoration.OAK_CAGE_DOOR, Decoration.OAK_STEEL_CAGE_DOOR, Decoration.STEEL_CAGE_DOOR, Decoration.SPIKED_CAGE_DOOR, Decoration.BONE_CAGE_DOOR),
GUARD(15354, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.SKELETON_GUARD, Decoration.GUARD_DOG, Decoration.HOBGOBLIN, Decoration.BABY_RED_DRAGON, Decoration.HUGE_SPIDER, Decoration.TROLL, Decoration.HELLHOUND),
LADDER(15356, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_HIGH_ANIM, Decoration.OAK_LADDER, Decoration.TEAK_LADDER, Decoration.MAHOGANY_LADDER),
OUBLIETTE_LIGHT(15355, BuildHotspotType.RECURSIVE, BuildingUtils.BUILD_HIGH_ANIM, Decoration.CANDLE, Decoration.TORCH, Decoration.SKULL_TORCH),
/**
* Corridor, junction, stairs, TODO: pit trap
*/
DUNGEON_DOOR_LEFT(15328, BuildHotspotType.LINKED, BuildingUtils.BUILD_HIGH_ANIM, Decoration.OAK_DOOR_LEFT, Decoration.STEEL_DOOR_LEFT, Decoration.MARBLE_DOOR_LEFT),
DUNGEON_DOOR_RIGHT(15329, BuildHotspotType.LINKED, BuildingUtils.BUILD_HIGH_ANIM, Decoration.OAK_DOOR_RIGHT, Decoration.STEEL_DOOR_RIGHT, Decoration.MARBLE_DOOR_RIGHT),
DUNGEON_DOOR_LEFT2(15326, BuildHotspotType.LINKED, BuildingUtils.BUILD_HIGH_ANIM, Decoration.OAK_DOOR_LEFT, Decoration.STEEL_DOOR_LEFT, Decoration.MARBLE_DOOR_LEFT),
DUNGEON_DOOR_RIGHT2(15327, BuildHotspotType.LINKED, BuildingUtils.BUILD_HIGH_ANIM, Decoration.OAK_DOOR_RIGHT, Decoration.STEEL_DOOR_RIGHT, Decoration.MARBLE_DOOR_RIGHT),
DUNGEON_DOOR_LEFT3(36672, BuildHotspotType.LINKED, BuildingUtils.BUILD_HIGH_ANIM, Decoration.OAK_DOOR_LEFT, Decoration.STEEL_DOOR_LEFT, Decoration.MARBLE_DOOR_LEFT),
DUNGEON_DOOR_RIGHT3(36675, BuildHotspotType.LINKED, BuildingUtils.BUILD_HIGH_ANIM, Decoration.OAK_DOOR_RIGHT, Decoration.STEEL_DOOR_RIGHT, Decoration.MARBLE_DOOR_RIGHT),
DUNGEON_TRAP(15324, BuildHotspotType.RECURSIVE, BuildingUtils.BUILD_LOW_ANIM, Decoration.SPIKE_TRAP, Decoration.MAN_TRAP, Decoration.TANGLE_TRAP, Decoration.MARBLE_TRAP, Decoration.TELEPORT_TRAP),
DUNGEON_TRAP2(15325, BuildHotspotType.RECURSIVE, BuildingUtils.BUILD_LOW_ANIM, Decoration.SPIKE_TRAP, Decoration.MAN_TRAP, Decoration.TANGLE_TRAP, Decoration.MARBLE_TRAP, Decoration.TELEPORT_TRAP),
DUNGEON_LIGHT(15330, BuildHotspotType.RECURSIVE, BuildingUtils.BUILD_HIGH_ANIM, Decoration.CANDLE, Decoration.TORCH, Decoration.SKULL_TORCH),
DUNGEON_DECO(15331, BuildHotspotType.RECURSIVE, BuildingUtils.BUILD_HIGH_ANIM, Decoration.DECORATIVE_BLOOD, Decoration.DECORATIVE_PIPE, Decoration.HANGING_SKELETON),
DUNGEON_GUARD(15323, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.SKELETON_GUARD, Decoration.GUARD_DOG, Decoration.HOBGOBLIN, Decoration.BABY_RED_DRAGON, Decoration.HUGE_SPIDER, Decoration.TROLL, Decoration.HELLHOUND),
DUNGEON_GUARD2(15336, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.SKELETON_GUARD, Decoration.GUARD_DOG, Decoration.HOBGOBLIN, Decoration.BABY_RED_DRAGON, Decoration.HUGE_SPIDER, Decoration.TROLL, Decoration.HELLHOUND),
DUNGEON_GUARD3(15337, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.SKELETON_GUARD, Decoration.GUARD_DOG, Decoration.HOBGOBLIN, Decoration.BABY_RED_DRAGON, Decoration.HUGE_SPIDER, Decoration.TROLL, Decoration.HELLHOUND),
DUNGEON_LIGHT2(34138, BuildHotspotType.RECURSIVE, BuildingUtils.BUILD_HIGH_ANIM, Decoration.CANDLE, Decoration.TORCH, Decoration.SKULL_TORCH),
DUNGEON_PIT_GUARD(36676, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_HIGH_ANIM, Decoration.PIT_DOG, Decoration.PIT_OGRE, Decoration.PIT_ROCK_PROTECTOR, Decoration.PIT_SCABARITE, Decoration.PIT_BLACK_DEMON, Decoration.PIT_IRON_DRAGON),
/**
* Treasure room
*/
MONSTER(15257, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.DEMON, Decoration.KALPHITE_SOLDIER, Decoration.TOK_XIL, Decoration.DAGANNOTH, Decoration.STEEL_DRAGON),
TREASURE_CHEST1(15256, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.WOODEN_CRATE, Decoration.OAK_T_CHEST, Decoration.TEAK_T_CHEST, Decoration.MGANY_T_CHEST, Decoration.MAGIC_CHEST),
WALL_DECORATION1(15259, BuildHotspotType.CREST, BuildingUtils.BUILD_HIGH_ANIM, Decoration.ROUND_SHIELD, Decoration.SQUARE_SHIELD, Decoration.KITE_SHIELD),
/**
* Stairways.
*/
STAIRWAYS(15380, BuildHotspotType.STAIRCASE, BuildingUtils.BUILD_HIGH_ANIM, Decoration.OAK_STAIRCASE, Decoration.TEAK_STAIRCASE, Decoration.SPIRAL_STAIRCASE, Decoration.MARBLE_STAIRCASE, Decoration.MARBLE_SPIRAL),
QUEST_STAIRWAYS(15390, BuildHotspotType.STAIRCASE, BuildingUtils.BUILD_HIGH_ANIM, Decoration.OAK_STAIRCASE, Decoration.TEAK_STAIRCASE, Decoration.SPIRAL_STAIRCASE, Decoration.MARBLE_STAIRCASE, Decoration.MARBLE_SPIRAL),
STAIRWAYS_DUNGEON(new int[] { 15380, 15380, 15380, 15380, 15390, 15390}, BuildHotspotType.STAIRCASE, BuildingUtils.BUILD_HIGH_ANIM, Decoration.OAK_STAIRCASE, Decoration.TEAK_STAIRCASE, Decoration.SPIRAL_STAIRCASE, Decoration.MARBLE_STAIRCASE, Decoration.MARBLE_SPIRAL),
/**
* Stairways.
*/
STAIRS_DOWN(15381, BuildHotspotType.STAIRCASE, BuildingUtils.BUILD_LOW_ANIM, Decoration.OAK_STAIRS_DOWN, Decoration.TEAK_STAIRS_DOWN, Decoration.SPIRAL_STAIRS_DOWN, Decoration.MARBLE_STAIRS_DOWN, Decoration.MARBLE_SPIRAL_DOWN),
STAIRS_DOWN2(15391, BuildHotspotType.STAIRCASE, BuildingUtils.BUILD_LOW_ANIM, Decoration.OAK_STAIRS_DOWN, Decoration.TEAK_STAIRS_DOWN, Decoration.SPIRAL_STAIRS_DOWN, Decoration.MARBLE_STAIRS_DOWN, Decoration.MARBLE_SPIRAL_DOWN),
/**
* Window hotspots.
*/
WINDOW(13830, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_HIGH_ANIM, Decoration.BASIC_WOOD_WINDOW, Decoration.BASIC_STONE_WINDOW, Decoration.WHITEWASHED_STONE_WINDOW, Decoration.FREMENNIK_WINDOW, Decoration.TROPICAL_WOOD_WINDOW, Decoration.FANCY_STONE_WINDOW),
;
/**
* The object id.
*/
private final int objectId;
/**
* The object ids.
*/
private final int[] objectIds;
/**
* The decorations to build on this hotspot.
*/
private final Decoration[] decorations;
/**
* The hotspot type.
*/
private final BuildHotspotType type;
/**
* The building animation.
*/
private final Animation buildingAnimation;
/**
* The linked hotspots
*/
private static final List<BuildHotspot[]> linkedHotspots = new ArrayList<BuildHotspot[]>();
/**
* Configures hotspots.
*/
static {
linkedHotspots.add(new BuildHotspot[] { RUG, RUG2, RUG3 });
linkedHotspots.add(new BuildHotspot[] { BEDROOM_RUG, BEDROOM_RUG2, BEDROOM_RUG3 });
linkedHotspots.add(new BuildHotspot[] { HALL_RUG, HALL_RUG2, HALL_RUG3 });
linkedHotspots.add(new BuildHotspot[] { CR_CORNER, CR_CORNER2, CR_CORNER3, CR_CORNER4, CR_RING,
CR_RING2, CR_RING3, CR_RING4, CR_FLOOR, CR_FLOOR2, CR_FLOOR3, CR_FLOOR4, CR_FLOOR5,
CR_FLOOR6, CR_FLOOR7, CR_FLOOR8, CR_INVISIBLE_WALL, CR_INVISIBLE_WALL2, CR_INVISIBLE_WALL3});
linkedHotspots.add(new BuildHotspot[] { Q_HALL_RUG, Q_HALL_RUG2, Q_HALL_RUG3 });
linkedHotspots.add(new BuildHotspot[] { CHAPEL_RUG, CHAPEL_RUG2 });
linkedHotspots.add(new BuildHotspot[] { HEDGE1, HEDGE2, HEDGE3 });
linkedHotspots.add(new BuildHotspot[] { FLOOR_MID, FLOOR_SIDE, FLOOR_CORNER, OUBLIETTE_FLOOR, OUBLIETTE_FLOOR_1 });
linkedHotspots.add(new BuildHotspot[] { PRISON, PRISON_DOOR });
linkedHotspots.add(new BuildHotspot[] { DUNGEON_DOOR_LEFT, DUNGEON_DOOR_RIGHT });
linkedHotspots.add(new BuildHotspot[] { DUNGEON_DOOR_LEFT2, DUNGEON_DOOR_RIGHT2 });
linkedHotspots.add(new BuildHotspot[] { HABITAT_1, HABITAT_2 });
linkedHotspots.add(new BuildHotspot[] { SMALL_PLANT_1, SMALL_PLANT1 });
}
/**
* Constructs a new {@code BuildHotspot} {@code Object}.
* @param objectId The object id.
* @param buildingAnimation The building animation.
* @param decorations The decoration.
*/
private BuildHotspot(int objectId, BuildHotspotType type, Animation buildingAnimation, Decoration... decorations) {
this.objectId = objectId;
this.objectIds = null;
this.type = type;
this.buildingAnimation = buildingAnimation;
this.decorations = decorations;
}
/**
* Constructs a new {@code BuildHotspot} {@code Object}.
* @param objectIds The objects ids.
* @param buildingAnimation The building animation.
* @param decorations The decoration.
*/
private BuildHotspot(int[] objectIds, BuildHotspotType type, Animation buildingAnimation, Decoration... decorations) {
this.objectId = objectIds[0];
this.objectIds = objectIds;
this.type = type;
this.buildingAnimation = buildingAnimation;
this.decorations = decorations;
}
/**
* Gets the building hotspot for the given object id.
* @param id The object id.
* @param style The housing style.
* @return The building hotspot.
*/
public static BuildHotspot forId(int id, HousingStyle style) {
for (BuildHotspot spot : values()) {
if (spot.getObjectId(style) == id) {
return spot;
}
}
return null;
}
/**
* Gets the linked hotspots (if any)
* @param b - the buildhotspot to find linked hotspots
* @return BuildHotspot[] or null
*/
public static BuildHotspot[] getLinkedHotspots(BuildHotspot b) {
for (BuildHotspot[] list : linkedHotspots) {
for (BuildHotspot bh : list) {
if (bh == b) {
return list;
}
}
}
return null;
}
/**
* Gets the decoration index.
* @param deco The decoration.
* @return The index.
*/
public int getDecorationIndex(Decoration deco) {
for (int i = 0; i < decorations.length; i++) {
if (decorations[i] == deco) {
return i;
}
}
return -1;
}
/**
* Gets the objectId.
* @param style The current housing style.
* @return The objectId.
*/
public int getObjectId(HousingStyle style) {
if (objectIds != null) {
return objectIds[style.ordinal()];
}
return objectId;
}
/**
* Gets the objectId.
* @return The objectId.
*/
public int getObjectId() {
return objectId;
}
/**
* Gets the type
* @return type
*/
public BuildHotspotType getType() {
return type;
}
/**
* Gets the decorations.
* @return The decorations.
*/
public Decoration[] getDecorations() {
return decorations;
}
/**
* Gets the objectIds value.
* @return The objectIds.
*/
public int[] getObjectIds() {
return objectIds;
}
/**
* Gets the buildingAnimation value.
* @return The buildingAnimation.
*/
public Animation getBuildingAnimation() {
return buildingAnimation;
}
}
@@ -0,0 +1,20 @@
package content.global.skill.construction;
/**
* BuiltHotspotType
* @author Clayton Williams
* @date Jul 26, 2015
*/
public enum BuildHotspotType {
INDIVIDUAL,
RECURSIVE,
LINKED,
CREST,
STAIRCASE;
BuildHotspotType() {
}
}
@@ -0,0 +1,181 @@
package content.global.skill.construction;
import core.cache.def.impl.SceneryDefinition;
import core.game.component.Component;
import core.game.dialogue.DialogueInterpreter;
import core.game.dialogue.DialoguePlugin;
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.plugin.Initializable;
import core.plugin.Plugin;
import core.tools.SystemLogger;
import core.plugin.ClassScanner;
/**
* The build option handling plugin.
* @author Emperor
*
*/
@Initializable
public final class BuildOptionPlugin extends OptionHandler {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
SceneryDefinition.setOptionHandler("build", this);
SceneryDefinition.setOptionHandler("remove", this);
ClassScanner.definePlugin(new RemoveDialogue());
return this;
}
@Override
public boolean handle(Player player, Node node, String option) {
if (!player.getHouseManager().isBuildingMode()) {
player.getPacketDispatch().sendMessage("You have to be in building mode to do this.");
return true;
}
Scenery object = ((Scenery) node);
if (option.equals("remove")) {
Decoration decoration = Decoration.getDecoration(player, object);
if (decoration == null || !object.isActive()) {
return false;
}
player.getDialogueInterpreter().open("con:removedec", object);
return true;
}
player.setAttribute("con:hsobject", node);
if (BuildingUtils.isDoorHotspot(object)) {
int[] pos = BuildingUtils.roomExists(player, object);
if (pos != null) {
player.getDialogueInterpreter().open("con:remove", "room", pos);
return true;
}
if (player.getHouseManager().getRoomAmount() < player.getHouseManager().getMaximumRooms(player)) {
player.getInterfaceManager().open(new Component(402));
} else {
player.getPacketDispatch().sendMessage("You currently have the maximum amount of rooms available.");
}
return true;
}
Hotspot hotspot = player.getHouseManager().getHotspot(object);
if (hotspot == null || !isBuildable(player, object, hotspot)) {
System.out.println(hotspot == null);
SystemLogger.logErr(this.getClass(), "Construction (building): " + hotspot + " : " + object + " chunkX = " + object.getLocation().getChunkX() + ", chunkY = " + object.getLocation().getChunkY());
return true;
}
player.setAttribute("con:hotspot", hotspot);
BuildingUtils.openBuildInterface(player, hotspot.getHotspot());
return true;
}
/**
* Checks if the hotspot can be used.
* @param player The player.
* @param hotspot The hotspot.
* @return {@code True} if so.
*/
private static boolean isBuildable(Player player, Scenery object, Hotspot hotspot) {
Room room = player.getHouseManager().getRoom(object.getLocation());
if (room == null) {
return false;
}
switch (hotspot.getHotspot()) {
case STAIRWAYS:
case STAIRS_DOWN:
case STAIRWAYS_DUNGEON:
if (room.isBuilt(BuildHotspot.HALL_RUG)) {
player.getPacketDispatch().sendMessage("You can't build a staircase on a rug.");
return false;
}
return true;
case HALL_RUG:
case HALL_RUG2:
case HALL_RUG3:
if (room.isBuilt(BuildHotspot.STAIRWAYS) || room.isBuilt(BuildHotspot.STAIRS_DOWN) || room.isBuilt(BuildHotspot.STAIRWAYS_DUNGEON)) {
player.getPacketDispatch().sendMessage("You can't build a rug under a staircase.");
return false;
}
return true;
case QUEST_STAIRWAYS:
case STAIRS_DOWN2:
if (room.isBuilt(BuildHotspot.Q_HALL_RUG)) {
player.getPacketDispatch().sendMessage("You can't build a staircase on a rug.");
return false;
}
return true;
case Q_HALL_RUG:
case Q_HALL_RUG2:
case Q_HALL_RUG3:
if (room.isBuilt(BuildHotspot.QUEST_STAIRWAYS) || room.isBuilt(BuildHotspot.STAIRS_DOWN2)) {
player.getPacketDispatch().sendMessage("You can't build a rug under a staircase.");
return false;
}
return true;
default:
return true;
}
}
/**
* Handles the removing a decoration dialogue.
* @author Emperor
*
*/
private static class RemoveDialogue extends DialoguePlugin {
/**
* The object.
*/
private Scenery object;
/**
* Constructs a new {@code RemoveDialogue} {@code Object}.
*/
public RemoveDialogue() {
super();
}
/**
* Constructs a new {@code RemoveDialogue} {@code Object}.
* @param player The player.
*/
public RemoveDialogue(Player player) {
super(player);
}
@Override
public DialoguePlugin newInstance(Player player) {
return new RemoveDialogue(player);
}
@Override
public boolean open(Object... args) {
interpreter.sendOptions("Really remove it?", "Yes", "No");
object = (Scenery) args[0];
return true;
}
@Override
public boolean handle(int interfaceId, int buttonId) {
switch (buttonId) {
case 1:
BuildingUtils.removeDecoration(player, object);
break;
}
end();
return true;
}
@Override
public int[] getIds() {
return new int[] { DialogueInterpreter.getDialogueKey("con:removedec") };
}
}
}
@@ -0,0 +1,263 @@
package content.global.skill.construction;
import core.game.node.entity.player.Player;
import core.game.node.item.Item;
import core.game.node.scenery.Scenery;
import core.game.node.scenery.SceneryBuilder;
import core.game.world.map.Direction;
import core.game.world.map.Location;
import core.game.world.map.RegionChunk;
import core.plugin.Initializable;
import core.game.dialogue.DialogueInterpreter;
import core.game.dialogue.DialoguePlugin;
import core.game.node.entity.skill.Skills;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
/**
* Handles the building a room dialogue.
* @author Emperor
*
*/
@Initializable
public final class BuildRoomDialogue extends DialoguePlugin {
/**
* The door hotspot.
*/
private Scenery door;
/**
* The direction.
*/
private Direction[] directions;
/**
* The room exits.
*/
private boolean[] exits;
/**
* The rotation index.
*/
private int index;
/**
* The boundaries of the room to build.
*/
private List<Scenery> boundaries = new ArrayList<>(20);
/**
* The room we're building.
*/
private Room room;
/**
* The room x-coordinate.
*/
private int roomX;
/**
* The room y-coordinate.
*/
private int roomY;
/**
* The room z-coordinate (3 for dungeon).
*/
private int roomZ;
/**
* Constructs a new {@code BuildRoomDialogue} {@code Object}
*/
public BuildRoomDialogue() {
super();
}
/**
* Constructs a new {@code BuildRoomDialogue} {@code Object}
* @param player The player.
*/
public BuildRoomDialogue(Player player) {
super(player);
}
@Override
public DialoguePlugin newInstance(Player player) {
return new BuildRoomDialogue(player);
}
@Override
public boolean open(Object... args) {
player.getInterfaceManager().close();
RoomProperties props = (RoomProperties) args[0];
if (player.getSkills().getStaticLevel(Skills.CONSTRUCTION) < props.getLevel()) {
interpreter.sendPlainMessage(false, "You need a Construction level of " + props.getLevel() + " to buy this room.");
stage = 2;
return true;
}
if (!player.getInventory().contains(995, props.getCost())) {
interpreter.sendPlainMessage(false, "You need " + props.getCost() + " coins to buy this room.");
stage = 2;
return true;
}
this.door = (Scenery) player.getAttribute("con:hsobject");
int[] pos = BuildingUtils.getRoomPosition(player, door);
roomX = pos[0];
roomY = pos[1];
if (!inBounds()) {
interpreter.sendPlainMessage(false, "Your house is too large. TODO: correct message");
stage = 2;
return true;
}
roomZ = player.getLocation().getZ();
if (roomZ != 0) {
Room r = player.getHouseManager().getRooms()[roomZ - 1][roomX][roomY];
if (r == null || r.getProperties().isLand()) {
interpreter.sendPlainMessage(false, "You can't build a room here, you need a room to build on.");
stage = 2;
return true;
}
}
if (HouseManager.isInDungeon(player)) {
if (props.isLand()) {
interpreter.sendPlainMessage(false, "You can't build this room inside your dungeon.");
stage = 2;
return true;
}
roomZ = 3;
}
else if (props.isDungeon()) {
interpreter.sendPlainMessage(false, "You can only build this room in your dungeon.");
stage = 2;
return true;
}
if (props.isLand() && roomZ != 0) {
interpreter.sendPlainMessage(false, "A garden can only be on ground floor.");
stage = 2;
return true;
}
this.room = Room.create(player, props);
this.exits = room.getExits(Direction.NORTH);
this.index = 0;
this.directions = BuildingUtils.getAvailableRotations(player, exits, roomZ, roomX, roomY);
while (directions[index] == null) {
if (++index == directions.length) {
interpreter.sendPlainMessage(false, "There's no space to build this room.");
stage = 2;
return true;
}
}
options("Rotate clockwise", "Rotate anticlockwise", "Build", "Cancel");
stage = 1;
drawGhostRoom();
return true;
}
/**
* Checks if the room to be built is in the available boundaries of the house.
* @return The boundaries.
*/
private boolean inBounds() {
Rectangle bounds = player.getHouseManager().getBoundaries();
int max = player.getHouseManager().getMaximumDimension(player);
if ((roomX < bounds.x || roomX >= bounds.x + bounds.width) && bounds.width >= max) {
return false;
}
if ((roomY < bounds.y || roomY >= bounds.y + bounds.height) && bounds.height >= max) {
return false;
}
return true;
}
@Override
public boolean close() {
for (Scenery object : boundaries) {
SceneryBuilder.remove(object);
}
boundaries.clear();
return super.close();
}
@Override
public boolean handle(int interfaceId, int buttonId) {
switch (stage) {
case 1:
switch (buttonId) {
case 1:
case 2:
rotate(buttonId == 2);
options("Rotate clockwise", "Rotate anticlockwise", "Build", "Cancel");
return true;
case 3:
if (player.getInventory().remove(new Item(995, room.getProperties().getCost()))) {
room.setRotation(directions[index]);
boolean[] exit = new boolean[exits.length];
for (int i = 0; i < exit.length; i++) {
exit[(i + index) % exit.length] = exits[i];
}
BuildingUtils.buildRoom(player, room, roomZ, roomX, roomY, exit, true);
end();
return true;
}
interpreter.sendPlainMessage(false, "You need " + room.getProperties().getCost() + " coins to buy this room.");
stage = 2;
return true;
case 4:
end();
return true;
}
break;
case 2:
end();
return true;
}
return false;
}
/**
* Rotates the room.
* @param counter If we're rotating counter clockwise.
*/
private void rotate(boolean counter) {
Direction direction = null;
while ((direction = directions[index = (index + (counter ? 3 : 1)) % 4]) == null) {
}
room.setRotation(direction);
drawGhostRoom();
}
/**
* Draws the current boundaries of the room to build.
*/
private void drawGhostRoom() {
for (Scenery object : boundaries) {
SceneryBuilder.remove(object);
}
int rotation = directions[index].toInteger();
boundaries.clear();
Location base = player.getViewport().getRegion().getBaseLocation().transform(roomX << 3, roomY << 3, player.getLocation().getZ());
for (int x = 0; x < 8; x++) {
for (int y = 0; y < 8; y++) {
Scenery[] objects = room.getChunk().getObjects(x, y);
for (Scenery object : objects) {
if (object != null && object.getDefinition().hasAction("build")) {
int[] pos = RegionChunk.getRotatedPosition(x, y, object.getDefinition().getSizeX(), object.getDefinition().getSizeY(), object.getRotation(), rotation);
Scenery obj = object.transform(object.getId(), (object.getRotation() + rotation) % 4, base.transform(pos[0], pos[1], 0));
boundaries.add(SceneryBuilder.add(obj));
}
}
}
}
}
@Override
public int[] getIds() {
return new int[] { DialogueInterpreter.getDialogueKey("con:room") };
}
}
@@ -0,0 +1,700 @@
package content.global.skill.construction;
import core.cache.def.impl.ItemDefinition;
import core.game.component.Component;
import core.game.node.entity.player.Player;
import core.game.node.entity.skill.Skills;
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.map.BuildRegionChunk;
import core.game.world.map.Direction;
import core.game.world.map.Location;
import core.game.world.map.Region;
import core.game.world.update.flag.context.Animation;
import core.net.packet.PacketRepository;
import core.net.packet.context.ContainerContext;
import core.net.packet.out.ContainerPacket;
import org.jetbrains.annotations.NotNull;
import core.tools.SystemLogger;
import java.util.ArrayList;
import java.util.Arrays;
/**
* Utility class for building.
* @author Emperor
*
*/
public final class BuildingUtils {
/**
* The directions array.
*/
public static final Direction[] DIRECTIONS = {
Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST
};
/**
* The building a decoration animation.
*/
public static final Animation BUILD_LOW_ANIM = Animation.create(3683);
/**
* The building a decoration animation.
*/
public static final Animation BUILD_MID_ANIM = Animation.create(3676);
/**
* The building a decoration animation.
*/
public static final Animation BUILD_HIGH_ANIM = Animation.create(3684);
/**
* The planting animation.
*/
public static final Animation PLANT_ANIM = Animation.create(3691);
/**
* The removing a decoration animation.
*/
private static final Animation REMOVE_ANIMATION = Animation.create(3685);
/**
* The plank item.
*/
public static final Item PLANK = new Item(960);
/**
* The watering can(8) item id.
*/
public static final int WATERING_CAN = 5340;
private static final int[] BUILD_INDEXES = { 0, 2, 4, 6, 1, 3, 5 };
/**
* Opens the building furniture interface.
* @param player The player.
* @param hotspot The hotspot.
*/
public static void openBuildInterface(Player player, BuildHotspot hotspot) {
player.getInterfaceManager().open(new Component(396));
Item[] items = new Item[7];
int c261Value = 0;
for (int menuIndex = 0; menuIndex < 7; menuIndex++) {
int itemsStringOffset = 97 + (menuIndex * 5);
//97 +
if (menuIndex >= hotspot.getDecorations().length || (hotspot.getDecorations()[menuIndex] != null && hotspot.getDecorations()[menuIndex].isInvisibleNode())) {
for (int j = 0; j < 5; j++) {
player.getPacketDispatch().sendString("", 396, itemsStringOffset + j);
}
player.getPacketDispatch().sendString("", 396, 140 + menuIndex);
c261Value += (1 << (menuIndex + 1));
continue;
}
Decoration decoration = hotspot.getDecorations()[menuIndex];
items[BUILD_INDEXES[menuIndex]] = new Item(decoration.getInterfaceItem());
player.getPacketDispatch().sendString(ItemDefinition.forId(decoration.getInterfaceItem()).getName(), 396, itemsStringOffset);
boolean hasRequirements = player.getSkills().getLevel(Skills.CONSTRUCTION) >= decoration.getLevel();
for (int j = 0; j < 4; j++) {
if (j >= decoration.getItems().length) {
if (j == decoration.getItems().length && decoration.getNailAmount() > 0) {
player.getPacketDispatch().sendString("Nails: " + decoration.getNailAmount(), 396, (itemsStringOffset + 1) + j);
} else {
player.getPacketDispatch().sendString("", 396, (itemsStringOffset + 1) + j);
}
} else {
Item item = decoration.getItems()[j];
if (!player.getInventory().containsItem(item)) {
hasRequirements = false;
}
String s = item.getName() + ": " + item.getAmount();
/*if (j > 1 && (decoration == Decoration.RUNE_CASE1 || decoration == Decoration.RUNE_CASE2)) {
if (j == 3) {
offset--;
item = decoration.getItems()[++j];
s = item.getName() + ": " + item.getAmount();
}
item = decoration.getItems()[j + 1];
s += ", " + item.getName() + ": " + item.getAmount();
player.getPacketDispatch().sendString(s, 396, 15 + offset + j);
continue;
}*/
player.getPacketDispatch().sendString(s, 396, (itemsStringOffset + 1) + j);
}
}
if (hasRequirements) {
c261Value += (1 << (menuIndex + 1));
}
player.getConfigManager().set(1485 + menuIndex, hasRequirements || player.isStaff() ? 1 : 0);
player.getPacketDispatch().sendString("Level " + decoration.getLevel(), 396, 140 + menuIndex);
//player.getPacketDispatch().sendItemZoomOnInterface(items[i].protocol(), 50000, 396, 49 + i);
}
System.out.println(c261Value);
player.getConfigManager().set(261, c261Value);
PacketRepository.send(ContainerPacket.class, new ContainerContext(player, 396, 132, 8, items, false));
}
/**
* Checks if the object is a door hotspot.
* @param object The object.
* @return {@code True} if so.
*/
public static boolean isDoorHotspot(Scenery object) {
return object.getId() >= 15305 && object.getId() <= 15322;
}
/**
* Builds a decoration object.
* @param player The player.
* @param deco The decoration.
* @param object The object.
*/
public static void buildDecoration(final Player player, final Hotspot hotspot, final Decoration deco, final Scenery object) {
final int nailAmount = deco.getNailAmount();
final NailType type = nailAmount > 0 ? NailType.get(player, nailAmount) : null;
if (nailAmount > 0 && type == null) {
player.getPacketDispatch().sendMessage("You don't have the right materials.");
return;
}
int roomX = object.getLocation().getChunkX();
int roomY = object.getLocation().getChunkY();
int z = object.getLocation().getZ();
Region region = player.getHouseManager().getHouseRegion();
if (HouseManager.isInDungeon(player)) {
region = player.getHouseManager().getDungeonRegion();
z = 3;
}
final Room room = player.getHouseManager().getRooms()[z][roomX][roomY];
if (!canBuildDecoration(player, room, deco, object)) {
return;
}
player.lock(3);
player.animate(hotspot.getHotspot().getBuildingAnimation());
final Region r = region;
player.getPulseManager().run(new Pulse(3, player, object) {
int nails = nailAmount;
NailType nail = type;
@Override
public boolean pulse() {
if (nails > 0) {
if (!type.isBend()) {
player.getPacketDispatch().sendMessage("You use a nail.");
nails--;
} else {
player.getPacketDispatch().sendMessage("You accidently bend a nail.");
}
player.animate(hotspot.getHotspot().getBuildingAnimation());
if (!player.getInventory().remove(new Item(nail.getItemId(), 1))) {
return true;
}
if (nails > 0) {
player.lock(4);
return false;
}
} else if (deco.getTools()[0] == WATERING_CAN) {
for (int i = 7; i >= 0; i--) {
Item can = player.getInventory().getItem(new Item(WATERING_CAN - i, 1));
if (can != null && can.getSlot() > -1) {
System.out.println("Can index " + (i == 7 ? i + 2 : i + 1) + ".");
player.getInventory().replace(new Item(WATERING_CAN - (i == 7 ? i + 2 : i + 1), 1), can.getSlot());
break;
}
}
}
if (player.getInventory().remove(deco.getItems()) || player.isAdmin()) {
setDecoration(player, r, room, hotspot, object, deco);
player.getSkills().addExperience(Skills.CONSTRUCTION, deco.getExperience(), true);
if (getObjectIdsThatGiveFarmingExperience().contains(deco.getObjectId())) {
player.getSkills().addExperience(Skills.FARMING, deco.getExperience(), true);
}
player.unlock();
}
return true;
}
@NotNull
private ArrayList<Integer> getObjectIdsThatGiveFarmingExperience() {
return new ArrayList<>(
// Garden big tree decorations.
Arrays.asList(13411, 13412, 13413, 13414, 13415, 13416, 13417,
// Garden tree decorations.
13418, 13419, 13420, 13421, 13422, 13423, 13424,
// Garden big plant 1 decorations.
13425, 13426, 13427,
// Garden big plant 2 decorations.
13428, 13429, 13430,
// Garden small plant 1 decorations.
13431, 13432, 13433,
// Garden small plant 2 decorations.
13434, 13435, 13436));
}
});
}
/**
* Sets a decoration for the given hotspot.
* @param player The player.
* @param region The region.
* @param room The room.
* @param hotspot The hotspot to set the decoration for.
* @param object The object representing the hotspot.
* @param deco The decoration to set.
*/
private static void setDecoration(Player player, Region region, Room room, Hotspot hotspot, Scenery object, Decoration deco) {
Location l = object.getLocation();
HousingStyle style = player.getHouseManager().getStyle();
int decIndex = hotspot.getHotspot().getDecorationIndex(deco);
switch(hotspot.getHotspot().getType()) {
case STAIRCASE:
int z = l.getZ();
if (region == player.getHouseManager().getDungeonRegion()) {
z = 3;
}
for (int i = -1; i <= 1; i++) {
int plane = (z + (i == -1 ? 3 : i)) % 4;
Room r = player.getHouseManager().getRooms()[plane][l.getChunkX()][l.getChunkY()];
if (r != null && r.getRotation() == room.getRotation() && !r.getProperties().isLand()) {
Hotspot h = r.getStairs();
if (h != null) {
h.setDecorationIndex(decIndex);
Region reg = plane == 3 ? player.getHouseManager().getDungeonRegion() : player.getHouseManager().getHouseRegion();
if (reg == null) {
continue;
}
BuildRegionChunk chunk = (BuildRegionChunk) reg.getPlanes()[plane % 3].getChunks()[l.getChunkX()][l.getChunkY()];
Scenery[] objects = chunk.getObjects(h.getCurrentX(), h.getCurrentY());
for (Scenery o : objects) {
if (o != null && o.getType() == object.getType()) {
SceneryBuilder.replace(o, o.transform(h.getHotspot().getDecorations()[decIndex].getObjectId(style)));
if (plane == 1) {
if (r.getProperties() == RoomProperties.SKILL_HALL) {
r.updateProperties(player, RoomProperties.SKILL_HALL_2);
} else if (r.getProperties() == RoomProperties.QUEST_HALL) {
r.updateProperties(player, RoomProperties.QUEST_HALL_2);
}
else {
break;
}
player.getHouseManager().reload(player, true);
}
break;
}
}
} else {
SystemLogger.logErr(BuildingUtils.class, "Couldn't find stairs! " + plane);
}
}
}
break;
case CREST:
SceneryBuilder.replace(object, object.transform(deco.getObjectId(style) + player.getHouseManager().getCrest().ordinal()));
hotspot.setDecorationIndex(decIndex);
break;
case INDIVIDUAL:
SceneryBuilder.replace(object, object.transform(deco.getObjectId(style)));
hotspot.setDecorationIndex(decIndex);
break;
case RECURSIVE:
BuildRegionChunk chunk = (BuildRegionChunk) region.getPlanes()[l.getZ()].getChunks()[l.getChunkX()][l.getChunkY()];
for (int x = 0; x < 8; x++) {
for (int y = 0; y < 8; y++) {
Hotspot h = room.getHotspot(hotspot.getHotspot(), x, y);
if (h != null) {
h.setDecorationIndex(decIndex);
int objectId = hotspot.getHotspot().getObjectId(style);
Scenery o = chunk.get(x, y, chunk.getIndex(x, y, objectId));
if (o != null && objectId == o.getId()) {
SceneryBuilder.replace(o, o.transform(hotspot.getHotspot().getDecorations()[decIndex].getObjectId(style)));
}
}
}
}
break;
case LINKED:
BuildHotspot[] linkedHotspots = BuildHotspot.getLinkedHotspots(hotspot.getHotspot());
chunk = (BuildRegionChunk) region.getPlanes()[l.getZ()].getChunks()[l.getChunkX()][l.getChunkY()];
for (int x = 0; x < 8; x++) {
for (int y = 0; y < 8; y++) {
for (BuildHotspot bh : linkedHotspots) {
Hotspot h = room.getHotspot(bh, x, y);
if (h != null) {
h.setDecorationIndex(decIndex);
int objectId = bh.getObjectId(style);
Scenery o = chunk.get(x, y, chunk.getIndex(x, y, objectId));
if (o != null && objectId == o.getId()) {
SceneryBuilder.replace(o, o.transform(bh.getDecorations()[decIndex].getObjectId(style)));
}
}
}
}
}
break;
}
}
/**
* Remove the decoration
* @param player the player
* @param object the object to remove
*/
public static void removeDecoration(Player player, Scenery object) {
if (object.getId() == Decoration.PORTAL.getObjectId() && player.getHouseManager().getPortalAmount() <= 1) {
player.getPacketDispatch().sendMessage("You need atleast one portal, how else would you leave your house?");
return;
}
Location l = object.getLocation();
Room room = player.getHouseManager().getRooms()[l.getZ()][l.getChunkX()][l.getChunkY()];
Region region = player.getHouseManager().getHouseRegion();
if (HouseManager.isInDungeon(player)) {
region = player.getHouseManager().getDungeonRegion();
room = player.getHouseManager().getRooms()[3][l.getChunkX()][l.getChunkY()];
}
HousingStyle style = player.getHouseManager().getStyle();
for (int i = 0; i < room.getHotspots().length; i++) {
Hotspot hotspot = room.getHotspots()[i];
int objectId = hotspot.getDecorationIndex() < 0 ? -1 : hotspot.getHotspot().getDecorations()[hotspot.getDecorationIndex()].getObjectId(style);
if (hotspot.getHotspot().getType() == BuildHotspotType.CREST) {
objectId += player.getHouseManager().getCrest().ordinal();
}
if (objectId == object.getId() && hotspot.getCurrentX() == l.getChunkOffsetX() && hotspot.getCurrentY() == l.getChunkOffsetY()) {
player.animate(REMOVE_ANIMATION);
removeDecoration(player, region, room, hotspot, object, style);
break;
}
}
}
/**
* Removes the decoration.
* @param player The player.
* @param region The region.
* @param room The room.
* @param hotspot The hotspot to remove the decoration from.
* @param object The object.
* @param style The housing style.
*/
private static void removeDecoration(Player player, Region region, Room room, Hotspot hotspot, Scenery object, HousingStyle style) {
Location l = object.getLocation();
switch (hotspot.getHotspot().getType()) {
case STAIRCASE:
int z = l.getZ();
if (region == player.getHouseManager().getDungeonRegion()) {
z = 3;
}
for (int i = -1; i <= 1; i++) {
int plane = (z + (i == -1 ? 3 : i)) % 4;
Room r = player.getHouseManager().getRooms()[plane][l.getChunkX()][l.getChunkY()];
if (r != null && r.getRotation() == room.getRotation()) {
Hotspot h = r.getStairs();
if (h != null) {
h.setDecorationIndex(-1);
Region reg = plane == 3 ? player.getHouseManager().getDungeonRegion() : player.getHouseManager().getHouseRegion();
if (reg == null) {
continue;
}
BuildRegionChunk chunk = (BuildRegionChunk) reg.getPlanes()[plane % 3].getChunks()[l.getChunkX()][l.getChunkY()];
Scenery[] objects = chunk.getObjects(h.getCurrentX(), h.getCurrentY());
for (Scenery o : objects) {
if (o != null && o.getType() == object.getType()) {
SceneryBuilder.replace(o, o.transform(h.getHotspot().getObjectId(style)));
break;
}
}
} else {
SystemLogger.logErr(BuildingUtils.class, "Couldn't find stairs! " + plane);
}
}
}
if (l.getZ() == 1) {
if (room.getProperties() == RoomProperties.SKILL_HALL_2) {
room.updateProperties(player, RoomProperties.SKILL_HALL);
}
else if (room.getProperties() == RoomProperties.QUEST_HALL_2) {
room.updateProperties(player, RoomProperties.QUEST_HALL);
}
else {
break;
}
player.getHouseManager().reload(player, true);
}
break;
case INDIVIDUAL:
case CREST:
SceneryBuilder.replace(object, object.transform(hotspot.getHotspot().getObjectId(style)));
hotspot.setDecorationIndex(-1);
break;
case RECURSIVE:
BuildRegionChunk chunk = (BuildRegionChunk) region.getPlanes()[l.getZ()].getChunks()[l.getChunkX()][l.getChunkY()];
for (int x = 0; x < 8; x++) {
for (int y = 0; y < 8; y++) {
Hotspot h = room.getHotspot(hotspot.getHotspot(), x, y);
if (h != null) {
int objectId = hotspot.getHotspot().getDecorations()[h.getDecorationIndex()].getObjectId(style);
Scenery o = chunk.get(x, y, chunk.getIndex(x, y, objectId));
h.setDecorationIndex(-1);
if (o != null && objectId == o.getId()) {
SceneryBuilder.replace(o, o.transform(hotspot.getHotspot().getObjectId(style)));
}
}
}
}
break;
case LINKED:
BuildHotspot[] linkedHotspots = BuildHotspot.getLinkedHotspots(hotspot.getHotspot());
chunk = (BuildRegionChunk) region.getPlanes()[l.getZ()].getChunks()[l.getChunkX()][l.getChunkY()];
for (int x = 0; x < 8; x++) {
for (int y = 0; y < 8; y++) {
for (BuildHotspot bh : linkedHotspots) {
Hotspot h = room.getHotspot(bh, x, y);
if (h != null) {
int objectId = bh.getDecorations()[h.getDecorationIndex()].getObjectId(style);
Scenery o = chunk.get(x, y, chunk.getIndex(x, y, objectId));
h.setDecorationIndex(-1);
if (o != null && objectId == o.getId()) {
SceneryBuilder.replace(o, o.transform(bh.getObjectId(style)));
}
}
}
}
}
break;
}
}
/**
* Checks if the decoration can be built.
* @param player The player.
* @param deco The decoration.
* @param object The object.
* @return {@code True} if so.
*/
private static boolean canBuildDecoration(Player player, Room room, Decoration deco, Scenery object) {
switch (deco) {
case TENTACLE_MID:
case TENTACLE_SIDE:
case TENTACLE_CORNER:
case TENTACLE_FL:
if (!room.isBuilt(BuildHotspot.PRISON)) {
player.getPacketDispatch().sendMessage("You can't build a tentacle pool without a cage.");
return false;
}
return true;
default:
return true;
}
}
/**
* Checks if the decoration can be built.
* @param player The player.
* @param hotspot The hotspot.
* @param object The object.
* @return {@code True} if so.
*/
@SuppressWarnings("unused")
private static boolean setLinkedHotspot(Player player, Room room, Hotspot hotspot, int decorationIndex, Scenery object) {
Location l = object.getLocation();
int z = l.getZ();
switch (hotspot.getHotspot()) {
case STAIRWAYS:
case QUEST_STAIRWAYS:
case STAIRWAYS_DUNGEON:
BuildHotspot[] stairs = { BuildHotspot.STAIRS_DOWN, BuildHotspot.STAIRS_DOWN2, BuildHotspot.STAIRWAYS, BuildHotspot.QUEST_STAIRWAYS, BuildHotspot.STAIRWAYS_DUNGEON };
for (int i = 0; i < 2; i++) {
int plane = (z + 1 + (i * 2)) % 4;
Room r = player.getHouseManager().getRooms()[plane][l.getChunkX()][l.getChunkY()];
if (r != null) {
for (BuildHotspot h : stairs) {
Hotspot hs = r.getHotspot(h, hotspot.getCurrentX(), hotspot.getCurrentY());
if (hs != null) {
hs.setDecorationIndex(decorationIndex);
SceneryBuilder.replace(object, object.transform(h.getDecorations()[decorationIndex].getObjectId(player.getHouseManager().getStyle())));
break;
}
}
}
}
return true;
default:
return true;
}
}
/**
* Builds a room.
* @param player The player.
* @param room The room to build.
* @param reload
*/
public static void buildRoom(Player player, Room room, int z, int x, int y, boolean[] exits, boolean reload) {
player.getHouseManager().getRooms()[z][x][y] = room;
player.getPacketDispatch().sendMessage("Building room " + room.getProperties() + ".");
if (z == 3) {
player.getHouseManager().setHasDungeon(true);
}
if (room.getProperties().isChamber() && z < 2) {
int count = 0;
int index = 0;
for (int i = 0; i < exits.length; i++) {
if (exits[i]) {
count++;
} else {
index = i;
}
}
//(0=east, 1=south, 2=west, 3=north).
// System.out.println("Roof information: index=" + index + ", exit count=" + count + "; array=" + Arrays.toString(exits));
if (count == 4) {
room = Room.create(player, RoomProperties.ROOF_4_EXIT);
}
else if (count == 3) {
room = Room.create(player, RoomProperties.ROOF_3_EXIT);
room.setRotation(DIRECTIONS[(index + 2) % 4]);
}
else if ((exits[0] != exits[2]) || (exits[1] != exits[3])) {
room = Room.create(player, RoomProperties.ROOF_3_EXIT);
if (exits[2]) {
room.setRotation(DIRECTIONS[exits[3] ? 3 : 1]);
}
} else {
room = Room.create(player, RoomProperties.ROOF_2_EXIT);
if (exits[0] || exits[2]) {
room.setRotation(DIRECTIONS[1]);
}
}
player.getHouseManager().getRooms()[z + 1][x][y] = room;
}
if (reload) {
player.getHouseManager().reload(player, true);
}
}
/**
* Checks of a room exists.
* @param player the player
* @param door the door hotspot the player is trying to build at
* @return true if the room is built already
*/
public static int[] roomExists(Player player, Scenery door) {
int[] location = getRoomPosition(player, door);
int z = player.getLocation().getZ();
if (HouseManager.isInDungeon(player)) {
z = 3;
}
if (player.getHouseManager().hasRoomAt(z, location[0], location[1])) {
return location;
}
return null;
}
/**
* Gets the room offset.
* @param door The door.
* @return The room offset [x, y].
*/
public static int[] getRoomPosition(Player player, Scenery door) {
Location l = door.getLocation();
int rotation = door.getRotation();
if (player.getLocation().getChunkX() != l.getLocation().getChunkX()
|| player.getLocation().getChunkY() != l.getLocation().getChunkY()) {
return new int[] { l.getChunkX(), l.getChunkY() };
}
switch (rotation) {
case 0: //West
return new int[] { l.getChunkX() - 1, l.getChunkY() };
case 1: //North
return new int[] { l.getChunkX(), l.getChunkY() + 1};
case 2: //East
return new int[] { l.getChunkX() + 1, l.getChunkY() };
case 3: //South
return new int[] { l.getChunkX(), l.getChunkY() - 1};
}
return null;
}
/**
* Gets the available rotations of the room to build.
* @param exits The exits of the room.
* @param z The plane
* @param roomX The room x-coordinate.
* @param roomY The room y-coordinate.
* @return The available rotations for the room [NORTH, EAST, SOUTH, WEST].
*/
public static Direction[] getAvailableRotations(Player player, boolean[] exits, int z, int roomX, int roomY) {
Direction[] directions = new Direction[4];
boolean[] exit = Arrays.copyOf(exits, exits.length); //(0=east, 1=south, 2=west, 3=north)
int[] info = getExitRequirements(player, z, roomX, roomY);//(0=west, 1=north, 2=east, 3=south)
// SystemLogger.logErr(BuildingUtils.class, "Available exits - [east=" + exit[0] + ", south=" + exit[1] + ", west=" + exit[2] + ", north=" + exit[3] + "]!");
// SystemLogger.logErr(BuildingUtils.class, "Required exits - [east=" + info[0] + ", south=" + info[1] + ", west=" + info[2] + ", north=" + info[3] + "]!");
for (int i = 0; i < 4; i++) {
boolean success = true;
for (int j = 0; j < 4; j++) {
if ((info[j] == 1 && !exit[j]) || (info[j] == -1 && exit[j])) {
success = false;
break;
}
}
if (success) {
directions[i] = DIRECTIONS[i];
}
for (int j = 0; j < exit.length; j++) {
exit[(j + i + 1) % exit.length] = exits[j];
}
}
return directions;
}
/**
* Gets the exit requirements for the given room.
* @param roomX The room x-coordinate.
* @param roomY The room y-coordinate.
* @return The disabled exit indexes.
*/
private static int[] getExitRequirements(Player player, int z, int roomX, int roomY) {
int[] exits = new int[4];
if (roomX == 0) {
exits[2] = -1;
}
else if (player.getHouseManager().hasExit(z, roomX - 1, roomY, Direction.EAST)) {
exits[2] = 1;
}
else if (player.getHouseManager().hasRoomAt(z, roomX - 1, roomY)) {
exits[2] = -1;
}
if (roomY == 7) {
exits[3] = -1;
}
else if (player.getHouseManager().hasExit(z, roomX, roomY + 1, Direction.SOUTH)) {
exits[3] = 1;
}
else if (player.getHouseManager().hasRoomAt(z, roomX, roomY + 1)) {
exits[3] = -1;
}
if (roomX == 7) {
exits[0] = -1;
}
else if (player.getHouseManager().hasExit(z, roomX + 1, roomY, Direction.WEST)) {
exits[0] = 1;
}
else if (player.getHouseManager().hasRoomAt(z, roomX + 1, roomY)) {
exits[0] = -1;
}
if (roomY == 0) {
exits[1] = -1;
}
else if (player.getHouseManager().hasExit(z, roomX, roomY - 1, Direction.NORTH)) {
exits[1] = 1;
}
else if (player.getHouseManager().hasRoomAt(z, roomX, roomY - 1)) {
exits[1] = -1;
}
return exits;
}
}
@@ -0,0 +1,104 @@
package content.global.skill.construction;
import core.game.dialogue.DialogueInterpreter;
import core.game.dialogue.DialoguePlugin;
import core.game.dialogue.book.Book;
import core.game.dialogue.book.Page;
import core.game.node.entity.player.Player;
import core.game.node.item.Item;
import core.game.world.GameWorld;
import core.plugin.Initializable;
/**
* Handles the construction guide book.
* @author Emperor
*
*/
@Initializable
public class ConstructionGuideBook extends Book {
/**
* The resources used in beta.
*/
private static final Item[] RESOURCES = {
new Item(8794),
new Item(2347),
new Item(4819, 500000),
new Item(4820, 500000),
new Item(1539, 500000),
new Item(4821, 500000),
new Item(4822, 500000),
new Item(4823, 500000),
new Item(4824, 500000),
new Item(961, 500000),
new Item(8779, 500000),
new Item(8781, 500000),
new Item(8783, 500000),
new Item(8791, 500000),
new Item(8785, 500000),
new Item(8787, 500000),
new Item(8789, 500000), //16
new Item(8418, 500000),
new Item(8420, 500000),
new Item(8422, 500000),
new Item(8424, 500000),
new Item(8426, 500000),
new Item(8428, 500000),
new Item(8430, 500000),
new Item(8432, 500000),
new Item(8434, 500000),
new Item(8436, 500000),
};
/**
* Constructs a new {@code ConstructionGuideBook} {@code Object}.
*/
public ConstructionGuideBook() {
/*
* empty.
*/
}
/**
* Constructs a new {@code ConstructionGuideBook} {@code Object}.
* @param player
*/
public ConstructionGuideBook(Player player) {
super(player, "Construction guide book", DialogueInterpreter.getDialogueKey("book:conguide"));
}
@Override
public boolean open(final Player player) {
if (GameWorld.getSettings().isDevMode() && GameWorld.getSettings().isBeta()) {
for (Item item : RESOURCES) {
if (!player.getInventory().contains(item.getId(), item.getAmount())) {
player.getInventory().add(item, player);
}
}
}
interpreter.sendPlainMessage(false, "Upon reading the book you discover you're supposed to", "use these resources to test out construction.", "Report all bugs on the forums.");
return true;
}
@Override
public void finish() {
}
@Override
public void display(Page[] set) {
}
@Override
public DialoguePlugin newInstance(Player player) {
return new ConstructionGuideBook(player);
}
@Override
public int[] getIds() {
return new int[] { DialogueInterpreter.getDialogueKey("book:conguide") };
}
}
@@ -0,0 +1,117 @@
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.SystemLogger;
/**
* 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) {
SystemLogger.logErr(this.getClass(), "Failed building decoration " + hotspot + " : " + object);
break;
}
slot = ((slot % 2 != 0) ? 4 : 0) + (slot >> 1);
if (slot >= hotspot.getHotspot().getDecorations().length) {
SystemLogger.logErr(this.getClass(), "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;
SystemLogger.logErr(this.getClass(), "BuildRoom Interface Index: " + index);
if (index > -1 && index < RoomProperties.values().length) {
player.getDialogueInterpreter().open("con:room", RoomProperties.values()[index]);
return true;
}
break;
}
return false;
}
}
@@ -0,0 +1,116 @@
package content.global.skill.construction;
import core.game.node.entity.player.Player;
import org.rs09.consts.Items;
import core.game.node.entity.skill.Skills;
/**
* Family crest types.
*
* @author Emperor
* >ORDINAL BOUND<
*/
public enum CrestType implements CrestRequirement {
ARRAV("the Shield of Arrav symbol") { // requires Shield of Arrav
@Override
public boolean eligible(Player player) {
return player.getQuestRepository().isComplete("Shield of Arrav");
}
},
ASGARNIA("the symbol of Asgarnia"), // no requirements
DORGESHUUN("the Dorgeshuun brooch") { // requires The Lost Tribe
@Override
public boolean eligible(Player player) {
return player.getQuestRepository().isComplete("The Lost Tribe");
}
},
DRAGON("a dragon") { // requires Dragon Slayer
@Override
public boolean eligible(Player player) {
return player.getQuestRepository().isComplete("Dragon Slayer");
}
},
FAIRY("a fairy") { // requries Lost City
@Override
public boolean eligible(Player player) {
return player.getQuestRepository().isComplete("Lost City");
}
},
GUTHIX("the symbol of Guthix") { // Requires 70+ Prayer
@Override
public boolean eligible(Player player) {
return player.getSkills().hasLevel(Skills.PRAYER, 70);
}
},
HAM("the symbol of the HAM cult."), // no requirements
HORSE("a horse") { // requires Toy Horsey in inventory
@Override
public boolean eligible(Player player) {
return player.getInventory().containsAtLeastOneItem(new int[]{
Items.TOY_HORSEY_2524,
Items.TOY_HORSEY_2520,
Items.TOY_HORSEY_2526,
Items.TOY_HORSEY_2522
});
}
},
JOGRE("Jiggig"), // no requirements
KANDARIN("the symbol of Kandarin"), // no requirements
MISTHALIN("the symbol of Misthalin"), // no requirements
MONEY("a bag of money", 500000), // Costs 500k
SARADOMIN("the symbol of Saradomin") { // Requires 70+ Prayer
@Override
public boolean eligible(Player player) {
return player.getSkills().hasLevel(Skills.PRAYER, 70);
}
},
SKULL("a skull") { // requires Skulled while talking to Herald
@Override
public boolean eligible(Player player) {
return player.getSkullManager().isSkulled();
}
},
VARROCK("the symbol of Varrock"), // no requirements
ZAMORAK("the symbol of Zamorak") { // Requires 70+ Prayer
@Override
public boolean eligible(Player player) {
return player.getSkills().hasLevel(Skills.PRAYER, 70);
}
};
private String name;
private int cost;
CrestType(String name, int cost) {
this.name = name;
this.cost = cost;
}
CrestType(String name) {
this(name, 5000);
}
public String getName() {
return this.name;
}
public int getCost() {
return this.cost;
}
}
interface CrestRequirement {
default boolean eligible(Player player) {
return true;
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,466 @@
package content.global.skill.construction
import core.game.node.entity.npc.NPC
import core.game.node.entity.player.Player
import core.game.node.entity.player.link.diary.DiaryType
import core.game.node.entity.skill.Skills
import core.game.node.item.Item
import core.plugin.Initializable
import org.rs09.consts.Items
import core.game.world.GameWorld.settings
import core.tools.END_DIALOGUE
import core.tools.START_DIALOGUE
/**
* Represents the estate agent dialogue.
*
* @author Woah
*/
@Initializable
class EstateAgentDialogue : core.game.dialogue.DialoguePlugin {
/**
* Constructs a new `EstateAgentDialogue` `Object`.
*/
constructor() {
/**
* empty.
*/
}
/**
* Constructs a new `EstateAgentDialogue` `Object`.
*
* @param player the player.
*/
constructor(player: Player?) : super(player)
override fun newInstance(player: Player): core.game.dialogue.DialoguePlugin {
return EstateAgentDialogue(player)
}
override fun open(vararg args: Any): Boolean {
npc = args[0] as NPC
npc("Hello. Welcome to the " + settings!!.name + " Housing Agency! What", "can I do for you?")
stage = START_DIALOGUE
return true
}
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
when (stage) {
START_DIALOGUE -> {
if (player.houseManager.hasHouse()) {
options(
"Can you move my house please?",
"Can you redecorate my house please?",
"Could I have a Construction guidebook?",
"Tell me about houses.",
"Tell me about that skillcape you're wearing.")
stage = 1
} else {
options("How can I get a house?", "Tell me about houses.")
stage = 2
}
}
1 -> when (buttonId) {
1 -> {
player("Can you move my house please?")
stage = 10
}
2 -> {
player("Can you redecorate my house please?")
stage = 30
}
3 -> {
player("Could I have a Construction guidebook?")
stage = 50
}
4 -> {
player("Tell me about houses!")
stage = 60
}
5 -> {
player("Tell me about that skillcape you're wearing!")
stage = if (core.game.global.Skillcape.isMaster(player, Skills.CONSTRUCTION)) 102 else 100
}
}
2 -> when (buttonId) {
1 -> {
player("How can I get a house?")
stage = 3
}
2 -> {
player("Tell me about houses.")
stage = 60
}
}
3 -> {
npc(
"I can sell you a starting house in Rimmington for",
"1000 coins. As you increase your construction skill you",
"will be able to have your house moved to other areas",
"and redecorated in other styles."
)
stage++
}
4 -> {
npc("Do you want to buy a starter house?")
stage++
}
5 -> {
options("Yes please!", "No thanks.")
stage++
}
6 -> when (buttonId) {
1 -> {
player("Yes please!")
stage = 7
}
2 -> {
player("No thanks.")
stage = END_DIALOGUE
}
}
7 -> {
if (player.inventory.contains(995, 1000)) {
player.inventory.remove(Item(995, 1000))
player.houseManager.createNewHouseAt(HouseLocation.RIMMINGTON)
npc(
"Thank you. Go through the Rimmington house portal",
"and you will find your house ready for you to start",
"building in it."
)
} else {
npc("You don't have enough money to buy a house,", "come back when you can afford one.")
}
stage = END_DIALOGUE
}
10 -> {
npc("Certainly. Where would you like it moved to?")
stage++
}
11 -> {
options(
"Rimmington (5,000)",
"Taverley (5,000)",
"Pollnivneach (7,500)",
"Rellekka (10,000)",
"More..." )
stage++
}
12 -> when (buttonId) {
1 -> {
player("To Rimmington please!")
stage = 15
}
2 -> {
player("To Taverly please!")
stage = 16
}
3 -> {
player("To Pollnivneach please!")
stage = 17
}
4 -> {
player("To Rellekka please!")
stage = 18
}
5 -> {
options("Brimhaven (15,000)", "Yanille (25,000)", "...Previous", "Back")
stage = 13
}
}
13 -> when (buttonId) {
1 -> {
player("To Brimhaven please!")
stage = 19
}
2 -> {
player("To Yanille please!")
stage = 20
}
3 -> {
options(
"Rimmington (5,000)",
"Taverley (5,000)",
"Pollnivneach (7,500)",
"Rellekka (10,000)",
"More..."
)
stage = 12
}
}
15 -> configureMove(HouseLocation.RIMMINGTON)
16 -> configureMove(HouseLocation.TAVERLY)
17 -> configureMove(HouseLocation.POLLNIVNEACH)
18 -> configureMove(HouseLocation.RELLEKKA)
19 -> configureMove(HouseLocation.BRIMHAVEN)
20 -> configureMove(HouseLocation.YANILLE)
30 -> {
npc(
"Certainly. My magic can rebuild the house in a",
"completely new style! What style would you like?" )
stage++
}
31 -> {
options(
"Basic wood (5,000)",
"Basic stone (5,000)",
"Whitewashed stone (7,500)",
"Fremennik-style wood (10,000)",
"More..."
)
stage++
}
32 -> when (buttonId) {
1 -> {
player("Basic wood please!")
stage = 35
}
2 -> {
player("Basic stone please!")
stage = 36
}
3 -> {
player("Whitewashed stone please!")
stage = 37
}
4 -> {
player("Fremennik-style wood please!")
stage = 38
}
5 -> {
options("Tropical wood (15,000)", "Fancy stone (25,000)", "Previous...", "Back")
stage = 33
}
}
33 -> when (buttonId) {
1 -> {
player("Tropical wood please!")
stage = 39
}
2 -> {
player("Fancy stone please!")
stage = 40
}
3 -> {
options(
"Basic wood (5,000)",
"Basic stone (5,000)",
"Whitewashed stone (7,500)",
"Fremennik-style wood (10,000)",
"More..."
)
stage = 32
}
}
35 -> redecorate(HousingStyle.BASIC_WOOD)
36 -> redecorate(HousingStyle.BASIC_STONE)
37 -> redecorate(HousingStyle.WHITEWASHED_STONE)
38 -> redecorate(HousingStyle.FREMENNIK_STYLE_WOOD)
39 -> redecorate(HousingStyle.TROPICAL_WOOD)
40 -> redecorate(HousingStyle.FANCY_STONE)
50 -> {
if (player.hasItem(CONSTRUCTION_GUIDE_8463)) {
npc("You've already got one!")
} else {
npc("Certainly.")
player.inventory.add(CONSTRUCTION_GUIDE_8463)
}
stage = END_DIALOGUE
}
60 -> {
npc(
"It all came out of the wizards' experiments. They found",
"a way to fold space, so that they could pack many",
"acres of land into an area only a foot across."
)
stage++
}
61 -> {
npc(
"They created several folded-space regions across",
"" + settings!!.name + ". Each one contains hundreds of small plots",
"where people can build houses."
)
stage++
}
62 -> {
player("Ah, so that's how everyone can have a house without", "them cluttering up the world!")
stage++
}
63 -> {
npc(
"Quite. The wizards didn't want to get bogged down",
"in the business side of things so they ",
"hired me to sell the houses."
)
stage++
}
64 -> {
npc(
"There are various other people across " + settings!!.name + " who can",
"help you furnish your house. You should start buying",
"planks from the sawmill operator in Varrock."
)
stage = END_DIALOGUE
}
100 -> {
npc(
"As you may know, skillcapes are only available to masters",
"in a skill. I have spent my entire life building houses and",
"now I spend my time selling them! As a sign of my abilites",
"I wear this Skillcape of Construction. If you ever have"
)
stage = 101
}
101 -> {
npc(
"enough skill to build a demonic throne, come and talk to",
"me and I'll sell you a skillcape like mine."
)
stage = END_DIALOGUE
}
102 -> {
interpreter.sendDialogues(
npc,
core.game.dialogue.FacialExpression.JOLLY,
"I see you have recently achieved 99 construction.",
"Would you like to buy a cape for 99,0000 gp?"
)
stage++
}
103 -> {
options("Yes, I'll pay the 99k", "No thanks, maybe later.")
stage++
}
104 -> when (buttonId) {
1 -> {
if (core.game.global.Skillcape.purchase(player, Skills.CONSTRUCTION)) {
npc("Here you go lad, enjoy!")
}
stage = END_DIALOGUE
}
2 -> {
player("No thanks, maybe later.")
stage = END_DIALOGUE
}
}
END_DIALOGUE -> end()
}
return true
}
/**
* Configures the move.
*
* @param location The house location.
*/
private fun configureMove(location: HouseLocation) {
//Achievement completion checks
val completedVarrockHouseMove = player.achievementDiaryManager.hasCompletedTask(DiaryType.VARROCK,0,11)
when {
//Player does not have required construction level
!location.hasLevel(player) -> {
npc(
"I'm afraid you don't have a high enough construction",
"level to move there. You need to have level " + location.levelRequirement + "." )
stage = 11
return
}
//Player's house location is already where they selected
location == player.houseManager.location -> {
npc("Your house is already there!")
stage = 11
return
}
//Player does not have enough coins to buy a house move
!player.inventory.contains(Items.COINS_995, location.cost) -> {
npc("Hmph. Come back when you have " + location.cost + " coins.")
stage = END_DIALOGUE
return
}
//Player meets all above requirements + check for achievement unlocks
else -> {
player.inventory.remove(Item(Items.COINS_995, location.cost))
player.houseManager.location = location
npc("Your house has been moved to " + location.getName() + ".")
if (player.location.isInRegion(REGION_VARROCK_NE) && !completedVarrockHouseMove) {
player.achievementDiaryManager.finishTask(player, DiaryType.VARROCK, 0, 11)
}
stage = END_DIALOGUE
}
}
}
/**
* Redecorates the player's house.
*
* @param style The house style.
*/
private fun redecorate(style: HousingStyle) {
//Achievement completion checks
val completedVarrockHouseRedecorate = player.achievementDiaryManager.hasCompletedTask(DiaryType.VARROCK,2,7)
when {
//Player does not have required construction level
!style.hasLevel(player) -> {
npc("You need a Construction level of " + style.level + " to buy this style.")
stage = 31
return
}
//Player's house location is already where they selected
style == player.houseManager.style -> {
npc("Your house is already in that style!")
stage = 31
return
}
//Player does not have enough coins to buy a house move
!player.inventory.contains(Items.COINS_995, style.cost) -> {
npc("Hmph. Come back when you have " + style.cost + " coins.")
stage = END_DIALOGUE
return
}
//Player meets all above requirements + check for achievement unlocks
else -> {
player.inventory.remove(Item(Items.COINS_995, style.cost))
player.houseManager.redecorate(style)
npc("Your house has been redecorated.")
// Give your player-owned house a fancy stone or tropical wood<br><br>finish at the Varrock estate agent's
if (player.location.isInRegion(REGION_VARROCK_NE) && !completedVarrockHouseRedecorate) {
player.achievementDiaryManager.finishTask(player, DiaryType.VARROCK, 2, 7)
}
stage = END_DIALOGUE
}
}
}
override fun getIds(): IntArray {
return intArrayOf(4247)
}
//Items
private val CONSTRUCTION_GUIDE_8463 = Item(Items.CONSTRUCTION_GUIDE_8463, 1)
//Region to check
private val REGION_VARROCK_NE = 12854
}
@@ -0,0 +1,60 @@
package content.global.skill.construction
import content.global.skill.construction.BuildHotspot
/**
* Represents a hotspot.
* @author Emperor
*/
class Hotspot (val hotspot: BuildHotspot, val chunkX: Int, val chunkY: Int, var chunkX2: Int, var chunkY2: Int) {
constructor(hotspot: BuildHotspot, chunkX: Int, chunkY: Int) : this(hotspot,chunkX,chunkY,-1,-1)
/**
* The current chunk x coordinate.
*/
var currentX: Int
/**
* Gets the currentY value.
* @return The currentY.
*/
/**
* Sets the currentY value.
* @param currentY The currentY to set.
*/
/**
* The chunk y coordinate.
*/
var currentY: Int
/**
* Gets the decorationIndex.
* @return The decorationIndex.
*/
/**
* Sets the decorationIndex.
* @param decorationIndex The decorationIndex to set.
*/
/**
* The current decoration index.
*/
var decorationIndex = -1
/**
* Copies the hotspot.
* @return The hotspot.
*/
fun copy(): Hotspot {
return Hotspot(hotspot, chunkX, chunkY, chunkX2, chunkY2)
}
/**
* Constructs a new `Hotspot` `Object`.
* @param hotspot The hotspot.
* @param chunkX The chunk x-coordinate.
* @param chunkY The chunk y-coordinate.
*/
init {
currentX = chunkX
currentY = chunkY
}
}
@@ -0,0 +1,164 @@
package content.global.skill.construction;
import core.game.node.entity.skill.Skills;
import core.game.node.entity.player.Player;
import core.game.world.map.Location;
import core.tools.StringUtils;
/**
* The house locations.
* @author Emperor
*/
@SuppressWarnings("all")
public enum HouseLocation {
//Nowhere is used for players who do not have a house
NOWHERE(-1, null, 0, 0),
RIMMINGTON(15478, Location.create(2953, 3224, 0), 5000, 1),
TAVERLY(15477, Location.create(2893, 3465, 0), 5000, 10),
POLLNIVNEACH(15479, Location.create(3340, 3003, 0), 7500, 20),
RELLEKKA(15480, Location.create(2670, 3631, 0), 10000, 30),
BRIMHAVEN(15481, Location.create(2757, 3178, 0), 15000, 40),
YANILLE(15482, Location.create(2544, 3096, 0), 25000, 50);
//custom island thing that previous source users had.
//WHITERIDGE(43832, Location.create(3965, 3546, 0), 100_000, 60);
/**
* The portal object id for this location.
*/
private final int portalId;
/**
* The exit location.
*/
private final Location exitLocation;
/**
* The cost to move
*/
private final int cost;
/**
* Level requirement
*/
private final int levelRequirement;
/**
* The house options
*/
//public static TabbedOption HOUSE_OPTIONS = new TabbedOption("House Locations", "Select an Option");
/**
* Sets up a page action tabbed option
*/
static {
/*int index = 0;
PageAction[] pageActions = new PageAction[5];
for (HouseLocation hl : values()) {
if (hl == HouseLocation.NOWHERE || (hl == HouseLocation.WHITERIDGE && GameWorld.getSettings().isDeadmanMode()))
continue;
if (index > 4) {
index = 0;
HOUSE_OPTIONS.addPage(new Page(pageActions));
pageActions = new PageAction[5];
}
pageActions[index++] = new PageAction(hl.name() + " - " + hl.cost + "gp") {
@Override
public boolean run(Player player) {
if (player.getHouseManager().getLocation() == hl) {
player.sendMessage("<col=FF0000>Your house already resides in " + hl.name() + "!");
return true;
}
if (player.getSkills().hasLevel(Skills.CONSTRUCTION, hl.levelRequirement)) {
if (player.getInventory().contains(995, hl.cost)) {
player.getInventory().remove(new Item(995, hl.cost));
player.getHouseManager().setLocation(hl);
player.sendMessage("<col=006600>You have changed your house location to " + hl.name() + "!");
} else {
player.sendMessage("<col=FF0000>You need " + hl.cost + "gp in order to move there!");
}
} else {
player.sendMessage("<col=FF0000>You need a construction level of " + hl.levelRequirement + " to move there!");
}
return true;
}
};
}
if (pageActions[0] != null) {
HOUSE_OPTIONS.addPage(new Page(pageActions));
}*/
}
/**
* Checks if the player has the level.
*
* @param player the player.
* @return {@code True} if so.
*/
public boolean hasLevel(Player player) {
return player.getSkills().getStaticLevel(Skills.CONSTRUCTION) >= levelRequirement;
}
/**
* Constructs a new {@code HouseLocation} {@code Object}
* @param portalId The portal id.
* @param exitLocation The exit location.
*/
private HouseLocation(int portalId, Location exitLocation, int cost, int levelRequirement) {
this.portalId = portalId;
this.exitLocation = exitLocation;
this.cost = cost;
this.levelRequirement = levelRequirement;
}
/**
* Gets the name formatted.
*
* @return the formatted name.
*/
public String getName() {
return StringUtils.formatDisplayName(name().toLowerCase());
}
/**
* Gets the portalId.
* @return the portalId
*/
public int getPortalId() {
return portalId;
}
/**
* Gets the exitLocation.
* @return the exitLocation
*/
public Location getExitLocation() {
return exitLocation;
}
/**
* Gets the cost to move to here
* @return the cost
*/
public int getCost() {
return cost;
}
/**
* Gets the level requirement to move to here
* @return the level requirement
*/
public int getLevelRequirement() {
return levelRequirement;
}
}
@@ -0,0 +1,892 @@
package content.global.skill.construction;
//import org.arios.game.content.global.DeadmanTimedAction;
//import org.arios.game.node.entity.player.info.login.SavingModule;
import core.api.regionspec.RegionSpecification;
import core.api.regionspec.contracts.FillChunkContract;
import core.game.dialogue.FacialExpression;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.audio.Audio;
import core.game.node.entity.skill.Skills;
import core.game.node.scenery.Scenery;
import core.game.system.task.Pulse;
import core.game.world.map.*;
import core.game.world.map.build.DynamicRegion;
import core.game.world.map.zone.ZoneBorders;
import core.game.world.map.zone.ZoneBuilder;
import core.game.world.update.flag.context.Animation;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import core.tools.SystemLogger;
import core.game.world.GameWorld;
import java.awt.*;
import java.nio.ByteBuffer;
import static core.api.regionspec.RegionSpecificationKt.fillWith;
import static core.api.regionspec.RegionSpecificationKt.using;
/**
* Manages the player's house.
* @author Emperor
*
*/
public final class HouseManager {
/**
* The current region.
*/
private DynamicRegion houseRegion;
/**
* The current region.
*/
private DynamicRegion dungeonRegion;
/**
* The house location.
*/
private HouseLocation location = HouseLocation.NOWHERE;
/**
* The house style.
*/
private HousingStyle style = HousingStyle.BASIC_WOOD;
/**
* The house zone.
*/
private final HouseZone zone = new HouseZone(this);
/**
* The player's house rooms.
*/
private final Room[][][] rooms = new Room[4][8][8];
/**
* If building mode is enabled.
*/
private boolean buildingMode;
/**
* If the player has used the portal to lock their house.
*/
private boolean locked;
/**
* The player's servant.
*/
private Servant servant;
/**
* If the house has a dungeon.
*/
private boolean hasDungeon;
/**
* The player's crest.
*/
private CrestType crest = CrestType.ASGARNIA;
/**
* Constructs a new {@code HouseManager} {@code Object}.
*/
public HouseManager() {
/*
* empty.
*/
}
public void save(ByteBuffer buffer) {
buffer.put((byte) location.ordinal());
buffer.put((byte) style.ordinal());
if (hasServant()) {
servant.save(buffer);
} else {
buffer.put((byte) -1);
}
for (int z = 0; z < 4; z++) {
for (int x = 0; x < 8; x++) {
for (int y = 0; y < 8; y++) {
Room room = rooms[z][x][y];
if (room != null) {
buffer.put((byte) z).put((byte) x).put((byte) y);
buffer.put((byte) room.getProperties().ordinal());
buffer.put((byte) room.getRotation().toInteger());
for (int i = 0; i < room.getHotspots().length; i++) {
if (room.getHotspots()[i].getDecorationIndex() > -1) {
buffer.put((byte) i);
buffer.put((byte) room.getHotspots()[i].getDecorationIndex());
}
}
buffer.put((byte) -1);
}
}
}
}
buffer.put((byte) -1);//Eof
}
public void parse(JSONObject data){
location = HouseLocation.values()[Integer.parseInt( data.get("location").toString())];
style = HousingStyle.values()[Integer.parseInt( data.get("style").toString())];
Object servRaw = data.get("servant");
if(servRaw != null){
servant = Servant.parse((JSONObject) servRaw);
}
JSONArray rArray = (JSONArray) data.get("rooms");
for(int i = 0; i < rArray.size(); i++){
JSONObject rm = (JSONObject) rArray.get(i);
int z = Integer.parseInt(rm.get("z").toString());
int x = Integer.parseInt(rm.get("x").toString());
int y = Integer.parseInt(rm.get("y").toString());
if(z == 3)
hasDungeon = true;
Room room = rooms[z][x][y] = new Room(RoomProperties.values()[Integer.parseInt(rm.get("properties").toString())]);
room.configure(style);
room.setRotation(Direction.get(Integer.parseInt(rm.get("rotation").toString())));
JSONArray hotspots = (JSONArray) rm.get("hotspots");
for(int j = 0; j < hotspots.size(); j++){
JSONObject spot = (JSONObject) hotspots.get(j);
room.getHotspots()[Integer.parseInt(spot.get("hotspotIndex").toString())].setDecorationIndex(Integer.parseInt(spot.get("decorationIndex").toString()));
}
}
}
public void parse(ByteBuffer buffer) {
location = HouseLocation.values()[buffer.get() & 0xFF];
style = HousingStyle.values()[buffer.get() & 0xFF];
servant = Servant.parse(buffer);
int z = 0;
while ((z = buffer.get()) != -1) {
if (z == 3) {
hasDungeon = true;
}
int x = buffer.get();
int y = buffer.get();
Room room = rooms[z][x][y] = new Room(RoomProperties.values()[buffer.get() & 0xFF]);
room.configure(style);
room.setRotation(Direction.get(buffer.get() & 0xFF));
int spot = 0;
while ((spot = buffer.get()) != -1) {
room.getHotspots()[spot].setDecorationIndex(buffer.get() & 0xFF);
}
}
}
/**
* Enter's the player's house.
* @param player
* @param buildingMode
*/
public void enter(final Player player, boolean buildingMode) {
if (this.buildingMode != buildingMode || !isLoaded()) {
this.buildingMode = buildingMode;
construct();
}
player.setAttribute("poh_entry", HouseManager.this);
player.lock(1);
player.sendMessage("House location: " + houseRegion.getBaseLocation() + ", entry: " + getEnterLocation());
player.getProperties().setTeleportLocation(getEnterLocation());
openLoadInterface(player);
checkForAndSpawnServant(player);
updateVarbits(player, buildingMode);
unlockMusicTrack(player);
}
private void openLoadInterface(Player player) {
player.getInterfaceManager().openComponent(399);
player.getAudioManager().send(new Audio(984));
submitCloseLoadInterfacePulse(player);
}
private void submitCloseLoadInterfacePulse(Player player) {
GameWorld.getPulser().submit(new Pulse(1, player) {
@Override
public boolean pulse() {
player.getInterfaceManager().close();
return true;
}
});
}
private void checkForAndSpawnServant(Player player) {
if(!hasServant()) return;
GameWorld.getPulser().submit(new Pulse(1, player) {
@Override
public boolean pulse() {
spawnServant();
if (servant.isGreet()){
player.getDialogueInterpreter().sendDialogues(servant.getType().getId(), servant.getType().getId() == 4243 ? FacialExpression.HALF_GUILTY : null, "Welcome.");
}
return true;
}
});
}
private void updateVarbits(Player player, boolean build) {
player.varpManager.get(261).setVarbit(0, build ? 1 : 0);
player.varpManager.get(262).setVarbit(0, getRoomAmount());
}
private void unlockMusicTrack(Player player) {
player.getMusicPlayer().unlock(454, true);
}
/**
* Leaves this house.
* @param player The player leaving.
*/
public static void leave(Player player) {
HouseManager house = player.getAttribute("poh_entry", player.getHouseManager());
if (house.getHouseRegion() == null){
return;
}
if (house.isInHouse(player)) {
player.animate(Animation.RESET);
player.setLocation(house.location.getExitLocation());
}
}
/**
* Toggles the building mode.
* @param player The house owner.
* @param enable If the building mode should be enabled.
*/
public void toggleBuildingMode(Player player, boolean enable) {
if (!isInHouse(player)) {
player.getPacketDispatch().sendMessage("Building mode really only helps if you're in a house.");
return;
}
if (buildingMode != enable) {
if (enable) {
expelGuests(player);
}
buildingMode = enable;
reload(player, enable);
player.getPacketDispatch().sendMessage("Building mode is now " + (buildingMode ? "on." : "off."));
}
}
/**
* Reloads the house.
* @param player The player.
* @param buildingMode If building mode should be enabled.
*/
public void reload(Player player, boolean buildingMode) {
int diffX = player.getLocation().getLocalX();
int diffY = player.getLocation().getLocalY();
int diffZ = player.getLocation().getZ();
boolean inDungeon = player.getViewport().getRegion() == dungeonRegion;
this.buildingMode = buildingMode;
construct();
Location newLoc = (dungeonRegion == null ? houseRegion : (inDungeon ? dungeonRegion : houseRegion)).getBaseLocation().transform(diffX,diffY,diffZ);
player.getProperties().setTeleportLocation(newLoc);
}
/**
* Expels the guests from the house.
* @param player The house owner.
*/
public void expelGuests(Player player) {
if (isLoaded()) {
for (RegionPlane plane : houseRegion.getPlanes()) {
for (Player p : plane.getPlayers()) {
if (p != player) {
leave(p);
}
}
}
if (dungeonRegion != null) {
for (RegionPlane plane : dungeonRegion.getPlanes()) {
for (Player p : plane.getPlayers()) {
if (p != player) {
leave(p);
}
}
}
}
}
}
/**
* Gets the entering location.
* @return The entering location.
*/
public Location getEnterLocation() {
if (houseRegion == null) {
SystemLogger.logErr(this.getClass(), "House wasn't constructed yet!");
return null;
}
for (int x = 0; x < 8; x++) {
for (int y = 0; y < 8; y++) {
Room room = rooms[0][x][y];
if (room != null && (room.getProperties() == RoomProperties.GARDEN || room.getProperties() == RoomProperties.FORMAL_GARDEN)) {
for (Hotspot h : room.getHotspots()) {
if (h.getDecorationIndex() > -1) {
Decoration d = h.getHotspot().getDecorations()[h.getDecorationIndex()];
if (d == Decoration.PORTAL) {
return houseRegion.getBaseLocation().transform(x * 8 + h.getChunkX(), y * 8 + h.getChunkY() + 2, 0);
}
}
}
}
}
}
return null;
}
/**
* Redecorates the house.
* @param style The new style.
*/
public void redecorate(HousingStyle style) {
this.style = style;
for (int z = 0; z < 4; z++) {
for (int x = 0; x < 8; x++) {
for (int y = 0; y < 8; y++) {
Room room = rooms[z][x][y];
if (room != null) {
room.decorate(style);
}
}
}
}
}
/**
* Clears all the rooms (<b>Including portal room!</b>).
*/
@Deprecated
public void clearRooms() {
for (int z = 0; z < 4; z++) {
for (int x = 0; x < 8; x++) {
for (int y = 0; y < 8; y++) {
rooms[z][x][y] = null;
}
}
}
}
/**
* Creates the default house.
* @param location The house location.
*/
public void createNewHouseAt(HouseLocation location) {
clearRooms();
Room room = rooms[0][4][3] = new Room(RoomProperties.GARDEN);
room.configure(style);
room.getHotspots()[0].setDecorationIndex(0);
this.location = location;
}
/**
* Constructs the dynamic region for the house.
* @return The region.
*/
public DynamicRegion construct() {
houseRegion = getPreparedRegion();
configureRoofs();
prepareHouseChunks(style, houseRegion, buildingMode, rooms);
if (hasDungeon()) {
dungeonRegion = getPreparedRegion();
prepareDungeonChunks(style, dungeonRegion, houseRegion, buildingMode, rooms[3]);
}
ZoneBuilder.configure(zone);
return houseRegion;
}
private DynamicRegion getPreparedRegion() {
ZoneBorders borders = DynamicRegion.reserveArea(8,8);
DynamicRegion region = new DynamicRegion(-1, borders.getSouthWestX() >> 6, borders.getSouthWestY() >> 6);
region.setBorders(borders);
region.setUpdateAllPlanes(true);
RegionManager.addRegion(region.getId(), region);
return region;
}
private class RoomLoadContract extends FillChunkContract {
Room[][][] rooms;
HouseManager manager;
boolean buildingMode;
public RoomLoadContract(HouseManager manager, boolean buildingMode, Room[][][] rooms) {
this.rooms = rooms;
this.manager = manager;
this.buildingMode = buildingMode;
}
@Override
public BuildRegionChunk getChunk(int x, int y, int plane, @NotNull DynamicRegion dyn) {
BuildRegionChunk chunk = rooms[plane][x][y].getChunk().copy(dyn.getPlanes()[plane]);
return chunk;
}
@Override
public void afterSetting(@Nullable BuildRegionChunk chunk, int x, int y, int plane, @NotNull DynamicRegion dyn) {
rooms[plane][x][y].loadDecorations(dyn != manager.dungeonRegion ? plane : 3, chunk, manager);
}
}
private void prepareHouseChunks(HousingStyle style, DynamicRegion target, boolean buildingMode, Room[][][] rooms) {
Region from = RegionManager.forId(style.getRegionId());
Region.load(from, true);
RegionChunk defaultChunk = from.getPlanes()[style.getPlane()].getRegionChunk(1, 0);
RegionChunk defaultSkyChunk = from.getPlanes()[1].getRegionChunk(0,0);
RoomLoadContract loadRooms = new RoomLoadContract(this, buildingMode, rooms);
RegionSpecification spec = new RegionSpecification(
using(target),
fillWith(defaultChunk)
.from(from)
.onPlanes(0)
.onCondition((destX, destY, plane) -> rooms[plane][destX][destY] == null),
fillWith((RegionChunk) null)
.from(from)
.onPlanes(1,2)
.onCondition((destX, destY, plane) -> rooms[plane][destX][destY] == null),
fillWith(defaultSkyChunk)
.from(from)
.onPlanes(3),
loadRooms
.from(from)
.onPlanes(0,1,2)
.onCondition((destX,destY,plane) -> rooms[plane][destX][destY] != null)
);
spec.build();
}
private void prepareDungeonChunks(HousingStyle style, DynamicRegion target, DynamicRegion house, boolean buildingMode, Room[][] rooms) {
Region from = RegionManager.forId(style.getRegionId());
Region.load(from, true);
RegionChunk defaultChunk = from.getPlanes()[style.getPlane()].getRegionChunk(3, 0);
RoomLoadContract loadRooms = new RoomLoadContract(this, buildingMode, new Room[][][]{rooms});
RegionSpecification spec = new RegionSpecification(
using(target),
fillWith((x,y,plane,region) -> buildingMode ? null : defaultChunk)
.from(from)
.onPlanes(0)
.onCondition((destX, destY, plane) -> rooms[destX][destY] == null),
loadRooms
.from(from)
.onPlanes(0)
.onCondition((destX, destY, plane) -> rooms[destX][destY] != null)
);
spec.build();
house.link(target);
}
/**
* Configures the rooftops.
*/
public void configureRoofs() {
// boolean[][][] roofs = new boolean[2][8][8];
// for (int x = 0; x < 8; x++) {
// for (int y = 0; y < 8; y++) {
// Room room = rooms[0][x][y];
// if (room != null && room.getProperties().isChamber()) {
// room = rooms[1][x][y];
// int z = 1;
// if (room != null && room.getProperties().isChamber()) {
// z = 2;
// }
// if (x > 0 )
// }
// }
// }
}
/**
* Gets the current room plane.
* @param l The location.
* @return The plane of the room.
*/
public Room getRoom(Location l) {
int z = l.getZ();
if (dungeonRegion != null && l.getRegionId() == dungeonRegion.getId()) {
z = 3;
}
return rooms[z][l.getChunkX()][l.getChunkY()];
}
/**
* Gets the hotspot for the given object.
* @param object The object.
* @return The hotspot.
*/
public Hotspot getHotspot(Scenery object) {
Room room = getRoom(object.getLocation());
if (room == null) {
return null;
}
int chunkX = object.getLocation().getChunkOffsetX();
int chunkY = object.getLocation().getChunkOffsetY();
switch(room.getRotation()){
case WEST: {
int tempChunk = chunkY;
chunkY = 7 - chunkX;
chunkX = tempChunk;
break;
}
case EAST: {
//x = y, y = x, x = 7 - y
int tempChunk = chunkX;
chunkX = 7 - chunkY;
chunkY = tempChunk;
break;
}
case SOUTH: {
chunkY = 7 - chunkY;
break;
}
default: {
}
}
for (Hotspot h : room.getHotspots()) {
if ((h.getChunkX() == chunkX || h.getChunkX2() == chunkX) && (h.getChunkY() == chunkY || h.getChunkY2() == chunkY) && h.getHotspot().getObjectId(style) == object.getId()) {
return h;
}
}
return null;
}
/**
* Checks if a room exists on the given location.
* @param z The plane.
* @param roomX The room x-coordinate.
* @param roomY The room y-coordinate.
* @return {@code True} if so.
*/
public boolean hasRoomAt(int z, int roomX, int roomY) {
Room room = rooms[z][roomX][roomY];
return room != null && !room.getProperties().isRoof();
}
/**
* Enters the dungeon.
* @param player The player.
*/
public void enterDungeon(Player player) {
if (!hasDungeon()) {
return;
}
int diffX = player.getLocation().getLocalX();
int diffY = player.getLocation().getLocalY();
player.getProperties().setTeleportLocation(dungeonRegion.getBaseLocation().transform(diffX, diffY, 0));
}
/**
* Checks if an exit exists on the given room.
* @param roomX The x-coordinate of the room.
* @param roomY The y-coordinate of the room.
* @param direction The exit direction.
* @return {@code True} if so.
*/
public boolean hasExit(int z, int roomX, int roomY, Direction direction) {
Room room = rooms[z][roomX][roomY];
int index = (direction.toInteger() + 3) % 4;
return room != null && room.getExits()[index];
}
/**
* Gets the amount of rooms.
* @return The amount of rooms.
*/
public int getRoomAmount() {
int count = 0;
for (int z = 0; z < 4; z++) {
for (int x = 0; x < 8; x++) {
for (int y = 0; y < 8; y++) {
Room r = rooms[z][x][y];
if (r != null && !r.getProperties().isRoof()) {
count++;
}
}
}
}
return count;
}
/**
* Gets the amount of portals available.
* @return The amount of portals.
*/
public int getPortalAmount() {
int count = 0;
for (int x = 0; x < 8; x++) {
for (int y = 0; y < 8; y++) {
Room room = rooms[0][x][y];
if (room != null && (room.getProperties() == RoomProperties.GARDEN
|| room.getProperties() == RoomProperties.FORMAL_GARDEN) && room.getHotspots()[0].getDecorationIndex() == 0) {
count++;
}
}
}
return count;
}
/**
* Gets the current house boundaries.
* @return The boundaries.
*/
public Rectangle getBoundaries() {
int startX = 99;
int startY = 99;
int endX = 0;
int endY = 0;
for (int x = 0; x < 8; x++) {
for (int y = 0; y < 8; y++) {
if (rooms[0][x][y] != null) {
if (x < startX) startX = x;
if (y < startY) startY = y;
if (x > endX) endX = x;
if (y > endY) endY = y;
}
}
}
return new Rectangle(startX, startY, (endX - startX) + 1, (endY - startY) + 1);
}
/**
* Gets the maximum dimension for the house boundaries.
* @param player The player.
* @return The dimension value (value X value = dimension)
*/
public int getMaximumDimension(Player player) {
int level = player.getSkills().getStaticLevel(Skills.CONSTRUCTION);
if (level >= 60) {
return 7;
}
if (level >= 45) {
return 6;
}
if (level >= 30) {
return 5;
}
if (level >= 15) {
return 4;
}
return 3;
}
/**
* Gets the maximum amount of rooms available for the player.
* @param player The player.
* @return The maximum amount of rooms.
*/
public int getMaximumRooms(Player player) {
int level = player.getSkills().getStaticLevel(Skills.CONSTRUCTION);
if (level >= 99) return 30;
if (level >= 96) return 29;
if (level >= 92) return 28;
if (level >= 86) return 27;
if (level >= 80) return 26;
if (level >= 74) return 25;
if (level >= 68) return 24;
if (level >= 62) return 23;
if (level >= 56) return 22;
if (level >= 50) return 21;
return 20;
}
/**
* Spawns the servant inside the player's home.
*/
private void spawnServant(){
servant.setLocation(getEnterLocation());
servant.setWalkRadius(getRoomAmount() * 2);
servant.setWalks(true);
servant.init();
}
/**
* Checks if the player has a servant.
* @return {@code True} if so.
*/
public boolean hasServant() {
return servant != null;
}
/**
* Checks if the player is in his own house (or dungeon).
* @param player The player.
* @return {@code True} if so.
*/
public boolean isInHouse(Player player) {
return isLoaded() && (player.getViewport().getRegion() == houseRegion || player.getViewport().getRegion() == dungeonRegion);
}
/**
* Checks if the player is in his dungeon.
* @param player The player.
* @return {@code True} if so.
*/
public static boolean isInDungeon(Player player) {
return player.getViewport().getRegion() == player.getHouseManager().dungeonRegion;
}
/**
* Checks if the house region was constructed and active.
* @return {@code True} if an active region for the house exists.
*/
public boolean isLoaded() {
return (houseRegion != null) || (dungeonRegion != null);
}
/**
* Gets the hasHouse.
* @return The hasHouse.
*/
public boolean hasHouse() {
return location != HouseLocation.NOWHERE;
}
/**
* Checks if the house has a dungeon.
* @return {@code True} if so.
*/
public boolean hasDungeon() {
return hasDungeon;
}
/**
* Sets the has dungeon value.
* @param hasDungeon If the house has a dungeon.
*/
public void setHasDungeon(boolean hasDungeon) {
this.hasDungeon = hasDungeon;
}
/**
* Gets the rooms.
* @return The rooms.
*/
public Room[][][] getRooms() {
return rooms;
}
/**
* Gets the location.
* @return The location.
*/
public HouseLocation getLocation() {
return location;
}
/**
* Sets the location.
* @param location The location to set.
*/
public void setLocation(HouseLocation location) {
this.location = location;
}
/**
* Checks if the building mode is enabled.
* @return {@code True} if so.
*/
public boolean isBuildingMode() {
return buildingMode;
}
/**
* Checks if the player has locked their house.
* @return {@code True} if so.
*/
public boolean isLocked() {
return locked;
}
/**
* Sets the house to locked.
* @param locked true or false
*/
public void setLocked(boolean locked) {
this.locked = locked;
}
/**
* Gets the region.
* @return The region.
*/
public DynamicRegion getHouseRegion() {
return houseRegion;
}
/**
* Gets the dungeon region.
* @return The dungeon region.
*/
public Region getDungeonRegion() {
return dungeonRegion;
}
/**
* Gets the style.
* @return the style
*/
public HousingStyle getStyle() {
return style;
}
/**
* Sets the style.
* @param style the style to set.
*/
public void setStyle(HousingStyle style) {
this.style = style;
}
/**
* Gets the player's servant
* @return the servant.
*/
public Servant getServant(){
return servant;
}
/**
* Sets the player's servant
* @param servant The servant to set.
*/
public void setServant(Servant servant){
this.servant = servant;
}
/**
* Gets the crest value.
* @return The crest.
*/
public CrestType getCrest() {
return crest;
}
/**
* Sets the crest value.
* @param crest The crest to set.
*/
public void setCrest(CrestType crest) {
this.crest = crest;
}
/**
* @return the zone
*/
public HouseZone getZone() {
return zone;
}
}
@@ -0,0 +1,78 @@
package content.global.skill.construction;
import core.game.node.entity.Entity;
import core.game.node.entity.player.Player;
import core.game.world.map.zone.MapZone;
import core.game.world.map.zone.ZoneRestriction;
/**
* Handles the player owned house zone.
*
* @author Emperor
*/
public final class HouseZone extends MapZone {
/**
* The house manager.
*/
private HouseManager house;
/**
* The previous house region id.
*/
private int previousRegion = -1;
/**
* The previous dungeon region id.
*/
private int previousDungeon = -1;
/**
* Constructs the house zone object.
*/
public HouseZone(HouseManager house) {
super("poh-zone" + house, true, ZoneRestriction.RANDOM_EVENTS, ZoneRestriction.FOLLOWERS);
this.house = house;
}
@Override
public void configure() {
if (previousRegion != -1) {
unregisterRegion(previousRegion);
}
if (previousDungeon != -1) {
unregisterRegion(previousDungeon);
}
registerRegion(house.getHouseRegion().getId());
if (house.getDungeonRegion() != null) {
registerRegion(house.getHouseRegion().getId());
}
}
@Override
public boolean enter(Entity e) {
return super.enter(e);
}
@Override
public boolean death(Entity e, Entity killer) {
if (e instanceof Player) {
Player p = (Player) e;
HouseManager.leave(p);
}
return true;
}
@Override
public boolean leave(Entity e, boolean logout) {
if (logout) {
if (e instanceof Player) {
Player p = (Player) e;
HouseManager.leave(p);
return true;
}
}
return true;
}
}
@@ -0,0 +1,152 @@
package content.global.skill.construction;
import core.game.node.entity.player.Player;
import core.game.node.entity.skill.Skills;
/**
* The styles of houses.
* @author Emperor
*
*/
public enum HousingStyle {
BASIC_WOOD (1, 5000, 7503, 0, 13100, 13101, 13098, Decoration.BASIC_WOOD_WINDOW),
BASIC_STONE (10, 5000, 7503, 1, 13094, 13096, 1902, Decoration.BASIC_STONE_WINDOW),
WHITEWASHED_STONE (20, 7500, 7503, 2, 13006, 13007, 1415, Decoration.WHITEWASHED_STONE_WINDOW),
FREMENNIK_STYLE_WOOD(30, 10000, 7503, 3, 13109, 13107, 13111, Decoration.FREMENNIK_WINDOW),
TROPICAL_WOOD (40, 15000, 7759, 0, 13016, 13015, 13011, Decoration.TROPICAL_WOOD_WINDOW),
FANCY_STONE (50, 25000, 7759, 1, 13119, 13118, 13116, Decoration.FANCY_STONE_WINDOW);
/**
* The level required.
*/
private final int levelRequirement;
/**
* The cost.
*/
private final int cost;
/**
* The region id.
*/
private final int regionId;
/**
* The plane.
*/
private final int plane;
/**
* The door id.
*/
private final int doorId;
/**
* The second door id.
*/
private final int secondDoorId;
/**
* The wall id.
*/
private final int wallId;
/**
* The window style
*/
private final Decoration window;
/**
* Checks if the player has the level.
*
* @param player the player.
* @return {@code True} if so.
*/
public boolean hasLevel(Player player) {
return player.getSkills().getStaticLevel(Skills.CONSTRUCTION) >= levelRequirement;
}
/**
* Constructs a new {@code HousingStyle} {@code Object}
* @param level The level required.
* @param cost The cost of the style.
* @param regionId The region id for this style.
* @param plane The plane for this style.
* @param doorId The door object id used in this style.
*/
private HousingStyle(int level, int cost, int regionId, int plane, int doorId, int secondDoorId, int wallId, Decoration window) {
this.levelRequirement = level;
this.cost = cost;
this.regionId = regionId;
this.plane = plane;
this.doorId = doorId;
this.secondDoorId = secondDoorId;
this.wallId = wallId;
this.window = window;
}
/**
* Gets the level.
* @return the level
*/
public int getLevel() {
return levelRequirement;
}
/**
* Gets the cost.
* @return the cost
*/
public int getCost() {
return cost;
}
/**
* Gets the regionId.
* @return the regionId
*/
public int getRegionId() {
return regionId;
}
/**
* Gets the plane.
* @return the plane
*/
public int getPlane() {
return plane;
}
/**
* Gets the door used in this style.
* @return The door object id.
*/
public int getDoorId() {
return doorId;
}
/**
* Gets the wall used in this style.
* @return The wall object id.
*/
public int getWallId() {
return wallId;
}
/**
* Gets the window id for this style of house
* @return The windows object id
*/
public Decoration getWindowStyle() {
return window;
}
/**
* Gets the secondDoorId value.
* @return The secondDoorId.
*/
public int getSecondDoorId() {
return secondDoorId;
}
}
@@ -0,0 +1,81 @@
package content.global.skill.construction;
import core.game.node.entity.player.Player;
import core.tools.RandomFunction;
/**
* Holds information of all nail types.
* @author Emperor
*
*/
public enum NailType {
BRONZE(4819, 5),
IRON(4820, 7),
STEEL(1539, 10),
MITHRIL(4822, 13),
ADAMANT(4823, 15),
RUNE(4824, 20)
;
/**
* The nail item id.
*/
private final int itemId;
/**
* The bend rate.
*/
private final int bendRate;
/**
* Constructs a new {@code NailType} {@code Object}.
* @param itemId The item id.
* @param bendRate The bending rate.
*/
private NailType(int itemId, int bendRate) {
this.itemId = itemId;
this.bendRate = bendRate;
}
/**
* Checks if the nail will bend.
* @return {@code True} if Random.nextInt(bendRate) equals 0.
*/
public boolean isBend() {
return RandomFunction.getRandom(bendRate) == 0;
}
/**
* Gets the nail type used by the player.
* @param player The player.
* @param amount The nails required.
* @return The nail type used, or null if the player didn't have the nails.
*/
public static NailType get(Player player, int amount) {
for (int i = values().length - 1; i >= 0; i--) {
NailType type = values()[i];
if (player.getInventory().contains(type.itemId, amount)) {
return type;
}
}
return null;
}
/**
* Gets the itemId value.
* @return The itemId.
*/
public int getItemId() {
return itemId;
}
/**
* Gets the bendRate value.
* @return The bendRate.
*/
public int getBendRate() {
return bendRate;
}
}
@@ -0,0 +1,165 @@
package content.global.skill.construction;
import static core.api.ContentAPIKt.*;
import core.cache.def.impl.SceneryDefinition;
import core.game.dialogue.DialogueInterpreter;
import core.game.dialogue.DialoguePlugin;
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.plugin.Initializable;
import core.plugin.Plugin;
import core.plugin.PluginManifest;
import core.plugin.PluginType;
import kotlin.Unit;
import core.game.world.repository.Repository;
import core.plugin.ClassScanner;
/**
* Handles the house portal options.
* @author Emperor
*
*/
@Initializable
public final class PortalOptionPlugin extends OptionHandler {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
for (HouseLocation hl : HouseLocation.values()) {
SceneryDefinition.forId(hl.getPortalId()).getHandlers().put("option:enter", this);
}
SceneryDefinition.forId(13405).getHandlers().put("option:lock", this);
SceneryDefinition.forId(13405).getHandlers().put("option:enter", this);
ClassScanner.definePlugin(new PortalDialogue());
return this;
}
@Override
public boolean handle(Player player, Node node, String option) {
Scenery object = node.asScenery();
if (object.getId() == 13405 && option.equals("enter")) {
HouseManager.leave(player);
return true;
}
if (option.equals("lock")) {
if (player.getHouseManager().isInHouse(player)) {
player.getHouseManager().setLocked(player.getHouseManager().isLocked() ? false : true);
player.sendMessage("Your house is now "+(player.getHouseManager().isLocked() ? "locked." : "unlocked." ));
return true;
}
player.sendMessage("This is not your house.");
return true;
}
player.setAttribute("con:portal", object.getId());
player.getDialogueInterpreter().open("con:portal");
return true;
}
/**
* Handles the portal dialogue.
* @author Emperor
*/
@PluginManifest(type= PluginType.DIALOGUE)
private class PortalDialogue extends DialoguePlugin {
/**
* Constructs a new {@code PortalDialogue} {@code Object}
*/
public PortalDialogue() {
}
/**
* Constructs a new {@code PortalDialogue} {@code Object}
* @param player The player.
*/
public PortalDialogue(Player player) {
super(player);
}
@Override
public DialoguePlugin newInstance(Player player) {
return new PortalDialogue(player);
}
@Override
public boolean open(Object... args) {
options("Go to your house", "Go to your house (building mode)", "Go to a friend's house", "Never mind");
stage = 1;
return true;
}
@Override
public boolean handle(int interfaceId, int buttonId) {
end();
switch (stage) {
case 1:
switch (buttonId) {
case 1:
case 2:
//If the player does not have a house
if (!player.getHouseManager().hasHouse()) {
player.getPacketDispatch().sendMessage("<col=FF0000>You don't have a house, talk to an estate agent to purchase a house.");
break;
}
//If the Player has a house, but does not have their house moved to the portal they are interacting with
if (player.getHouseManager().getLocation().getPortalId() != player.getAttribute("con:portal", -1)) {
player.getPacketDispatch().sendMessage("<col=FF0000>Your house is in " + player.getHouseManager().getLocation().getName() + ".");
player.sendMessage("<col=FF0000>Speak with an estate agent to change your house location.");
break;
}
player.getHouseManager().enter(player, buttonId == 2);
break;
case 3:
if(player.getIronmanManager().isIronman()){
end();
sendMessage(player, "You can't do that as an ironman.");
return true;
}
sendInputDialogue(player, false, "Enter friend's name:", (value) -> {
Player p = Repository.getPlayerByName((String) value);
if (p == null || !p.isActive()) {
player.getPacketDispatch().sendMessage("This player is not online.");
return Unit.INSTANCE;
}
if (p.getUsername().equals(player.getUsername())) {
player.getPacketDispatch().sendMessage("You aren't a friend of yourself!");
return Unit.INSTANCE;
}
if (!p.getHouseManager().isLoaded()) {
player.getPacketDispatch().sendMessage("This player is not at home right now.");
return Unit.INSTANCE;
}
if (p.getHouseManager().isBuildingMode()) {
player.getPacketDispatch().sendMessage("This player is in building mode.");
return Unit.INSTANCE;
}
if (p.getHouseManager().isLocked()) {
player.getPacketDispatch().sendMessage("The other player has locked their house.");
return Unit.INSTANCE;
}
p.setAttribute("poh_owner", (String) value);
p.getHouseManager().enter(player, false);
return Unit.INSTANCE;
});
break;
}
break;
}
return true;
}
@Override
public int[] getIds() {
return new int[] { DialogueInterpreter.getDialogueKey("con:portal") };
}
}
}
@@ -0,0 +1,102 @@
package content.global.skill.construction;
import core.game.dialogue.DialogueInterpreter;
import core.game.dialogue.DialoguePlugin;
import core.game.node.entity.player.Player;
import core.plugin.Initializable;
/**
* Removal dialogue for room & decorations in construction
* @author Clayton Williams
* @author Emperor
* @date Jun-30-2015
*/
@Initializable
public final class RemovalDialogue extends DialoguePlugin {
/**
* The room position.
*/
private int[] pos;
/**
* The plane.
*/
private int plane;
/**
* The room to remove.
*/
private Room room;
/**
* Removal Dialogue
*/
public RemovalDialogue() {
super();
}
/**
* Removal Dialogue
* @param player
*/
public RemovalDialogue(Player player) {
super(player);
}
@Override
public DialoguePlugin newInstance(Player player) {
return new RemovalDialogue(player);
}
@Override
public boolean open(Object... args) {
pos = (int[]) args[1];
plane = player.getLocation().getZ();
if (HouseManager.isInDungeon(player)) {
plane = 3;
}
room = player.getHouseManager().getRooms()[plane][pos[0]][pos[1]];
player.getDialogueInterpreter().sendOptions("Remove the " + (room != null ? room.getProperties().getName() : "room") + "?", "Yes", "No");
stage = 0;
return true;
}
@Override
public boolean handle(int interfaceId, int buttonId) {
if (stage == 0) {
if (buttonId == 1) {
if (plane == 0 && player.getHouseManager().hasRoomAt(1, pos[0], pos[1])) {
interpreter.sendPlainMessage(false, "You can't remove a room supporting another room.");
stage = 1;
return true;
}
if (room != null && room.getProperties().isLand()) {
Hotspot h = room.getHotspots()[0];
if (h != null && h.getDecorationIndex() == 0 && player.getHouseManager().getPortalAmount() <= 1) {
interpreter.sendPlainMessage(false, "You can't remove the garden with your portal in it.");
stage = 1;
return true;
}
}
player.getHouseManager().getRooms()[plane][pos[0]][pos[1]] = null;
for (int i = plane; i < 3; i++) {
Room r = player.getHouseManager().getRooms()[i][pos[0]][pos[1]];
if (r != null && r.getProperties().isRoof()) {
player.getHouseManager().getRooms()[i][pos[0]][pos[1]] = null;
}
}
player.getHouseManager().reload(player, true);
}
}
end();
return true;
}
@Override
public int[] getIds() {
return new int[]{ DialogueInterpreter.getDialogueKey("con:remove") };
}
}
@@ -0,0 +1,393 @@
package content.global.skill.construction;
import core.game.node.entity.player.Player;
import core.game.node.scenery.Scenery;
import core.game.node.scenery.SceneryBuilder;
import core.game.world.map.*;
/**
* Represents a room.
* @author Emperor
*
*/
public final class Room {
/**
* The default room type.
*/
public static final int CHAMBER = 0x0;
/**
* The rooftop room type.
*/
public static final int ROOF = 0x1;
/**
* The dungeon room type.
*/
public static final int DUNGEON = 0x2;
/**
* The dungeon room type.
*/
public static final int LAND = 0x4;
/**
* The room properties.
*/
private RoomProperties properties;
/**
* The region chunk.
*/
private RegionChunk chunk;
/**
* The hotspots.
*/
private Hotspot[] hotspots;
/**
* The current rotation of the room.
*/
private Direction rotation = Direction.NORTH;
/**
* Constructs a new {@code Room} {@code Object}.
* @param properties The room properties.
*/
public Room(RoomProperties properties) {
this.properties = properties;
}
/**
* Creates a new room.
* @param player The player.
* @param properties The room properties.
* @return The room.
*/
public static Room create(Player player, RoomProperties properties) {
Room room = new Room(properties);
room.configure(player.getHouseManager().getStyle());
return room;
}
/**
* Configures the room.
*/
public void configure(HousingStyle style) {
this.hotspots = new Hotspot[properties.getHotspots().length];
for (int i = 0; i < hotspots.length; i++) {
hotspots[i] = properties.getHotspots()[i].copy();
}
decorate(style);
}
/**
* Redecorates the room.
* @param style The house style.
*/
public void decorate(HousingStyle style) {
Region region = RegionManager.forId(style.getRegionId());
Region.load(region, true);
chunk = region.getPlanes()[style.getPlane()].getRegionChunk(properties.getChunkX(), properties.getChunkY());
}
/**
* Gets the hotspot object for the given hotspot type.
* @param hotspot The hotspot type.
* @return The hotspot.
*/
public Hotspot getHotspot(BuildHotspot hotspot) {
for (Hotspot h : hotspots) {
if (h.getHotspot() == hotspot) {
return h;
}
}
return null;
}
/**
* Checks if the building hotspot has been built.
* @param hotspot The building hotspot.
* @return {@code True} if so.
*/
public boolean isBuilt(BuildHotspot hotspot) {
Hotspot h = getHotspot(hotspot);
return h != null && h.getDecorationIndex() > -1;
}
/**
* Loads all the decorations.
* @param housePlane The plane.
* @param chunk The chunk used in the dynamic region.
*/
public void loadDecorations(int housePlane, BuildRegionChunk chunk, HouseManager house) {
for (int i = 0; i < hotspots.length; i++) {
Hotspot spot = hotspots[i];
int x = spot.getChunkX();
int y = spot.getChunkY();
if (spot.getHotspot() == null) {
continue;
}
int index = chunk.getIndex(x, y, spot.getHotspot().getObjectId(house.getStyle()));
Scenery[][] objects = chunk.getObjects(index);
Scenery object = objects[x][y];
if (object != null && object.getId() == spot.getHotspot().getObjectId(house.getStyle())) {
if (spot.getDecorationIndex() > -1 && spot.getDecorationIndex() < spot.getHotspot().getDecorations().length) {
int id = spot.getHotspot().getDecorations()[spot.getDecorationIndex()].getObjectId(house.getStyle());
if (spot.getHotspot().getType() == BuildHotspotType.CREST) {
id += house.getCrest().ordinal();
}
SceneryBuilder.replace(object, object.transform(id, object.getRotation(), chunk.getCurrentBase().transform(x, y, 0)));
}
else if (object.getId() == BuildHotspot.WINDOW.getObjectId(house.getStyle()) || (!house.isBuildingMode() && object.getId() == BuildHotspot.CHAPEL_WINDOW.getObjectId(house.getStyle()))) {
chunk.add(object.transform(house.getStyle().getWindowStyle().getObjectId(house.getStyle()), object.getRotation(), object.getType()));
}
int[] pos = RegionChunk.getRotatedPosition(x, y, object.getSizeX(), object.getSizeY(), 0, rotation.toInteger());
spot.setCurrentX(pos[0]);
spot.setCurrentY(pos[1]);
}
}
if (rotation != Direction.NORTH && chunk.getRotation() == 0) {
chunk.rotate(rotation);
}
if (!house.isBuildingMode()) {
removeHotspots(housePlane, house, chunk);
}
}
/**
* Removes the building hotspots from the room.
* @param housePlane The room's plane in house.
* @param house The house manager.
* @param chunk The region chunk used.
*/
private void removeHotspots(int housePlane, HouseManager house, BuildRegionChunk chunk) {
for (int i = 0; i < BuildRegionChunk.ARRAY_SIZE; i++) {
for (int x = 0; x < 8; x++) {
for (int y = 0; y < 8; y++) {
Scenery object = chunk.get(x, y, i);
if (object != null && object.getDefinition().hasAction("Build")) {
if (properties.isChamber() && BuildingUtils.isDoorHotspot(object)) {
if (!placeDoors(house, chunk, object, housePlane, x, y, rotation)) {
chunk.remove(object);
}
} else {
chunk.remove(object);
}
}
}
}
}
}
/**
* Places the doors when needed.
* @param chunk The chunk.
* @param object The object.
* @param x The x-coordinate of the object.
* @param y The y-coordinate of the object.
*/
private boolean placeDoors(HouseManager house, BuildRegionChunk chunk, Scenery object, int z, int x, int y, Direction rotation) {
int doorX;
int doorY;
switch (rotation) {
case EAST:
doorX = y;
doorY = 7 - x;
break;
case SOUTH:
doorX = 7 - x;
doorY = 7 - y;
break;
case WEST:
doorX = 7 - y;
doorY = x;
break;
default:
doorX = x;
doorY = y;
break;
}
int chunkX = chunk.getCurrentBase().getChunkX();
int chunkY = chunk.getCurrentBase().getChunkY();
boolean houseExit = true;
Room r;
if (doorX == 0 && chunkX > 0 && (r = house.getRooms()[z][chunkX - 1][chunkY]) != null && r.getProperties().isChamber()) {
houseExit = false;
}
else if (doorX == 7 && chunkX < 7 && (r = house.getRooms()[z][chunkX + 1][chunkY]) != null && r.getProperties().isChamber()) {
houseExit = false;
}
else if (doorY == 0 && chunkY > 0 && (r = house.getRooms()[z][chunkX][chunkY - 1]) != null && r.getProperties().isChamber()) {
houseExit = false;
}
else if (doorY == 7 && chunkY < 7 && (r = house.getRooms()[z][chunkX][chunkY + 1]) != null && r.getProperties().isChamber()) {
houseExit = false;
}
int replaceId = object.getId() % 2 != 0 ? house.getStyle().getDoorId() : house.getStyle().getSecondDoorId();
houseExit = false;
if (z != 0 && houseExit) {
r = house.getRooms()[z][chunkX][chunkY];
if (r.getProperties().isDungeon()) {
replaceId = 13065;
} else {
replaceId = house.getStyle().getWallId();
}
}
else if (!houseExit) {
return false;
}
return SceneryBuilder.replace(object, object.transform(replaceId, object.getRotation(), chunk.getCurrentBase().transform(x, y, 0)), true, true);
}
/**
* Sets the decoration index for a group of object ids
* @param index The index.
* @param hs The building hotspot.
*/
public void setAllDecorationIndex(int index, BuildHotspot hs) {
for (int i = 0; i < hotspots.length; i++) {
Hotspot h = hotspots[i];
if (h.getHotspot() == hs) {
h.setDecorationIndex(index);
}
}
}
/**
* Gets the stairs hotspot for this room (or null if no stairs are available).
* @return The stairs.
*/
public Hotspot getStairs() {
for (Hotspot h : hotspots) {
if (h.getHotspot().getType() == BuildHotspotType.STAIRCASE
|| h.getHotspot() == BuildHotspot.LADDER || h.getHotspot() == BuildHotspot.TRAPDOOR
|| (h.getHotspot() == BuildHotspot.CENTREPIECE_1 && h.getDecorationIndex() == 4)
|| (h.getHotspot() == BuildHotspot.CENTREPIECE_2 && h.getDecorationIndex() == 2)) {
return h;
}
}
return null;
}
/**
* Gets the exit directions
* @return The exits information.
*/
public boolean[] getExits() {
return getExits(rotation);
}
/**
* Gets the exit directions.
* @return The directions at which you can exit the room (0=east, 1=south, 2=west, 3=north).
*/
public boolean[] getExits(Direction rotation) {
boolean[] exits = properties.getExits();
if (chunk.getRotation() != rotation.toInteger()) {
boolean[] exit = new boolean[exits.length];
int offset = rotation.toInteger() - chunk.getRotation();
for (int i = 0; i < 4; i++) {
exit[(i + offset) % 4] = exits[i];
}
return exit;
}
return exits;
}
/**
* Gets the hotspot for the given coordinates.
* @param build The build hotspot.
* @param x The x-coordinate.
* @param y The y-coordinate.
* @return The hotspot.
*/
public Hotspot getHotspot(BuildHotspot build, int x, int y) {
for (int i = 0; i < getHotspots().length; i++) {
Hotspot h = getHotspots()[i];
if (h.getCurrentX() == x && h.getCurrentY() == y && h.getHotspot() == build) {
return h;
}
}
return null;
}
/**
* Sets the properties.
* @param properties The properties.
*/
public void updateProperties(Player player, RoomProperties properties) {
this.properties = properties;
decorate(player.getHouseManager().getStyle());
if (hotspots.length != properties.getHotspots().length) {
return;
}
for (int i = 0; i < hotspots.length; i++) {
Hotspot h = hotspots[i];
Hotspot hs = hotspots[i] = properties.getHotspots()[i].copy();
hs.setCurrentX(h.getCurrentX());
hs.setCurrentY(h.getCurrentY());
hs.setDecorationIndex(h.getDecorationIndex());
}
}
/**
* Gets the chunk.
* @return The chunk.
*/
public RegionChunk getChunk() {
return chunk;
}
/**
* Sets the chunk.
* @param chunk The chunk to set.
*/
public void setChunk(RegionChunk chunk) {
this.chunk = chunk;
}
/**
* Gets the hotspots.
* @return The hotspots.
*/
public Hotspot[] getHotspots() {
return hotspots;
}
/**
* Sets the hotspots.
* @param hotspots The hotspots to set.
*/
public void setHotspots(Hotspot[] hotspots) {
this.hotspots = hotspots;
}
/**
* Gets the properties.
* @return The properties.
*/
public RoomProperties getProperties() {
return properties;
}
/**
* Sets the room rotation.
* @param rotation The rotation.
*/
public void setRotation(Direction rotation) {
this.rotation = rotation;
}
/**
* Gets the rotation.
* @return The rotation.
*/
public Direction getRotation() {
return rotation;
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,34 @@
package content.global.skill.construction
import content.global.skill.construction.RoomProperties
class RoomTemplate(properties: RoomProperties) {
var hotspots: MutableList<Hotspot> = ArrayList<Hotspot>()
init {
for(property in properties.hotspots){
hotspots.add(Hotspot(property.hotspot,property.chunkX,property.chunkY,property.chunkX2,property.chunkY2))
}
}
fun rotate(clockwise: Boolean){
hotspots = hotspots.map{
if(!clockwise) {
val newChunkX = it.chunkY
val newChunkY = 7 - it.chunkX
val newChunkX2 = it.chunkY2
val newChunkY2 = 7 - it.chunkX2
Hotspot(it.hotspot,newChunkX,newChunkY,newChunkX2,newChunkY2)
} else {
val newChunkY = it.chunkX
val newChunkX = 7 - it.chunkY
val newChunkY2 = it.chunkX2
val newChunkX2 = 7 - it.chunkY2
Hotspot(it.hotspot,newChunkX,newChunkY,newChunkX2,newChunkY2)
}
}.toMutableList()
}
}
@@ -0,0 +1,150 @@
package content.global.skill.construction;
import core.game.node.entity.npc.NPC;
import core.game.node.item.Item;
import org.json.simple.JSONObject;
import java.nio.ByteBuffer;
/**
* Represents a player's servant.
* @author Emperor
*
*/
public final class Servant extends NPC {
/**
* The servant type.
*/
private final ServantType type;
/**
* The item the servant is carrying.
*/
private Item item;
/**
* The amount this servant has been used.
*/
private int uses;
/**
* If the servant is greeting players entering the house.
*/
private boolean greet;
/**
* Constructs a new {@code Servant} {@code Object}.
* @param type The servant type.
*/
public Servant(ServantType type) {
super(type.getId());
this.type = type;
}
/**
* Saves the servant details.
* @param buffer The buffer to write on.
*/
public void save(ByteBuffer buffer) {
buffer.put((byte) type.ordinal());
buffer.putShort((byte) uses);
if (item == null) {
buffer.putShort((short) -1);
} else {
buffer.putShort((short) item.getId());
buffer.putInt(item.getAmount());
}
buffer.put((byte) (greet ? 1 : 0));
}
/**
* Parses the servant from the buffer.
* @return The servant.
*/
public static Servant parse(JSONObject data){
int type = Integer.parseInt( data.get("type").toString());
Servant servant = new Servant(ServantType.values()[type]);
servant.uses = Integer.parseInt( data.get("uses").toString());
Object itemRaw = data.get("item");
if(itemRaw != null){
JSONObject item = (JSONObject) itemRaw;
servant.item = new Item(Integer.parseInt(item.get("id").toString()),Integer.parseInt(item.get("amount").toString()));
}
servant.greet = (boolean) data.get("greet");
return servant;
}
public static Servant parse(ByteBuffer buffer) {
int type = buffer.get();
if (type == -1) {
return null;
}
Servant servant = new Servant(ServantType.values()[type]);
servant.uses = buffer.getShort() & 0xFFFF;
int itemId = buffer.getShort() & 0xFFFF;
if ((short) itemId != -1) {
servant.item = new Item(itemId, buffer.getInt());
}
servant.greet = buffer.get() == 1;
return servant;
}
/**
* Gets the item value.
* @return The item.
*/
public Item getItem() {
return item;
}
/**
* Sets the item value.
* @param item The item to set.
*/
public void setItem(Item item) {
this.item = item;
}
/**
* Gets the uses value.
* @return The uses.
*/
public int getUses() {
return uses;
}
/**
* Sets the uses value.
* @param uses The uses to set.
*/
public void setUses(int uses) {
this.uses = uses;
}
/**
* Gets the greet value.
* @return The greet.
*/
public boolean isGreet() {
return greet;
}
/**
* Sets the greet value.
* @param greet The greet to set.
*/
public void setGreet(boolean greet) {
this.greet = greet;
}
/**
* Gets the type value.
* @return The type.
*/
public ServantType getType() {
return type;
}
}
@@ -0,0 +1,123 @@
package content.global.skill.construction;
import core.game.node.item.Item;
/**
* Represents a type of servant
* @author Splinter
* @version 1.1
*/
public enum ServantType {
NONE(-1, -1, -1, -1, -1),
RICK(4235, 500, 6, 20, 60),
MAID(4237, 1000, 10, 25, 50, new Item(2003)),
COOK(4239, 3000, 16, 30, 17, new Item(2301), new Item(712)),
BUTLER(4241, 5000, 20, 40, 12, new Item(1897), new Item(712)),
DEMON_BUTLER(4243, 10000, 26, 50, 7, new Item(2011))
;
/**
* The ID of the npc.
*/
private int npcId;
/**
* How much this servant costs.
*/
private int cost;
/**
* How much this servant is able to bring back.
*/
private int capacity;
/**
* The level the player must have before recruiting this servant.
*/
private int level;
/**
* How long it takes this servant to return from their duties.
*/
private int timer;
/**
* The food items the servant can cook.
*/
private Item[] food;
/**
* Constructor
*/
private ServantType(int npcId, int cost, int capacity, int level, int timer, Item... food) {
this.npcId = npcId;
this.cost = cost;
this.capacity = capacity;
this.level = level;
this.timer = timer;
this.food = food;
}
/**
* Gets a servant for the NPC id
* @param id The NPC id.
* @return The servant type.
*/
public static ServantType forId(int id){
for (ServantType s : ServantType.values()){
if (s.getId() == id){
return s;
}
}
return null;
}
/**
* Gets the NPC's id
* @return
*/
public int getId(){
return npcId;
}
/**
* Gets the initial cost
* @return
*/
public int getCost(){
return cost;
}
/**
* Gets the NPC's capacity
* @return
*/
public int getCapacity(){
return capacity;
}
/**
* Gets the level
* @return
*/
public int getLevel(){
return level;
}
/**
* Gets the timer
* @return
*/
public int getTimer(){
return timer;
}
/**
* Gets the food the servant can cook
* @return
*/
public Item[] getFood(){
return food;
}
}
@@ -0,0 +1,75 @@
package content.global.skill.construction.decoration;
import core.game.interaction.NodeUsageEvent;
import core.game.interaction.UseWithHandler;
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.Initializable;
import core.plugin.Plugin;
/**
* Handles the Construction beer barrels.
* @author Splinter
*/
@Initializable
public class BeerBarrelPlugin extends UseWithHandler {
/**
* The object ids
*/
private static final int[] OBJECTS = new int[] {
13568, 13569, 13570, 13571, 13572, 13573
};
/**
* Constructs a new {@Code BeerBarrelPlugin} {@Code Object}
*/
public BeerBarrelPlugin() {
super(1919);
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
for (int id : OBJECTS) {
addHandler(id, OBJECT_TYPE, this);
}
return this;
}
@Override
public boolean handle(NodeUsageEvent event) {
Player player = event.getPlayer();
final Scenery object = (Scenery) event.getUsedWith();
if (player.getInventory().remove(new Item(1919))) {
player.animate(Animation.create(833));
player.sendMessage("You fill up your glass.");
player.getInventory().add(new Item(getReward(object.getId()), 1));
}
return true;
}
/**
* Get the beer reward based on the interaced barrel.
* @return the item to give.
*/
public int getReward(int barrelId) {
switch (barrelId) {
case 13568:
return 1917;
case 13569:
return 5763;
case 13570:
return 1905;
case 13571:
return 1909;
case 13572:
return 1911;
case 13573:
return 5755;
}
return 1917;
}
}
@@ -0,0 +1,97 @@
package content.global.skill.construction.decoration;
import core.cache.def.impl.SceneryDefinition;
import content.global.skill.construction.Decoration;
import core.game.interaction.OptionHandler;
import core.game.node.Node;
import core.game.node.entity.impl.ForceMovement;
import core.game.node.entity.player.Player;
import core.game.node.scenery.Scenery;
import core.game.system.task.Pulse;
import core.game.world.update.flag.context.Animation;
import core.plugin.Initializable;
import core.plugin.Plugin;
/**
* Handles chair and bench options.
* @author Emperor
*
*/
@Initializable
public final class ChairBenchPlugin extends OptionHandler {
/**
* The decorations that can be seated on.
*/
private static final Object[][] CHAIRS = {
{Decoration.CRUDE_CHAIR, 4073, 4103},
{Decoration.WOODEN_CHAIR, 4075, 4103},
{Decoration.ROCKING_CHAIR, 4079, 4103},
{Decoration.OAK_CHAIR, 4081, 4103},
{Decoration.OAK_ARMCHAIR, 4083, 4103},
{Decoration.TEAK_ARMCHAIR, 4085, 4103},
{Decoration.MAHOGANY_ARMCHAIR, 4087, 4103},
{Decoration.BENCH_WOODEN, 4089, 4104},
{Decoration.BENCH_OAK, 4091, 4104},
{Decoration.BENCH_CARVED_OAK, 4093, 4104},
{Decoration.BENCH_TEAK, 4095, 4104},
{Decoration.BENCH_CARVED_TEAK, 4097, 4104},
{Decoration.BENCH_MAHOGANY, 4099, 4104},
{Decoration.BENCH_GILDED, 4101, 4104},
{Decoration.CARVED_TEAK_BENCH, 4097, 4104},
{Decoration.MAHOGANY_BENCH, 4099, 4104},
{Decoration.GILDED_BENCH, 4101, 4104},
{Decoration.OAK_THRONE, 4111, 4103},
{Decoration.TEAK_THRONE, 4112, 4103},
{Decoration.MAHOGANY_THRONE, 4113, 4103},
{Decoration.GILDED_THRONE, 4114, 4103},
{Decoration.SKELETON_THRONE, 4115, 4103},
{Decoration.CRYSTAL_THRONE, 4116, 4103},
{Decoration.DEMONIC_THRONE, 4117, 4103},
};
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
for (Object[] data : CHAIRS) {
SceneryDefinition.forId(((Decoration) data[0]).getObjectId()).getHandlers().put("option:sit-on", this);
}
return this;
}
@Override
public boolean handle(final Player player, Node node, String option) {
Scenery object = (Scenery) node;
int animId = -1;
int sitAnimId = -1;
for (Object[] data : CHAIRS) {
if (((Decoration) data[0]).getObjectId() == object.getId()) {
animId = (Integer) data[1];
sitAnimId = (Integer) data[2];
break;
}
}
if (object.getType() == 11) {
animId++;
}
final int animation = animId;
final int sitAnimation = sitAnimId;
ForceMovement.run(player, player.getLocation(), node.getLocation(), ForceMovement.WALK_ANIMATION, Animation.create(sitAnimation), object.getDirection().getOpposite(), ForceMovement.WALKING_SPEED, ForceMovement.WALKING_SPEED);
player.getLocks().lockInteractions(600000);
player.getPulseManager().run(new Pulse(2) {
@Override
public boolean pulse() {
player.animate(Animation.create(animation));
return false;
}
@Override
public void stop() {
super.stop();
player.getLocks().unlockInteraction();
player.animate(Animation.create(sitAnimation + 2));
}
});
return true;
}
}
@@ -0,0 +1,83 @@
package content.global.skill.construction.decoration
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.scenery.Scenery
import core.game.node.entity.player.Player
import content.global.skill.construction.BuildHotspot
import content.global.skill.construction.HousingStyle
import core.plugin.Initializable
import core.plugin.Plugin
/**
* Handles Construction related doors.
* @author Emperor
*/
@Initializable
class ConstructionDoorPlugin : OptionHandler() {
@Throws(Throwable::class)
override fun newInstance(arg: Any?): Plugin<Any> {
for (style in HousingStyle.values()) {
SceneryDefinition.forId(style.doorId).handlers["option:open"] = this
SceneryDefinition.forId(style.secondDoorId).handlers["option:open"] = this
}
for (deco in BuildHotspot.DUNGEON_DOOR_LEFT.decorations) {
SceneryDefinition.forId(deco.objectId).handlers["option:open"] = this
SceneryDefinition.forId(deco.objectId).handlers["option:pick-lock"] = this
SceneryDefinition.forId(deco.objectId).handlers["option:force"] = this
}
for (deco in BuildHotspot.DUNGEON_DOOR_RIGHT.decorations) {
SceneryDefinition.forId(deco.objectId).handlers["option:open"] = this
SceneryDefinition.forId(deco.objectId).handlers["option:pick-lock"] = this
SceneryDefinition.forId(deco.objectId).handlers["option:force"] = this
}
return this
}
override fun handle(player: Player, node: Node, option: String): Boolean {
val `object` = node as Scenery
val second = core.game.global.action.DoorActionHandler.getSecondDoor(`object`, player)
when (option) {
"pick-lock", "force" -> return false //TODO
}
core.game.global.action.DoorActionHandler.open(`object`, second, getReplaceId(`object`), getReplaceId(second), true, 500, false)
return true
}
/**
* Gets the replace id for the door.
* @param object The door.
* @return The replace object id.
*/
private fun getReplaceId(`object`: Scenery): Int {
for (data in REPLACEMENT) {
if (`object`.id == data[0]) {
return data[1]
}
}
return `object`.id + 6
}
companion object {
/**
* The replacement ids.
*/
val REPLACEMENT = arrayOf(
intArrayOf(13100, 13102),
intArrayOf(13101, 13103),
intArrayOf(13006, 13008),
intArrayOf(13007, 13008),
intArrayOf(13015, 13017),
intArrayOf(13016, 13018),
intArrayOf(13094, 13095),
intArrayOf(13096, 13097),
intArrayOf(13109, 13110),
intArrayOf(13107, 13108),
intArrayOf(13118, 13120),
intArrayOf(13119, 13121)
)
}
}
@@ -0,0 +1,63 @@
package content.global.skill.construction.decoration;
import core.cache.def.impl.SceneryDefinition;
import core.plugin.Initializable;
import core.game.node.entity.skill.Skills;
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.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;
/**
* Handles the various fireplaces that you may light in Construction.
* @author Splinter
* @author Emperor
*/
@Initializable
public final class FireplacePlugin extends OptionHandler {
/**
* The animation.
*/
private static final Animation ANIMATION = Animation.create(3658);
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
SceneryDefinition.forId(13609).getHandlers().put("option:light", this);
SceneryDefinition.forId(13611).getHandlers().put("option:light", this);
SceneryDefinition.forId(13613).getHandlers().put("option:light", this);
return this;
}
@Override
public boolean handle(final Player player, Node node, String option) {
if (!player.getInventory().contains(1511, 1) || !player.getInventory().contains(590, 1)) {
player.sendMessage("You need some logs and a tinderbox in order to light the fireplace.");
return true;
}
final Scenery obj = (Scenery) node.asScenery();
player.lock(2);
player.animate(ANIMATION);
GameWorld.getPulser().submit(new Pulse(2, player) {
@Override
public boolean pulse() {
if (!obj.isActive()) {
return true;
}
player.getInventory().remove(new Item(1511));
player.getSkills().addExperience(Skills.FIREMAKING, 80);
SceneryBuilder.replace(new Scenery(obj.getId(), obj.getLocation()), new Scenery(obj.getId() + 1, obj.getLocation(), obj.getRotation()), 1000);
player.sendMessage("You light the fireplace.");
return true;
}
});
return true;
}
}
@@ -0,0 +1,439 @@
package content.global.skill.construction.decoration;
import content.global.skill.construction.*;
import core.cache.def.impl.SceneryDefinition;
import core.game.dialogue.DialogueInterpreter;
import core.game.dialogue.DialoguePlugin;
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.system.task.Pulse;
import core.game.world.map.Direction;
import core.game.world.map.Location;
import core.plugin.Initializable;
import core.plugin.Plugin;
import core.game.world.GameWorld;
import core.plugin.ClassScanner;
/**
* Handles construction staircases.
* @author Emperor
*
*/
@Initializable
public final class StaircasePlugin extends OptionHandler {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ClassScanner.definePlugin(new BuildDialogue());
ClassScanner.definePlugin(new ClimbPohLadder());
for (int i = 13497; i < 13507; i++) {
SceneryDefinition.forId(i).getHandlers().put("option:climb", this);
SceneryDefinition.forId(i).getHandlers().put("option:climb-up", this);
SceneryDefinition.forId(i).getHandlers().put("option:climb-down", this);
SceneryDefinition.forId(i).getHandlers().put("option:remove-room", this);
}
SceneryDefinition.forId(13409).getHandlers().put("option:enter", this);
SceneryDefinition.forId(13409).getHandlers().put("option:remove-room", this);
for (int id = 13328; id < 13331; id++) {
SceneryDefinition.forId(id).getHandlers().put("option:climb", this);
SceneryDefinition.forId(id).getHandlers().put("option:remove-room", this);
}
for (int id = 13675; id <= 13680; id++) {
if (id < 13678) {
SceneryDefinition.forId(id).getHandlers().put("option:open", this);
} else {
SceneryDefinition.forId(id).getHandlers().put("option:go-down", this);
SceneryDefinition.forId(id).getHandlers().put("option:close", this);
}
SceneryDefinition.forId(id).getHandlers().put("option:remove-room", this);
}
return this;
}
@Override
public boolean handle(Player player, Node node, String option) {
HouseManager house = player.getAttribute("poh_entry", null);
if (house == null) {
player.getPacketDispatch().sendMessage("You're not in your house right now (REPORT).");
return true;
}
Scenery object = (Scenery) node;
switch (option) {
case "open":
SceneryBuilder.replace(object, object.transform(object.getId() + 3), 200);
return true;
case "close":
SceneryBuilder.replace(object, object.transform(object.getId() - 3));
return true;
case "remove-room":
if (player.getLocation().getZ() != 0) {
player.getPacketDispatch().sendMessage("The room below is supporting this room!");
return true;
}
return false;
case "climb":
if (house.getDungeonRegion() == player.getViewport().getRegion()) {
climb(player, 1, house, object);
return true;
}
if (object.getLocation().getZ() > 0) {
climb(player, -1, house, object);
return true;
}
player.getDialogueInterpreter().open("con:climbdial", house, object);
return true;
case "climb-up":
climb(player, 1, house, object);
return true;
case "enter":
case "climb-down":
case "go-down":
climb(player, -1, house, object);
return true;
}
return false;
}
/**
* Climbs the staircase.
* @param player The player.
* @param z The plane difference.
* @param house The house the player is currently in.
* @param object The object.
*/
private static void climb(Player player, int z, HouseManager house, Scenery object) {
Location l = player.getLocation();
int plane = l.getZ() + z;
int roomX = l.getChunkX();
int roomY = l.getChunkY();
Room current = house.getRooms()[l.getZ()][roomX][roomY];
if (plane < 0) { //Dungeon
plane = 3;
}
else if (player.getViewport().getRegion() == house.getDungeonRegion() && plane == 1) {//going up
plane = 0;
}
Room room = house.getRooms()[plane][roomX][roomY];
// boolean stairs = room != null && room.getStairs() != null || room.get;
if (room == null || room.getProperties().isRoof()) {
if (player.getHouseManager().isInHouse(player) && player.getHouseManager().isBuildingMode()) {
player.getDialogueInterpreter().open("con:nfroom", plane, roomX, roomY, current, object);
}
else {
player.getPacketDispatch().sendMessage("This doesn't seem to lead anywhere.");
}
} else {
Location destination = l.transform(0, 0, z);
if (player.getViewport().getRegion() == house.getDungeonRegion()) {
destination = house.getHouseRegion().getBaseLocation().transform(l.getLocalX(), l.getLocalY(), 0);
}
else if (plane == 3) {
destination = house.getDungeonRegion().getBaseLocation().transform(l.getLocalX(), l.getLocalY(), 0);
}
Room r = house.getRoom(destination);
Hotspot h = r.getStairs();
if (h != null && h.getDecorationIndex() > -1) {
player.getProperties().setTeleportLocation(destination);
} else {
player.getPacketDispatch().sendMessage("This doesn't seem to lead anywhere.");
}
}
}
/**
* Handles the climbing dialogue.
* @author Emperor
*/
static final class ClimbPohLadder extends DialoguePlugin {
/**
* Represents the object to use.
*/
private HouseManager house;
/**
* The ladder.
*/
private Scenery ladder;
/**
* Constructs a new {@code ClimbPohLadder} {@code Object}.
*/
public ClimbPohLadder() {
super();
}
/**
* Constructs a new {@code ClimbPohLadder} {@code Object}.
* @param player the player.
*/
public ClimbPohLadder(final Player player) {
super(player);
}
@Override
public DialoguePlugin newInstance(Player player) {
return new ClimbPohLadder(player);
}
@Override
public boolean open(Object... args) {
house = (HouseManager) args[0];
ladder = (Scenery) args[1];
interpreter.sendOptions("What would you like to do?", "Climb Up.", "Climb Down.");
stage = 0;
return true;
}
@Override
public boolean handle(int interfaceId, int buttonId) {
switch (stage) {
case 0:
switch (buttonId) {
case 1:
player.lock(1);
GameWorld.getPulser().submit(new Pulse(1) {
@Override
public boolean pulse() {
climb(player, 1, house, ladder);
return true;
}
});
end();
break;
case 2:
player.lock(1);
GameWorld.getPulser().submit(new Pulse(1) {
@Override
public boolean pulse() {
climb(player, -1, house, ladder);
return true;
}
});
end();
break;
}
break;
}
return true;
}
@Override
public int[] getIds() {
return new int[] { DialogueInterpreter.getDialogueKey("con:climbdial") };
}
}
/**
* Handles the creating a room on different floor dialogue.
* @author Emperor
*/
static final class BuildDialogue extends DialoguePlugin {
/**
* The plane of the room to build.
*/
private int plane;
/**
* The room x-coordinate.
*/
private int roomX;
/**
* The room y-coordinate.
*/
private int roomY;
/**
* The room we're building on.
*/
private Room room;
/**
* The stairs object.
*/
private Scenery stairs;
/**
* Constructs a new {@code BuildDialogue} {@code Object}.
*/
public BuildDialogue() {
/**
* empty.
*/
}
/**
* Constructs a new {@code BuildDialogue} {@code Object}.
* @param player the player.
*/
public BuildDialogue(final Player player) {
super(player);
}
@Override
public DialoguePlugin newInstance(Player player) {
return new BuildDialogue(player);
}
@Override
public boolean open(Object... args) {
plane = (Integer) args[0];
roomX = (Integer) args[1];
roomY = (Integer) args[2];
room = (Room) args[3];
stairs = (Scenery) args[4];
stage = 0;
if (stairs.getId() >= 13328 && stairs.getId() <= 13330) {
interpreter.sendPlainMessage(false, "These stairs don't seem to lead anywhere. Do you", "want to build a throne room upstairs?");
stage = 5;
return true;
}
if (plane == 3) {
if (room.getProperties() == RoomProperties.THRONE_ROOM) {
interpreter.sendPlainMessage(false, "These stairs don't seem to lead anywhere. Do you", "want to build an Oubilette?");
} else {
interpreter.sendPlainMessage(false, "These stairs don't seem to lead anywhere. Do you", "want to build a dungeon room?");
}
return true;
}
interpreter.sendPlainMessage(false, "These stairs don't seem to lead anywhere. Do you", "want to build a room at the top?");
return true;
}
@Override
public boolean handle(int interfaceId, int buttonId) {
boolean dungeon = plane == 3;
switch (stage) {
case 0:
interpreter.sendOptions("Select an option", "Yes", "No");
stage = 1;
break;
case 1:
switch (buttonId) {
case 1: //yes
if (room.getProperties() == RoomProperties.THRONE_ROOM) {
Room r = Room.create(player, RoomProperties.OUBILETTE);
Direction[] dirs = BuildingUtils.getAvailableRotations(player, r.getExits(), plane, roomX, roomY);
for (Direction d : dirs) {
if (d == room.getRotation()) {
r.setRotation(d);
Hotspot stairs = room.getStairs();
int index = stairs != null ? stairs.getDecorationIndex() : -1;
BuildingUtils.buildRoom(player, r, plane, roomX, roomY, r.getExits(), true);
r.getStairs().setDecorationIndex(index);
end();
return true;
}
}
interpreter.sendPlainMessage(false, "The room you're trying to build doesn't fit.");
stage = 4;
return true;
}
if (dungeon) {
interpreter.sendOptions("Select an option", "Skill Hall", "Quest Hall", "Dungeon Stairs");
} else {
interpreter.sendOptions("Select an option", "Skill Hall", "Quest Hall");
}
stage = 2;
return true;
}
end();
return true;
case 2:
if (dungeon && buttonId == 3) {
stage = 3;
return handle(interfaceId, 1);
}
RoomProperties props = buttonId == 2 ? RoomProperties.QUEST_HALL_2 : RoomProperties.SKILL_HALL_2;
if (plane == 3) {
props = buttonId == 2 ? RoomProperties.QUEST_HALL : RoomProperties.SKILL_HALL;
}
Room r = Room.create(player, props);
Direction[] dirs = BuildingUtils.getAvailableRotations(player, r.getExits(), plane, roomX, roomY);
for (Direction d : dirs) {
if (d == room.getRotation()) {
r.setRotation(d);
Hotspot stairs = room.getStairs();
int index = stairs != null ? stairs.getDecorationIndex() : -1;
r.getStairs().setDecorationIndex(index);
BuildingUtils.buildRoom(player, r, plane, roomX, roomY, r.getExits(), true);
end();
return true;
}
}
interpreter.sendPlainMessage(false, "The room you're trying to build doesn't seem to fit.");
stage = 4;
return true;
case 3:
switch (buttonId) {
case 1: //yes
r = Room.create(player, RoomProperties.DUNGEON_STAIRS);
dirs = BuildingUtils.getAvailableRotations(player, r.getExits(), plane, roomX, roomY);
for (Direction d : dirs) {
if (d == room.getRotation()) {
r.setRotation(d);
Hotspot stairs = room.getStairs();
int index = stairs != null ? stairs.getDecorationIndex() : -1;
BuildingUtils.buildRoom(player, r, plane, roomX, roomY, r.getExits(), true);
r.getStairs().setDecorationIndex(index);
end();
return true;
}
}
interpreter.sendPlainMessage(false, "The room you're trying to build doesn't fit.");
stage = 4;
return true;
case 2:
end();
return true;
}
return true;
case 4:
end();
return true;
case 5:
interpreter.sendOptions("Select an option", "Yes", "No");
stage = 6;
return true;
case 6:
switch (buttonId) {
case 1: //yes
r = Room.create(player, RoomProperties.THRONE_ROOM);
dirs = BuildingUtils.getAvailableRotations(player, r.getExits(), plane, roomX, roomY);
for (Direction d : dirs) {
if (d == room.getRotation()) {
r.setRotation(d);
Hotspot stairs = room.getStairs();
int index = stairs != null ? stairs.getDecorationIndex() : -1;
BuildingUtils.buildRoom(player, r, plane, roomX, roomY, r.getExits(), true);
r.getStairs().setDecorationIndex(index);
end();
return true;
}
}
interpreter.sendPlainMessage(false, "The room you're trying to build doesn't fit.");
stage = 4;
return true;
case 2:
end();
return true;
}
return true;
}
return true;
}
@Override
public int[] getIds() {
return new int[] { DialogueInterpreter.getDialogueKey("con:nfroom") };
}
}
}
@@ -0,0 +1,52 @@
package content.global.skill.construction.decoration.bedroom;
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.scenery.Scenery;
import core.plugin.Initializable;
import core.plugin.Plugin;
import java.text.SimpleDateFormat;
import java.util.Calendar;
/**
* ClockPlugin.java
* @author Clayton Williams (hope)
* @date Oct 26, 2015
*/
@Initializable
public class ClockPlugin extends OptionHandler {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
SceneryDefinition.forId(13169).getHandlers().put("option:read", this);
SceneryDefinition.forId(13170).getHandlers().put("option:read", this);
SceneryDefinition.forId(13171).getHandlers().put("option:read", this);
return this;
}
@Override
public boolean handle(Player player, Node node, String option) {
Scenery object = node.asScenery();
SimpleDateFormat format = new SimpleDateFormat("mm");
int minuteDisplay = Integer.parseInt(format.format(Calendar.getInstance().getTime()));
StringBuilder sb = new StringBuilder("It's ");
if (minuteDisplay == 0) {
sb.append("Rune o'clock.");
} else if (minuteDisplay == 15) {
sb.append("a quarter past Rune.");
} else if (minuteDisplay > 0 && minuteDisplay < 30) {
sb.append(minuteDisplay + " past Rune.");
} else if (minuteDisplay == 45) {
sb.append("a quarter till Rune.");
} else {
sb.append((60 - minuteDisplay) + " till Rune.");
}
player.getDialogueInterpreter().sendItemMessage(object.getId() - 5117, sb.toString());
return true;
}
}
@@ -0,0 +1,31 @@
package content.global.skill.construction.decoration.bedroom
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.plugin.Initializable
import core.plugin.Plugin
@Initializable
class ShavingStandHandler : OptionHandler() {
override fun newInstance(arg: Any?): Plugin<Any> {
SceneryDefinition.forId(13162).handlers["option:preen"] = this
SceneryDefinition.forId(13163).handlers["option:preen"] = this
SceneryDefinition.forId(13168).handlers["option:preen"] = this
return this
}
override fun handle(player: Player?, node: Node?, option: String?): Boolean {
player ?: return false
node ?: return false
if(player.appearance.isMale){
player.interfaceManager.open(Component(596))
} else {
player.interfaceManager.open(Component(592))
}
return true
}
}
@@ -0,0 +1,31 @@
package content.global.skill.construction.decoration.bedroom
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.plugin.Initializable
import core.plugin.Plugin
@Initializable
class WardrobeHandler : OptionHandler() {
override fun newInstance(arg: Any?): Plugin<Any> {
SceneryDefinition.forId(13155).handlers["option:change-clothes"] = this
SceneryDefinition.forId(13156).handlers["option:change-clothes"] = this
SceneryDefinition.forId(13161).handlers["option:change-clothes"] = this
return this
}
override fun handle(player: Player?, node: Node?, option: String?): Boolean {
player ?: return false
node ?: return false
if(player.appearance.isMale){
player.interfaceManager.open(Component(591))
} else {
player.interfaceManager.open(Component(594))
}
return true;
}
}
@@ -0,0 +1,181 @@
package content.global.skill.construction.decoration.chapel;
import static core.api.ContentAPIKt.*;
import core.cache.def.impl.SceneryDefinition;
import content.global.skill.prayer.Bones;
import core.game.node.entity.skill.Skills;
import core.game.interaction.NodeUsageEvent;
import core.game.interaction.UseWithHandler;
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.node.scenery.Scenery;
import core.game.system.task.Pulse;
import core.game.world.map.Location;
import core.game.world.map.RegionManager;
import core.game.world.update.flag.context.Animation;
import core.game.world.update.flag.context.Graphics;
import core.plugin.Initializable;
import core.plugin.Plugin;
/**
* Handles the offering of bones on an altar.
* @author Splinter
*/
@Initializable
public class BoneOfferPlugin extends UseWithHandler {
/**
* The offer GFX.
*/
private final Graphics GFX = new Graphics(624);
/**
* The offer Animation.
*/
private final Animation ANIM = new Animation(896);
/**
* Constructor.
*/
public BoneOfferPlugin() {
super(526, 2859, 528, 3183, 3179, 530, 532, 3125, 4812, 3123, 534, 6812, 536, 4830, 4832, 6729, 4834, 14693);
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
addHandler(13185, OBJECT_TYPE, this);
addHandler(13188, OBJECT_TYPE, this);
addHandler(13191, OBJECT_TYPE, this);
addHandler(13194, OBJECT_TYPE, this);
addHandler(13197, OBJECT_TYPE, this);
return this;
}
@Override
public boolean handle(NodeUsageEvent event) {
Player player = event.getPlayer();
Scenery left = null;
Scenery right = null;
if (event.getUsedWith().asScenery().getRotation() % 2 == 0) {
left = RegionManager.getObject(event.getUsedWith().getLocation().getZ(), event.getUsedWith().getLocation().getX() + 3, event.getUsedWith().getLocation().getY());
right = RegionManager.getObject(event.getUsedWith().getLocation().getZ(), event.getUsedWith().getLocation().getX() - 2, event.getUsedWith().getLocation().getY());
} else {
left = RegionManager.getObject(event.getUsedWith().getLocation().getZ(), event.getUsedWith().getLocation().getX(), event.getUsedWith().getLocation().getY() + 3);
right = RegionManager.getObject(event.getUsedWith().getLocation().getZ(), event.getUsedWith().getLocation().getX(), event.getUsedWith().getLocation().getY() - 2);
}
Bones b = Bones.forId(event.getUsedItem().getId());
if (b != null) {
worship(player, event.getUsedWith().asScenery(), left, right, b);
}
return true;
}
/**
* Worships the altar.
* @param player the player
* @param altar the altar object
* @param left the left brazier
* @param right the right brazier
* @param b the bone used
*/
private void worship(final Player player, final Scenery altar, final Scenery left, final Scenery right, final Bones b) {
if (player.getIronmanManager().isIronman() && !player.getHouseManager().isInHouse(player)) {
player.sendMessage("You cannot do this on someone else's altar.");
return;
}
final Location start = player.getLocation();
Location gfxLoc = player.getLocation().transform(player.getDirection(), 1);
submitIndividualPulse(player, new Pulse(1) {
int counter = 0;
@Override
public boolean pulse() {
counter++;
if (counter == 1 || counter % 5 == 0) {
if (player.getInventory().remove(new Item(b.getItemId()))) {
player.animate(ANIM);
player.getAudioManager().send(new Audio(958));
player.getPacketDispatch().sendPositionedGraphics(GFX, gfxLoc);
player.sendMessage(getMessage(isLit(left), isLit(right)));
player.getSkills().addExperience(Skills.PRAYER, b.getExperience() * getMod(altar, isLit(left), isLit(right)));
}
}
return !player.getLocation().equals(start) || !player.getInventory().containsItem(new Item(b.getItemId()));
}
});
}
/**
* Checks if the burner is lit.
* @param obj the object.
*/
private boolean isLit(Scenery obj) {
return obj != null && obj.getId() != 15271 && SceneryDefinition.forId(obj.getId()).getOptions() != null && !SceneryDefinition.forId(obj.getId()).hasAction("Light");
}
/**
* Gets the base modifier of the altar.
* @param altar the altar object
* @return the base bonus.
*/
private double getBase(Scenery altar) {
double base = 150.0;
if (altar == null) {
return base;
}
switch (altar.getId()) {
case 13182:
base = 110.0;
break;
case 13185:
base = 125.0;
break;
case 13188:
base = 150.0;
break;
case 13191:
base = 175.0;
break;
case 13194:
base = 200.0;
break;
case 13197:
base = 250.0;
break;
}
return base;
}
/**
* Gets the total experience modifier.
* @param isLeft if the left is lit.
* @param isRight if the right is lit.
* @return the mod.
*/
private double getMod(Scenery altar, boolean isLeft, boolean isRight) {
double total = getBase(altar);
if (isLeft) {
total += 50.0;
}
if (isRight) {
total += 50.0;
}
return (total / 100);
}
/**
* Gets the proper message.
* @return the message.
*/
private String getMessage(boolean isLeft, boolean isRight) {
return isLeft && isRight ? "The gods are very pleased with your offering." : isLeft || isRight ? "The gods are pleased with your offering." : "The gods accept your offering.";
}
}
@@ -0,0 +1,44 @@
package content.global.skill.construction.decoration.chapel
import core.game.node.scenery.Scenery
import core.game.node.scenery.SceneryBuilder
import core.game.node.item.Item
import core.game.world.update.flag.context.Animation
import core.tools.RandomFunction
import core.game.interaction.InteractionListener
import core.game.interaction.IntType
/**
* Handles the lighting of the torches of the Chapel.
* @author Splinter
*/
class BurnerListener : InteractionListener {
val IDs = intArrayOf(13202,13203,13204,13205,13206,13207,13208,13209,13210,13211,13212,13213)
override fun defineListeners() {
on(IDs, IntType.SCENERY, "light"){ player, node ->
if (player.ironmanManager.checkRestriction() && !player.houseManager.isInHouse(player)) {
return@on true
}
if (!player.inventory.containsItem(Item(590)) || !player.inventory.containsItem(Item(251))) {
player.dialogueInterpreter.sendDialogue(
"You'll need a tinderbox and a clean marrentill herb in order to",
"light the burner."
)
return@on true
}
if (player.inventory.remove(Item(251))) {
player.lock(1)
player.animate(Animation.create(3687))
player.sendMessage("You burn some marrentill in the incense burner.")
SceneryBuilder.replace(
node.asScenery(),
Scenery(node.asScenery().id + 1, node.location),
RandomFunction.random(100, 175)
)
}
return@on true
}
}
}
@@ -0,0 +1,47 @@
package content.global.skill.construction.decoration.chapel
import core.game.interaction.NodeUsageEvent
import core.game.interaction.UseWithHandler
import core.game.node.entity.player.link.audio.Audio
import core.game.node.entity.skill.Skills
import core.game.node.item.Item
import core.game.world.update.flag.context.Animation
import core.plugin.Initializable
import core.plugin.Plugin
import org.rs09.consts.Items
const val HOLY_ELIXER = 13754
const val SPIRIT_SHIELD = 13734
@Initializable
/**
* Blesses shields
* @author Ceikry
*/
class ShieldBlessingPlugin : UseWithHandler(HOLY_ELIXER, SPIRIT_SHIELD) {
override fun newInstance(arg: Any?): Plugin<Any> {
for(i in arrayOf(13185, 13188, 13191, 13194, 13197)){
addHandler(i, OBJECT_TYPE,this)
}
return this
}
override fun handle(event: NodeUsageEvent?): Boolean {
val player = event?.player
player ?: return false
if (player.ironmanManager.isIronman && !player.houseManager.isInHouse(player)) {
player.sendMessage("You cannot do this on someone else's altar.")
return true
}
if(player.skills.getLevel(Skills.PRAYER) < 85){
player.sendMessage("You need 85 prayer to do this.")
return true
}
player.animator.animate(Animation(896))
player.audioManager.send(Audio(958))
if(player.inventory.remove(Item(HOLY_ELIXER)) && player.inventory.remove(Item(SPIRIT_SHIELD)))
player.inventory.add(Item(Items.BLESSED_SPIRIT_SHIELD_13736))
return true
}
}
@@ -0,0 +1,32 @@
package content.global.skill.construction.decoration.combatroom;
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;
/**
* Handles the combat ring.
* @author Emperor
*
*/
@Initializable
public final class CombatRing extends OptionHandler {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
SceneryDefinition.forId(13129).getHandlers().put("option:climb-over", this); //Boxing ring
SceneryDefinition.forId(13133).getHandlers().put("option:climb-over", this); //Fencing ring
SceneryDefinition.forId(13137).getHandlers().put("option:climb-over", this); //Combat ring
return this;
}
@Override
public boolean handle(Player player, Node node, String option) {
return false;
}
}
@@ -0,0 +1,29 @@
package content.global.skill.construction.decoration.costume
import core.cache.def.impl.SceneryDefinition
import core.game.interaction.OptionHandler
import content.global.handlers.item.toys.DiangoReclaimInterface
import core.game.node.Node
import core.game.node.entity.player.Player
import core.plugin.Initializable
import core.plugin.Plugin
/**
* Handles the Toy Box POH
* ToyBoxPlugin.java
* @author Lee
* @date 10/2/2017
*/
@Initializable
class ToyBoxPlugin : OptionHandler() {
@Throws(Throwable::class)
override fun newInstance(arg: Any?): Plugin<Any?> {
SceneryDefinition.forId(18802).handlers["option:open"] = this
return this
}
override fun handle(player: Player, node: Node, option: String): Boolean {
DiangoReclaimInterface.open(player)
return true
}
}
@@ -0,0 +1,76 @@
package content.global.skill.construction.decoration.kitchen;
import core.game.interaction.NodeUsageEvent;
import core.game.interaction.UseWithHandler;
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.Initializable;
import core.plugin.Plugin;
/**
* Handles the Construction beer barrels.
* @author Splinter
*/
@Initializable
public class BeerBarrelPlugin extends UseWithHandler {
/**
* The object ids
*/
private static final int[] OBJECTS = new int[] {
13568, 13569, 13570, 13571, 13572, 13573
};
/**
* Constructs a new {@Code BeerBarrelPlugin} {@Code Object}
*/
public BeerBarrelPlugin() {
super(1919);
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
for (int id : OBJECTS) {
addHandler(id, OBJECT_TYPE, this);
}
return this;
}
@Override
public boolean handle(NodeUsageEvent event) {
Player player = event.getPlayer();
final Scenery object = (Scenery) event.getUsedWith();
if (player.getInventory().remove(new Item(1919))) {
player.animate(Animation.create(3661 + (object.getId() - 13569)));
player.sendMessage("You fill up your glass with " + object.getName().toLowerCase().replace("barrel", "").trim() + ".");
player.getInventory().add(new Item(getReward(object.getId()), 1));
}
return true;
}
/**
* Get the beer reward based on the interacted barrel.
* @return the item to give.
*/
public int getReward(int barrelId) {
switch (barrelId) {
case 13568:
return 1917;
case 13569:
return 5763;
case 13570:
return 1905;
case 13571:
return 1909;
case 13572:
return 1911;
case 13573:
return 5755;
}
return 1917;
}
}
@@ -0,0 +1,148 @@
package content.global.skill.construction.decoration.kitchen;
import core.cache.def.impl.SceneryDefinition;
import core.plugin.Initializable;
import core.game.dialogue.DialoguePlugin;
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.Plugin;
import core.plugin.ClassScanner;
/**
* Handles the interactions for the three Larders.
* @author Splinter
*/
@Initializable
public final class LarderPlugin extends OptionHandler {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ClassScanner.definePlugin(new LarderDialogue());
SceneryDefinition.forId(13565).getHandlers().put("option:search", this);
SceneryDefinition.forId(13566).getHandlers().put("option:search", this);
SceneryDefinition.forId(13567).getHandlers().put("option:search", this);
return this;
}
@Override
public boolean handle(Player player, Node node, String option) {
player.getDialogueInterpreter().open(42048, node.getId());
return true;
}
/**
* Dialogue options for the Larders.
* @author Splinter
* @version 1.0
*/
public final class LarderDialogue extends DialoguePlugin {
/**
* Constructs a new {@code LarderDialogue} {@code Object}.
*/
public LarderDialogue() {
/**
* empty.
*/
}
/**
* Constructs a new {@code LarderDialogue} {@code Object}.
*
* @param player
* the player.
*/
public LarderDialogue(Player player) {
super(player);
}
@Override
public DialoguePlugin newInstance(Player player) {
return new LarderDialogue(player);
}
@Override
public boolean open(Object... args) {
int id = (int) args[0];
switch (id) {
case 13565:
interpreter.sendOptions("Select an Option", "Tea Leaves", "Bucket of Milk");
stage = 1;
break;
case 13566:
interpreter.sendOptions("Select an Option", "Tea Leaves", "Bucket of Milk", "Eggs", "Pot of Flour");
stage = 1;
break;
case 13567:
interpreter.sendOptions("Select an Option", "Tea Leaves", "Bucket of Milk", "Eggs", "Pot of Flour", "More Options");
stage = 1;
break;
}
return true;
}
@Override
public boolean handle(int interfaceId, int buttonId) {
if (player.getInventory().freeSlots() < 1) {
player.sendMessage("You need at least one free inventory space to take from the larder.");
end();
return true;
}
switch (stage) {
case 1:
switch (buttonId) {
case 1:
player.getInventory().add(new Item(7738, 1));
end();
break;
case 2:
player.getInventory().add(new Item(1927, 1));
end();
break;
case 3:
player.getInventory().add(new Item(1944, 1));
end();
break;
case 4:
player.getInventory().add(new Item(1933, 1));
end();
break;
case 5:
player.getDialogueInterpreter().sendOptions(
"Select an Option", "Potatoes", "Garlic", "Onions", "Cheese");
stage = 2;
break;
}
break;
case 2:
switch (buttonId) {
case 1:
player.getInventory().add(new Item(1942, 1));
end();
break;
case 2:
player.getInventory().add(new Item(1550, 1));
end();
break;
case 3:
player.getInventory().add(new Item(1957, 1));
end();
break;
case 4:
player.getInventory().add(new Item(1985, 1));
end();
break;
}
}
return true;
}
@Override
public int[] getIds() {
return new int[] { 42048 };
}
}
}
@@ -0,0 +1,238 @@
package content.global.skill.construction.decoration.kitchen;
import core.cache.def.impl.SceneryDefinition;
import core.game.dialogue.DialoguePlugin;
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;
import core.plugin.ClassScanner;
/**
* Handles the shelves in the kitchen room.
* @author Splinter
*/
@Initializable
public final class ShelfPlugin extends OptionHandler {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ClassScanner.definePlugin(new ShelfDialogue());
for (int i = 13545; i < 13552; i++) {
SceneryDefinition.forId(i).getHandlers().put("option:search", this);
}
return this;
}
@Override
public boolean handle(Player player, Node node, String option) {
player.getDialogueInterpreter().open(778341, node.getId());
return true;
}
/**
* Dialogue options for the shelves, what a mess!
* @author Splinter
* @version 1.0
*/
public final class ShelfDialogue extends DialoguePlugin {
/**
* Constructs a new {@code ShelfDialogue} {@code Object}.
*/
public ShelfDialogue() {
/**
* empty.
*/
}
/**
* Constructs a new {@code ShelfDialogue} {@code Object}.
* @param player the player.
*/
public ShelfDialogue(Player player) {
super(player);
}
@Override
public DialoguePlugin newInstance(Player player) {
return new ShelfDialogue(player);
}
@Override
public boolean open(Object... args) {
int id = (int) args[0];
switch (id) {
case 13545:// wood 1
interpreter.sendOptions("Select an Option", "Kettle", "Teapot", "Clay cup");
stage = 1;
break;
case 13546:// wood 2
interpreter.sendOptions("Select an Option", "Kettle", "Teapot", "Clay cup", "Empty beer glass");
stage = 1;
break;
case 13547:// wood 3
interpreter.sendOptions("Select an Option", "Kettle", "Teapot", "Clay cup", "Empty beer glass", "Cake tin");
stage = 1;
break;
case 13548:// oak 1
interpreter.sendOptions("Select an Option", "Kettle", "Teapot", "Clay cup", "Empty beer glass", "Bowl");
stage = 2;
break;
case 13549:// oak 2
interpreter.sendOptions("Select an Option", "Kettle", "Teapot", "Porcelain cup", "Empty beer glass", "More Options");
stage = 3;
break;
case 13550:// teak 1
case 13551:
interpreter.sendOptions("Select an Option", "Kettle", "Teapot", "Porcelain cup", "Empty beer glass", "More Options");
stage = 5;
break;
}
return true;
}
@Override
public boolean handle(int interfaceId, int buttonId) {
if (player.getInventory().freeSlots() < 1) {
player.sendMessage("You need at least one free inventory space to take from the shelves.");
end();
return true;
}
switch (stage) {
case 1:// all wood shelves
switch (buttonId) {
case 1:
end();
player.getInventory().add(new Item(7688, 1));
break;
case 2:
end();
player.getInventory().add(new Item(7702, 1));
break;
case 3:
end();
player.getInventory().add(new Item(7728, 1));
break;
case 4:
end();
player.getInventory().add(new Item(1919, 1));
break;
case 5:
end();
player.getInventory().add(new Item(1887, 1));
break;
}
break;
case 2:// Oak shelf #1
switch (buttonId) {
case 1:
end();
player.getInventory().add(new Item(7688, 1));
break;
case 2:
end();
player.getInventory().add(new Item(7702, 1));
break;
case 3:
end();
player.getInventory().add(new Item(7728, 1));
break;
case 4:
end();
player.getInventory().add(new Item(1919, 1));
break;
case 5:
end();
player.getInventory().add(new Item(1923, 1));
break;
}
break;
case 3:// Oak shelves #2 only
switch (buttonId) {
case 1:
end();
player.getInventory().add(new Item(7688, 1));
break;
case 2:
end();
player.getInventory().add(new Item(7702, 1));
break;
case 3:
end();
player.getInventory().add(new Item(4244, 1));
break;
case 4:
end();
player.getInventory().add(new Item(1919, 1));
break;
case 5:
interpreter.sendOptions("Select an Option", "Bowl", "Cake tin");
stage = 4;
break;
}
break;
case 4:// Oak shelves #2 only
switch (buttonId) {
case 1:
end();
player.getInventory().add(new Item(1923, 1));
break;
case 2:
end();
player.getInventory().add(new Item(1887, 1));
break;
}
case 5:// teak shelves
switch (buttonId) {
case 1:
end();
player.getInventory().add(new Item(7688, 1));
break;
case 2:
end();
player.getInventory().add(new Item(7702, 1));
break;
case 3:
end();
player.getInventory().add(new Item(7735, 1));
break;
case 4:
end();
player.getInventory().add(new Item(1919, 1));
break;
case 5:
interpreter.sendOptions("Select an Option", "Bowl", "Pie dish", "Empty pot");
stage = 6;
break;
}
break;
case 6:// teak shelves
switch (buttonId) {
case 1:
end();
player.getInventory().add(new Item(1923, 1));
break;
case 2:
end();
player.getInventory().add(new Item(2313, 1));
break;
case 3:
end();
player.getInventory().add(new Item(1931, 1));
break;
}
break;
}
return true;
}
@Override
public int[] getIds() {
return new int[] { 778341 };
}
}
}
@@ -0,0 +1,51 @@
package content.global.skill.construction.decoration.portalchamber
import core.game.dialogue.DialoguePlugin
import core.game.node.entity.player.Player
import content.global.skill.construction.decoration.portalchamber.PortalChamberPlugin
import core.plugin.Initializable
/**
* Portal Chamber Dialogue go brrrrrr
* @author Ceikry
*/
@Initializable
class PortalChamberDialogue(player: Player? = null) : core.game.dialogue.DialoguePlugin(player) {
var portal = "none"
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
when(stage){
0 -> when(buttonId){
1 -> directPortal("varrock")
2 -> directPortal("lumbridge")
3 -> directPortal("falador")
4 -> options("Camelot Portal","Ardougne Portal","Yanille Portal","Kharyll Portal").also { stage++ }
}
1 -> when(buttonId){
1 -> directPortal("camelot")
2 -> directPortal("ardougne")
3 -> directPortal("yanille")
4 -> directPortal("kharyrll")
}
}
return true
}
fun directPortal(portal: String){
PortalChamberPlugin.direct(player,portal.toUpperCase())
end()
}
override fun open(vararg args: Any?): Boolean {
player.dialogueInterpreter.sendOptions("Select one.","Varrock Portal","Lumbridge Portal","Falador Portal","More...")
stage = 0
return true
}
override fun newInstance(player: Player?): core.game.dialogue.DialoguePlugin {
return PortalChamberDialogue(player)
}
override fun getIds(): IntArray {
return intArrayOf(394857)
}
}
@@ -0,0 +1,258 @@
package content.global.skill.construction.decoration.portalchamber;
import content.global.skill.construction.Hotspot;
import content.global.skill.runecrafting.Rune;
import core.cache.def.impl.SceneryDefinition;
import core.game.dialogue.DialogueInterpreter;
import core.game.dialogue.DialoguePlugin;
import core.game.interaction.OptionHandler;
import core.game.node.Node;
import core.game.node.entity.player.Player;
import content.global.skill.construction.Decoration;
import core.game.node.item.Item;
import core.game.node.scenery.Scenery;
import core.game.world.map.Location;
import core.plugin.Initializable;
import core.plugin.Plugin;
import core.plugin.ClassScanner;
/**
* PortalChamberPlugin
* @author Clayton Williams
* @date Jan 2, 2016
*/
@Initializable
public class PortalChamberPlugin extends OptionHandler {
/**
* Locations
* @author Clayton Williams
* @date Jan 3, 2016
*/
private static enum Locations {
VARROCK(Location.create(3213, 3428, 0), new Item(Rune.FIRE.getRune().getId(), 100), new Item(Rune.AIR.getRune().getId(), 300), new Item(Rune.LAW.getRune().getId(), 100)),
LUMBRIDGE(Location.create(3222, 3217, 0), new Item(Rune.EARTH.getRune().getId(), 100), new Item(Rune.AIR.getRune().getId(), 300), new Item(Rune.LAW.getRune().getId(), 100)),
FALADOR(Location.create(2965, 3380, 0), new Item(Rune.WATER.getRune().getId(), 100), new Item(Rune.AIR.getRune().getId(), 300), new Item(Rune.LAW.getRune().getId(), 100)),
CAMELOT(Location.create(2730, 3485, 0), new Item(Rune.AIR.getRune().getId(), 500), new Item(Rune.LAW.getRune().getId(), 100)),
ARDOUGNE(Location.create(2663, 3305, 0), new Item(Rune.WATER.getRune().getId(), 200), new Item(Rune.LAW.getRune().getId(), 200)),
YANILLE(Location.create(2554, 3114, 0), new Item(Rune.EARTH.getRune().getId(), 200), new Item(Rune.LAW.getRune().getId(), 200)),
KHARYRLL(Location.create(3493, 3474, 0), new Item(Rune.BLOOD.getRune().getId(), 100), new Item(Rune.LAW.getRune().getId(), 200));
/**
* The location to teleport to
*/
private Location location;
/**
* The rune requirements
*/
private Item[] runes;
/**
* Locations
* @param location
* @param runes
*/
Locations(Location location, Item... runes) {
this.location = location;
this.runes = runes;
}
}
/**
* Directs a portal
* @param player
* @param identifier
*/
public static void direct(Player player, String identifier) {
player.getInterfaceManager().closeSingleTab();
int dpId = player.getAttribute("con:dp-id", 1);
Hotspot[] hotspots = player.getHouseManager().getRoom(player.getLocation()).getHotspots();
for (int i = 0; i < hotspots.length; i++) {
Hotspot h = hotspots[i];
if (h.getHotspot().name().equalsIgnoreCase("PORTAL" + dpId)) {
if (h.getDecorationIndex() == -1) {
player.sendMessage("You must build a portal frame first!");
return;
}
Decoration previous = h.getHotspot().getDecorations()[h.getDecorationIndex()];
String name = previous.name();
String prefix = "TEAK";
if (name.toLowerCase().contains("mahogany")) {
prefix = "MAHOGANY";
} else if (name.toLowerCase().contains("marble")) {
prefix = "MARBLE";
}
for (Locations l : Locations.values()) {
if (l.name().contains(identifier)) {
Item[] runes = l.runes;
if (!player.getInventory().containsItems(runes)) {
player.sendMessage("You do not have the required runes to build this portal");
return;
}
player.getInventory().remove(runes);
break;
}
}
h.setDecorationIndex(h.getHotspot().getDecorationIndex(Decoration.forName(prefix + "_" + identifier + "_" + "PORTAL")));
player.getHouseManager().reload(player, player.getHouseManager().isBuildingMode()); //TODO replace object live instead?
}
}
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
SceneryDefinition.forId(13639).getHandlers().put("option:direct-portal", this);
SceneryDefinition.forId(13639).getHandlers().put("option:scry", this);
SceneryDefinition.forId(13640).getHandlers().put("option:direct-portal", this);
SceneryDefinition.forId(13641).getHandlers().put("option:direct-portal", this);
for (int i = 13615; i <= 13635; i++) {
SceneryDefinition.forId(i).getHandlers().put("option:enter", this);
}
ClassScanner.definePlugin(new DirectPortalDialogue());
return this;
}
@Override
public boolean handle(Player player, Node node, String option) {
Scenery object = node.asScenery();
switch (option) {
case "direct-portal":
if (!player.getHouseManager().isBuildingMode()) {
player.sendMessage("You can currently only do this in building mode.");
return true;
}
player.getDialogueInterpreter().open(DialogueInterpreter.getDialogueKey("con:directportal"));
return true;
case "enter":
String objectName = object.getName();
for (Locations l : Locations.values()) {
if (objectName.toLowerCase().contains(l.name().toLowerCase())) {
player.teleport(l.location);
if (player.getHouseManager().isInHouse(player) && node.getId() == 13635) {
//player.getAchievementDiaryManager().getDiary(DiaryType.MORYTANIA).updateTask(player, 2, 0, true);
}
break;
}
}
return true;
case "scry":
//wtf
return true;
}
return false;
}
/**
* DirectPortalDialogue.java
* @author Clayton Williams
* @date Jan 2, 2016
*/
private static final class DirectPortalDialogue extends DialoguePlugin {
/**
* DirectPortalDialogue
*/
public DirectPortalDialogue() {
/**
* Empty
*/
}
/**
* DirectPortalDialogue
* @param player
*/
public DirectPortalDialogue(Player player) {
super(player);
}
@Override
public DialoguePlugin newInstance(Player player) {
return new DirectPortalDialogue(player);
}
@Override
public boolean open(Object... args) {
interpreter.sendOptions("Select a portal", "Portal 1", "Portal 2", "Portal 3");
stage = 0;
return true;
}
@Override
public boolean handle(int interfaceId, int buttonId) {
player.setAttribute("con:dp-id", buttonId);
end();
player.getDialogueInterpreter().open(394857);
return true;
}
@Override
public int[] getIds() {
return new int[]{DialogueInterpreter.getDialogueKey("con:directportal")};
}
}
/**
* The direct options build
*/
/*private final static TabbedOption DIRECT_OPTIONS = new TabbedOption("Direct Portal", "Select an option",
new Page(
new PageAction("Varrock Portal") {
@Override
public boolean run(Player player) {
PortalChamberPlugin.direct(player, "VARROCK");
return true;
}
},
new PageAction("Lumbridge Portal") {
@Override
public boolean run(Player player) {
PortalChamberPlugin.direct(player, "LUMBRIDGE");
return true;
}
},
new PageAction("Falador Portal") {
@Override
public boolean run(Player player) {
PortalChamberPlugin.direct(player, "FALADOR");
return true;
}
},
new PageAction("Camelot Portal") {
@Override
public boolean run(Player player) {
PortalChamberPlugin.direct(player, "CAMELOT");
return true;
}
},
new PageAction("Ardougne Portal") {
@Override
public boolean run(Player player) {
PortalChamberPlugin.direct(player, "ARDOUGNE");
return true;
}
}
), new Page(
new PageAction("Yanille Portal") {
@Override
public boolean run(Player player) {
PortalChamberPlugin.direct(player, "YANILLE");
return true;
}
},
new PageAction("Kharyrll Portal") {
@Override
public boolean run(Player player) {
PortalChamberPlugin.direct(player, "KHARYRLL");
return true;
}
}
)
);*/
}
@@ -0,0 +1,65 @@
package content.global.skill.construction.decoration.questhall
import core.api.teleport
import core.game.node.entity.player.Player
import core.game.node.entity.player.link.audio.Audio;
import core.game.system.task.Pulse
import core.game.world.map.Location
import core.game.world.update.flag.context.Animation
import core.game.world.update.flag.context.Graphics
import core.game.interaction.InteractionListener
import core.game.interaction.IntType
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
class MountedGlory : InteractionListener {
val MOUNTED_GLORY = 13523
val TELEPORTS = arrayOf(
Location.create(3087, 3495, 0),
Location.create(2919, 3175, 0),
Location.create(3104, 3249, 0),
Location.create(3304, 3124, 0)
)
override fun defineListeners() {
on(MOUNTED_GLORY, IntType.SCENERY, "Edgeville") { player, _ ->
mountedGloryTeleport(player,0)
return@on true
}
on(MOUNTED_GLORY, IntType.SCENERY, "Karamja") { player, _ ->
mountedGloryTeleport(player,1)
return@on true
}
on(MOUNTED_GLORY, IntType.SCENERY, "Draynor Village") { player, _ ->
mountedGloryTeleport(player,2)
return@on true
}
on(MOUNTED_GLORY, IntType.SCENERY, "Al Kharid") { player, _ ->
mountedGloryTeleport(player,3)
return@on true
}
}
private fun mountedGloryTeleport(player : Player, int : Int) {
Executors.newSingleThreadScheduledExecutor().schedule({
player.pulseManager.run(object : Pulse() {
var counter = 0
override fun pulse(): Boolean {
when (counter++) {
1 -> {
player.lock(5)
player.visualize(Animation(714), Graphics(308, 100, 50))
player.getAudioManager().send(Audio(200), true);
}
4 -> player.animator.reset().also { teleport(player, TELEPORTS[int]) }
}
return false
}
})
}, 0, TimeUnit.SECONDS)
}
}
@@ -0,0 +1,96 @@
package content.global.skill.construction.decoration.questhall;
import core.cache.def.impl.SceneryDefinition;
import core.game.dialogue.DialogueAction;
import core.game.dialogue.DialogueInterpreter;
import core.game.interaction.OptionHandler;
import core.game.node.Node;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.audio.Audio;
import core.game.system.task.Pulse;
import core.game.world.GameWorld;
import core.game.world.map.Location;
import core.game.world.update.flag.context.Animation;
import core.game.world.update.flag.context.Graphics;
import core.plugin.Initializable;
import core.plugin.Plugin;
/**
* Handles the POH Mounted Glory.
* @author Splinter
*/
@Initializable
public class MountedGloryPlugin extends OptionHandler {
/**
* Represents the teleport animation.
*/
private static final Animation ANIMATION = new Animation(714);
/**
* Represents the graphics to use.
*/
private static final Graphics GRAPHICS = new Graphics(308, 100, 50);
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
SceneryDefinition.forId(13523).getHandlers().put("option:rub", this);
return this;
}
@Override
public boolean handle(Player player, Node node, String option) {
DialogueInterpreter interpreter = player.getDialogueInterpreter();
interpreter.sendOptions("Select a location.", "Edgeville", "Karamja", "Draynor Village", "Al-Kharid", "Nowhere.");
interpreter.addAction(new DialogueAction() {
@Override
public void handle(Player player, int buttonId) {
switch (buttonId) {
case 2:
teleport(player, Location.create(3087, 3495, 0));
break;
case 3:
teleport(player, Location.create(2919, 3175, 0));
break;
case 4:
teleport(player, Location.create(3081, 3250, 0));
break;
case 5:
teleport(player, Location.create(3304, 3124, 0));
break;
}
}
});
return true;
}
/**
* Method used to teleport to a location.
* @param player the player.
* @param location the location.
*/
private boolean teleport(final Player player, final Location location) {
if (player.isTeleBlocked()) {
player.sendMessage("A magical force has stopped you from teleporting.");
return false;
}
player.lock();
player.visualize(ANIMATION, GRAPHICS);
player.getAudioManager().send(new Audio(200), true);
player.getImpactHandler().setDisabledTicks(4);
GameWorld.getPulser().submit(new Pulse(4, player) {
@Override
public boolean pulse() {
player.unlock();
player.getProperties().setTeleportLocation(location);
player.getAnimator().reset();
return true;
}
});
return true;
}
}
@@ -0,0 +1,220 @@
package content.global.skill.construction.decoration.study
import core.api.*
import core.cache.def.impl.SceneryDefinition
import core.game.component.Component
import core.game.interaction.OptionHandler
import content.global.handlers.item.TeleTabsOptionPlugin
import core.game.node.Node
import core.game.node.entity.player.Player
import core.game.node.entity.player.link.diary.DiaryType
import core.game.node.entity.skill.Skills
import content.global.skill.construction.Decoration
import core.game.node.entity.combat.spell.MagicStaff
import core.game.node.item.Item
import core.game.system.task.Pulse
import core.game.world.update.flag.context.Animation
import core.plugin.Initializable
import core.plugin.Plugin
import core.game.world.GameWorld
import core.game.interaction.InterfaceListener
/**
* Handles the lectern
* LecternPlugin
* @author Ceikry
*/
@Initializable
class LecternPlugin : OptionHandler() {
/**
* TeleTabButton
*/
private enum class TeleTabButton(
/**
* The button id
*/
val buttonId: Int,
/**
* The level and xp
*/
val level: Int,
val xp: Double,
/**
* The item
*/
val tabItem: Item,
/**
* The required decoration (lectern)
*/
private val requiredDecorations: Array<Decoration>, vararg requiredItems: Item) {
ARDOUGNE(2, 51, 61.0, Item(TeleTabsOptionPlugin.TeleTabs.ADDOUGNE_TELEPORT.item), arrayOf<Decoration>(Decoration.TEAK_EAGLE_LECTERN, Decoration.MAHOGANY_EAGLE_LECTERN), SOFT_CLAY, Item(563, 2), Item(555, 2)),
BONES_TO_BANANNAS(3, 15, 25.0, Item(8014), arrayOf<Decoration>(Decoration.DEMON_LECTERN, Decoration.TEAK_DEMON_LECTERN, Decoration.MAHOGANY_DEMON_LECTERN), SOFT_CLAY, Item(561, 1), Item(557, 2), Item(555, 2)),
BONES_TO_PEACHES(4, 60, 35.5, Item(8015), arrayOf<Decoration>(Decoration.MAHOGANY_DEMON_LECTERN), SOFT_CLAY, Item(561, 2), Item(557, 4), Item(555, 4)),
CAMELOT(5, 45, 55.5, Item(TeleTabsOptionPlugin.TeleTabs.CAMELOT_TELEPORT.item), arrayOf<Decoration>(Decoration.TEAK_EAGLE_LECTERN, Decoration.MAHOGANY_EAGLE_LECTERN), SOFT_CLAY, Item(563), Item(556, 5)),
ENCHANT_DIAMOND(6, 57, 67.0, Item(8019), arrayOf<Decoration>(Decoration.TEAK_DEMON_LECTERN, Decoration.MAHOGANY_DEMON_LECTERN), SOFT_CLAY, Item(564), Item(557, 10)),
ENCHANT_DRAGONSTONE(7, 68, 78.0, Item(8020), arrayOf<Decoration>(Decoration.MAHOGANY_DEMON_LECTERN), SOFT_CLAY, Item(564), Item(557, 15), Item(555, 15)),
ENCHANT_EMERALD(8, 27, 37.0, Item(8017), arrayOf<Decoration>(Decoration.DEMON_LECTERN, Decoration.TEAK_DEMON_LECTERN, Decoration.MAHOGANY_DEMON_LECTERN), SOFT_CLAY, Item(564), Item(556, 3)),
ENCHANT_ONYX(9, 87, 97.0, Item(8021), arrayOf<Decoration>(Decoration.MAHOGANY_DEMON_LECTERN), SOFT_CLAY, Item(564), Item(557, 20), Item(554, 20)),
ENCHANT_RUBY(10, 49, 59.0, Item(8018), arrayOf<Decoration>(Decoration.TEAK_DEMON_LECTERN, Decoration.MAHOGANY_DEMON_LECTERN), SOFT_CLAY, Item(564), Item(554, 5)),
ENCHANT_SAPPHIRE(11, 7, 17.5, Item(8016), arrayOf<Decoration>(Decoration.OAK_LECTERN, Decoration.EAGLE_LECTERN, Decoration.TEAK_EAGLE_LECTERN, Decoration.MAHOGANY_EAGLE_LECTERN, Decoration.DEMON_LECTERN, Decoration.TEAK_DEMON_LECTERN, Decoration.MAHOGANY_DEMON_LECTERN), SOFT_CLAY, Item(564), Item(555)),
FALADOR(12, 37, 48.0, Item(TeleTabsOptionPlugin.TeleTabs.FALADOR_TELEPORT.item), arrayOf<Decoration>(Decoration.EAGLE_LECTERN, Decoration.TEAK_EAGLE_LECTERN, Decoration.MAHOGANY_EAGLE_LECTERN), SOFT_CLAY, Item(563), Item(555), Item(556, 3)),
LUMBRIDGE(13, 31, 41.0, Item(TeleTabsOptionPlugin.TeleTabs.LUMBRIDGE_TELEPORT.item), arrayOf<Decoration>(Decoration.EAGLE_LECTERN, Decoration.TEAK_EAGLE_LECTERN, Decoration.MAHOGANY_EAGLE_LECTERN), SOFT_CLAY, Item(563), Item(557), Item(556, 3)),
HOUSE(14, 40, 30.0, Item(8013), arrayOf<Decoration>(Decoration.MAHOGANY_EAGLE_LECTERN), SOFT_CLAY, Item(563), Item(557), Item(556)),
VARROCK(15, 25, 35.0, Item(TeleTabsOptionPlugin.TeleTabs.VARROCK_TELEPORT.item), arrayOf<Decoration>(Decoration.OAK_LECTERN, Decoration.EAGLE_LECTERN, Decoration.TEAK_EAGLE_LECTERN, Decoration.MAHOGANY_EAGLE_LECTERN, Decoration.DEMON_LECTERN, Decoration.TEAK_DEMON_LECTERN, Decoration.MAHOGANY_DEMON_LECTERN), SOFT_CLAY, Item(563), Item(554), Item(556, 3)),
WATCHTOWER(16, 58, 68.0, Item(TeleTabsOptionPlugin.TeleTabs.WATCH_TOWER_TELEPORT.item), arrayOf<Decoration>(Decoration.MAHOGANY_EAGLE_LECTERN), SOFT_CLAY, Item(563, 2), Item(557, 2));
/**
* The required items
*/
val requiredItems: ArrayList<Item> = arrayListOf(*requiredItems)
/**
* Checks if the player can make this tab
* @param player
* @return
*/
fun canMake(player: Player): Boolean {
val objectId = player.getAttribute<Int>("ttb:objectid")
if (player.skills.getLevel(Skills.MAGIC) < level && player.spellBookManager.spellBook == 192) {
player.sendMessage("You need a magic level of $level to make that!")
return false
}
if (this == BONES_TO_PEACHES && !player.savedData.activityData.isBonesToPeaches) {
player.sendMessages("You need the Bones to Peaches ability purchased from MTA before making these.", "This requirement doesn't apply to actually using the tabs.")
return false
}
var found = false
for (d in requiredDecorations) if (d.objectId == objectId) found = true
if (!found) {
player.sendMessage("You're unable to make this tab on this specific lectern.")
return false
}
for (item in requiredItems) {
val staff = MagicStaff.forId(item.id)
if (staff != null && player.equipment.containsAtLeastOneItem(staff.staves)) {
continue;
}
if (!player.inventory.containsItem(item)) {
//TODO staffs
player.sendMessage("You don't have enough materials.")
return false
}
}
return true
}
companion object {
/**
* Gets the button for the id
* @param id
* @return
*/
fun forId(id: Int): TeleTabButton? {
for (ttb in values()) {
if (ttb.buttonId == id) return ttb
}
return null
}
}
}
@Throws(Throwable::class)
override fun newInstance(arg: Any?): Plugin<Any>? {
for (i in 13642..13648) {
SceneryDefinition.forId(i).handlers["option:study"] = this
}
return this
}
override fun handle(player: Player, node: Node, option: String): Boolean {
val id = node.asScenery().id
player.setAttribute("ttb:objectid", id)
GameWorld.Pulser.submit(object : Pulse(){
var counter = 0
override fun pulse(): Boolean {
when(counter++){
0 -> player.animator.animate(Animation(1894)).also { player.lock() }
1 -> player.interfaceManager.open(Component(400)).also { player.unlock(); return true }
}
return false
}
})
return true
}
/**
* TeleTabInterface
* @author Ceikry
*/
class TeleTabInterface : InterfaceListener {
val decorationVarps = hashMapOf(
Decoration.OAK_LECTERN to Pair(0, 0),
Decoration.EAGLE_LECTERN to Pair(1, 0),
Decoration.DEMON_LECTERN to Pair(0, 1),
Decoration.TEAK_EAGLE_LECTERN to Pair(2, 0),
Decoration.TEAK_DEMON_LECTERN to Pair(0, 2),
Decoration.MAHOGANY_EAGLE_LECTERN to Pair(3, 0),
Decoration.MAHOGANY_DEMON_LECTERN to Pair(0, 3),
)
override fun defineInterfaceListeners() {
onOpen(400) { player, component ->
val id = player.getAttribute("ttb:objectid", 0)
val deco = Decoration.forObjectId(id)
val values = decorationVarps[deco] ?: Pair(0, 0)
player.varpManager.get(261).setVarbit(0, values.first).send(player)
player.varpManager.get(262).setVarbit(0, values.second).send(player)
return@onOpen true
}
on(400) { player, _, _, buttonID, _, _ ->
val ttb = TeleTabButton.forId(buttonID)
if (ttb != null && ttb.canMake(player)) {
player.interfaceManager.close()
var requiredItemsCountingStaves = ttb.requiredItems.filter({ item ->
val staff = MagicStaff.forId(item.id);
!(staff != null && player.equipment.containsAtLeastOneItem(staff.staves))
}).toTypedArray()
player.pulseManager.run(object : Pulse(1) {
var counter = 0
override fun pulse(): Boolean {
when(counter++) {
0 -> {
if (!ttb.canMake(player)) {
return true
}
//TODO Add correct lectern animation (should look like raising arms progressively higher 3 times).
player.animate(Animation(782))
}
2 -> {
if (player.inventory.remove(*requiredItemsCountingStaves)) {
// Should never drop, since soft clay was successfully removed
addItemOrDrop(player, ttb.tabItem.id)
player.skills.addExperience(Skills.MAGIC, ttb.xp, true)
if (ttb == TeleTabButton.VARROCK
&& (player.getAttribute("ttb:objectid", 0) == Decoration.MAHOGANY_EAGLE_LECTERN.objectId
|| player.getAttribute("ttb:objectid", 0) == Decoration.MAHOGANY_DEMON_LECTERN.objectId)) {
player.achievementDiaryManager.finishTask(player, DiaryType.VARROCK, 2, 8)
}
} else {
return true
}
}
}
counter %= 6
return false
}
})
}
player.animate(Animation(-1))
return@on true
}
}
}
companion object {
/**
* Soft clay
*/
private val SOFT_CLAY = Item(1761, 1)
}
}
@@ -0,0 +1,53 @@
package content.global.skill.construction.decoration.study
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.scenery.Scenery
import core.game.node.entity.player.Player
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 content.global.activity.shootingstar.ShootingStarPlugin
import core.game.world.GameWorld.Pulser
import java.util.concurrent.TimeUnit
@Initializable
class TelescopePlugin : OptionHandler() {
@Throws(Throwable::class)
override fun newInstance(arg: Any?): Plugin<Any?>? {
SceneryDefinition.forId(13656).handlers["option:observe"] = this
SceneryDefinition.forId(13657).handlers["option:observe"] = this
SceneryDefinition.forId(13658).handlers["option:observe"] = this
return this
}
override fun handle(player: Player?, node: Node?, option: String?): Boolean {
val star = ShootingStarPlugin.getStar()
val delay: Int = 25000 + (25000 / 3)
val timeLeft = delay - star.ticks
val fakeTimeLeftBecauseFuckPlayers = TimeUnit.MILLISECONDS.toMinutes(timeLeft * 600L) + if(RandomFunction.random(0,100) % 2 == 0) 2 else -2
val obj = node?.asScenery() as Scenery
player?.lock()
player?.animate(ANIMATION)
player?.interfaceManager?.open(Component(782)).also { player?.unlock()
Pulser.submit(object : Pulse(2, player) {
override fun pulse(): Boolean {
if (obj.isActive) {
player?.dialogueInterpreter?.sendDialogue("You see a shooting star! The star looks like it will land","in about $fakeTimeLeftBecauseFuckPlayers minutes!")
return true
}
return true
}
})
return true
}
}
companion object {
private val ANIMATION = Animation.create(3649)
}
}
@@ -0,0 +1,105 @@
package content.global.skill.construction.decoration.workshop
import core.game.dialogue.DialoguePlugin
import content.data.RepairItem
import core.game.interaction.NodeUsageEvent
import core.game.interaction.UseWithHandler
import content.region.misthalin.lumbridge.dialogue.BobDialogue.BarrowsEquipment
import content.region.misthalin.lumbridge.dialogue.BobDialogue.BarrowsEquipment.BarrowsFullEquipment
import core.game.node.entity.player.Player
import core.game.node.entity.skill.Skills
import core.game.node.item.Item
import core.plugin.Initializable
import core.plugin.Plugin
import kotlin.math.ceil
@Initializable
class ArmourStand : UseWithHandler(494, 468, 496, 470, 498, 472, 500, 502, 474, 504, 476, 506, 478, 6741, 4856, 4857, 4858, 4859, 4860, 4862, 4863, 4864, 4865, 4866, 4868, 4869, 4870, 4871, 4872, 4874, 4875, 4876, 4877, 4878, 4880, 4881, 4882, 4883, 4884, 4886, 4887, 4888, 4889, 4890, 4892, 4893, 4894, 4895, 4896, 4898, 4899, 4900, 4901, 4902, 4904, 4905, 4906, 4907, 4908, 4910, 4911, 4912, 4913, 4914, 4916, 4917, 4918, 4919, 4920, 4922, 4923, 4924, 4925, 4926, 4928, 4929, 4930, 4931, 4932, 4934, 4935, 4936, 4937, 4938, 4940, 4941, 4942, 4943, 4944, 4946, 4947, 4948, 4949, 4950, 4952, 4953, 4954, 4955, 4956, 4958, 4959, 4960, 4961, 4962, 4964, 4965, 4966, 4967, 4968, 4970, 4971, 4972, 4973, 4974, 4976, 4977, 4978, 4979, 4980, 4982, 4983, 4984, 4985, 4986, 4988, 4989, 4990, 4991, 4992, 4994, 4995, 4996, 4997, 4998){
override fun newInstance(arg: Any?): Plugin<Any> {
addHandler(13715, OBJECT_TYPE, this)
return this
}
override fun handle(event: NodeUsageEvent?): Boolean {
event ?: return false
val player = event.player
val repairItem = RepairItem.forId(event.used.id)
var baseCost = 0.0
var product: Item? = null
if(repairItem != null){
baseCost = repairItem.cost * 1.0
product = repairItem.product
} else if(BarrowsEquipment.isBarrowsItem(event.used.id)){
//Begin terrible code thanks to Vexia
val type = BarrowsEquipment.formatedName(event.used.id)
val single = BarrowsEquipment.getSingleName(type)
val equipment = BarrowsEquipment.getEquipmentType(type)
val newString = type.toLowerCase().replace(single, "").trim { it <= ' ' }.replace("'s", "")
val newewString = StringBuilder()
newewString.append(newString).append(" $equipment")
val fullequip = BarrowsFullEquipment.forName(newewString.toString())
baseCost = BarrowsEquipment.getFormatedCost(equipment,event.used.asItem()) * 1.0
product = fullequip.full
//End terrible code thanks to Vexia
}
if((repairItem == null && baseCost == 0.0)){
player.sendMessage("That item can't be repaired.")
return true
}
val cost: Int = ceil(((100.0 - (player.skills.getLevel(Skills.SMITHING) / 2.0) ) / 100.0) * baseCost).toInt()
player.dialogueInterpreter.open(58824213,event.used,cost,product)
return true
}
@Initializable
class RepairDialogue(player: Player? = null) : core.game.dialogue.DialoguePlugin(player){
override fun newInstance(player: Player?): core.game.dialogue.DialoguePlugin {
return RepairDialogue(player)
}
var item: Item? = null
var cost: Int = 0
var product: Item? = null
override fun open(vararg args: Any?): Boolean {
item = args[0] as Item
cost = args[1] as Int
product = args[2] as Item
player.dialogueInterpreter.sendDialogue("Would you like to repair your ${(item as Item).name.toLowerCase()}","for $cost gp?")
stage = 0
return true
}
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
item ?: return false
product ?: return false
when(stage){
0 -> options("Yes, please","No, thanks").also{stage++}
1 -> when(buttonId){
1 -> exchangeItems(item as Item,cost,product as Item).also { end() }
2 -> end()
}
}
return true
}
fun exchangeItems(item: Item, cost: Int, product: Item) {
val coins = Item(995, cost)
if (player.inventory.containsItem(coins) && player.inventory.containsItem(item)) {
player.inventory.remove(item, coins)
player.inventory.add(product)
player.sendMessage("You repair your ${product.name.toLowerCase()} for $cost.")
} else {
player.sendMessage("You can't afford that.")
}
}
override fun getIds(): IntArray {
return intArrayOf(58824213)
}
}
}
@@ -0,0 +1,235 @@
package content.global.skill.construction.decoration.workshop;
import content.global.skill.construction.BuildingUtils;
import content.global.skill.construction.Decoration;
import core.cache.def.impl.ItemDefinition;
import core.cache.def.impl.SceneryDefinition;
import core.game.dialogue.DialogueInterpreter;
import core.game.dialogue.DialoguePlugin;
import core.game.node.entity.skill.Skills;
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.plugin.Initializable;
import core.plugin.Plugin;
import core.plugin.ClassScanner;
/**
* Handles the clockmakers bench in the workshop
* ClockmakersBenchPlugin.java
* @author Clayton Williams (hope)
* @date Oct 29, 2015
*/
@Initializable
public class ClockmakersBenchPlugin extends OptionHandler {
/**
* Stores data for things created by the clockmakers bench
* ClockmakersBenchPlugin.java
* @author Clayton Williams
* @date Oct 30, 2015
*/
private enum Craftable {
TOY_HORSEY(2520, 10, BuildingUtils.PLANK),
CLOCKWORK(8792, 8, new Item(2353)),
TOY_SOLDIER(7759, 13, BuildingUtils.PLANK, new Item(8792)),
TOY_DOLL(7763, 18, BuildingUtils.PLANK, new Item(8792)),
TOY_MOUSE(7767, 33, BuildingUtils.PLANK, new Item(8792)),
TOY_CAT(7771, 85, BuildingUtils.PLANK, new Item(8792)),
WATCH(2575, 28, new Item(8792), new Item(2353)),
SEXTANT(2574, 23, new Item(2353));
/**
* The itemId to give after making this
*/
private int itemId;
/**
* The materials needed to make this
*/
private Item[] materials;
/**
* The crafting level required to make this
*/
private int craftingLevel;
/**
* Craftable
* @param itemId
* @param craftingLevel
* @param materials
*/
Craftable(int itemId, int craftingLevel, Item... materials) {
this.itemId = itemId;
this.craftingLevel = craftingLevel;
this.materials = materials;
}
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
SceneryDefinition.forId(13709).getHandlers().put("option:craft", this);
SceneryDefinition.forId(13710).getHandlers().put("option:craft", this);
SceneryDefinition.forId(13711).getHandlers().put("option:craft", this);
SceneryDefinition.forId(13712).getHandlers().put("option:craft", this);
ClassScanner.definePlugin(new ClockmakerBenchDialogue());
return this;
}
@Override
public boolean handle(Player player, Node node, String option) {
player.getDialogueInterpreter().open(DialogueInterpreter.getDialogueKey("con:clockbench"), node.asScenery());
return true;
}
/**
* Handles the dialogue for clock bench
* @author Clayton Williams
* @date Oct 29, 2015
*/
private final class ClockmakerBenchDialogue extends DialoguePlugin {
/**
* The crafting table decoration
*/
Decoration decoration;
/**
* ClockmakerBenchDialogue
*/
public ClockmakerBenchDialogue() {
/**
* Empty
*/
}
/**
* ClockmakerBenchDialogue
* @param player
*/
public ClockmakerBenchDialogue(Player player) {
super(player);
}
@Override
public DialoguePlugin newInstance(Player player) {
return new ClockmakerBenchDialogue(player);
}
@Override
public boolean open(Object... args) {
Scenery object = (Scenery) args[0];
decoration = Decoration.forObjectId(object.getId());
if (decoration != null) {
switch (decoration) {
case CRAFTING_TABLE_1:
interpreter.sendOptions("Select an Option", "Toy Horsey", "Nevermind");
break;
case CRAFTING_TABLE_2:
interpreter.sendOptions("Select an Option", "Toy Horsey", "Clockwork Mechanism");
break;
case CRAFTING_TABLE_3:
interpreter.sendOptions("Select an Option", "Toy Horsey", "Clockwork Mechanism", "Clockwork Devices");
break;
case CRAFTING_TABLE_4:
interpreter.sendOptions("Select an Option", "Toy Horsey", "Clockwork Mechanism", "Clockwork Devices", "Watch", "Sextant");
break;
default:
break;
}
}
stage = 1;
return true;
}
@Override
public boolean handle(int interfaceId, int buttonId) {
switch (stage) {
case 1:
switch (buttonId) {
case 1:
case 2:
if (decoration == Decoration.CRAFTING_TABLE_1 && buttonId == 2) {
end();
return true;
}
craftItem(buttonId == 1 ? Craftable.TOY_HORSEY : Craftable.CLOCKWORK);
stage = 3;
break;
case 3:
if (decoration == Decoration.CRAFTING_TABLE_3) {
interpreter.sendOptions("Select an Option", "Clockwork Soldier", "Clockwork Doll");
} else if (decoration == Decoration.CRAFTING_TABLE_4) {
interpreter.sendOptions("Select an Option", "Clockwork Soldier", "Clockwork Doll", "Clockwork Mouse", "Clockwork Cat");
}
stage = 2;
break;
case 4:
case 5:
craftItem(buttonId == 4 ? Craftable.WATCH : Craftable.SEXTANT);
stage = 3;
break;
}
break;
case 2:
switch (buttonId) {
case 1:
craftItem(Craftable.TOY_SOLDIER);
break;
case 2:
craftItem(Craftable.TOY_DOLL);
break;
case 3:
craftItem(Craftable.TOY_MOUSE);
break;
case 4:
craftItem(Craftable.TOY_CAT);
break;
}
stage = 3;
break;
case 3:
end();
break;
}
return true;
}
/**
* Attempts to craft an item
* @param c - the craftable to make
*/
private void craftItem(Craftable c) {
if (c != null) {
if (player.getSkills().getLevel(Skills.CRAFTING) < c.craftingLevel) {
interpreter.sendDialogue("You need level " + c.craftingLevel + " crafting to make that.");
return;
}
for (Item n : c.materials) {
if (!player.getInventory().containsItem(n)) {
interpreter.sendDialogue("You need a " + ItemDefinition.forId(n.getId()).getName() + " to make that!");
return;
}
}
for (Item n : c.materials) {
n.setAmount(1);
player.getInventory().remove(n);
}
player.getSkills().addExperience(Skills.CRAFTING, 15);
player.getInventory().add(new Item(c.itemId, 1));
player.animate(BuildingUtils.BUILD_MID_ANIM);
interpreter.sendDialogue("You made a " + ItemDefinition.forId(c.itemId).getName() + "!");
}
}
@Override
public int[] getIds() {
return new int[] { DialogueInterpreter.getDialogueKey("con:clockbench") };
}
}
}
@@ -0,0 +1,171 @@
package content.global.skill.construction.decoration.workshop;
import core.cache.def.impl.ItemDefinition;
import core.cache.def.impl.SceneryDefinition;
import core.plugin.Initializable;
import core.game.dialogue.DialogueInterpreter;
import core.game.dialogue.DialoguePlugin;
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.plugin.Plugin;
import core.plugin.ClassScanner;
import java.util.ArrayList;
import java.util.List;
/**
* Handles the 5 types of tool stores
* ToolsPlugin.java
* @author Clayton Williams
* @date Oct 29, 2015
*
*/
@Initializable
public class ToolsPlugin extends OptionHandler {
/**
* The different tool stores
* @author Clayton Williams
* @date Oct 29, 2015
*/
private enum ToolStore {
TOOLSTORE_1(13699, 8794, 1755, 2347, 1735),
TOOLSTORE_2(13700, 1925, 952, 590),
TOOLSTORE_3(13701, 1757, 1785, 1733),
TOOLSTORE_4(13702, 1595, 1597, 1592, 1599, 5523),
TOOLSTORE_5(13703, 5341, 952, 676, 5343, 5331);
/**
* The object id of the tool store
*/
private int objectId;
/**
* The tools included
*/
private int[] tools;
/**
* ToolStore
* @param objectId
* @param tools
*/
ToolStore(int objectId, int... tools) {
this.objectId = objectId;
this.tools = tools;
}
/**
* Gets the toolstore from an object id
* @param objectId - the object id
* @return
*/
private static ToolStore forId(int objectId) {
for (ToolStore t : ToolStore.values()) {
if (t.objectId == objectId) {
return t;
}
}
return null;
}
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
for (ToolStore t : ToolStore.values()) {
SceneryDefinition.forId(t.objectId).getHandlers().put("option:search", this);
}
ClassScanner.definePlugin(new ToolDialogue());
return this;
}
@Override
public boolean handle(Player player, Node node, String option) {
Scenery object = node.asScenery();
ToolStore ts = ToolStore.forId(object.getId());
if (ts != null) {
player.getDialogueInterpreter().open(DialogueInterpreter.getDialogueKey("con:tools"), ts);
}
return true;
}
/**
* Handles the tool dialogue
* @author Clayton Williams
* @date Oct 29, 2015
*/
private final class ToolDialogue extends DialoguePlugin {
/**
* The tool store being used
*/
private ToolStore toolStore;
/**
* ToolDialogue
*/
private ToolDialogue() {
/**
* Empty
*/
}
/**
* ToolDialogue
* @param player
*/
public ToolDialogue(Player player) {
super(player);
}
@Override
public DialoguePlugin newInstance(Player player) {
return new ToolDialogue(player);
}
@Override
public boolean open(Object... args) {
toolStore = (ToolStore) args[0];
List<String> itemNames = new ArrayList<String>();
for(int itemId : toolStore.tools) {
ItemDefinition n = ItemDefinition.forId(itemId);
itemNames.add(n.getName());
}
interpreter.sendOptions("Select a Tool", itemNames.toArray(new String[itemNames.size()]));
stage = 1;
return true;
}
@Override
public boolean handle(int interfaceId, int buttonId) {
switch (stage) {
case 1:
Item item = new Item(toolStore.tools[buttonId - 1], 1);
if (player.getInventory().freeSlots() <= 0) {
interpreter.sendDialogue("You have no space in your inventory.");
stage = 2;
return true;
}
player.getInventory().add(item);
end();
return true;
case 2:
end();
return true;
}
return false;
}
@Override
public int[] getIds() {
return new int[] { DialogueInterpreter.getDialogueKey("con:tools") };
}
}
}
@@ -0,0 +1,568 @@
package content.global.skill.construction.npc;
import content.global.skill.construction.HouseManager;
import content.global.skill.construction.ServantType;
import core.game.dialogue.DialoguePlugin;
import core.game.dialogue.FacialExpression;
import core.game.node.entity.impl.PulseType;
import core.game.node.entity.skill.Skills;
import content.global.skill.construction.Servant;
import core.game.interaction.MovementPulse;
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.system.task.Pulse;
import core.game.world.GameWorld;
import core.game.world.map.Location;
import core.game.world.map.path.Pathfinder;
import content.global.handlers.iface.SawmillPlankInterface.Plank;
/**
* Handles the Servant's dialogues.
* @author Splinter
* @date 9/23/2015
* @version 0.98 (TODO: Missing a few dialogues)
*/
public class HouseServantDialogue extends DialoguePlugin {
/**
* If using the sawmill.
*/
private boolean sawmill;
/**
* The logs
*/
private Item logs;
/**
* Constructs a new {@code ServantDialogue} {@code Object}.
*/
public HouseServantDialogue() {
/**
* empty.
*/
}
/**
* Constructs a new {@code ServantDialogue} {@code Object}.
* @param player the player.
*/
public HouseServantDialogue(Player player) {
super(player);
}
@Override
public DialoguePlugin newInstance(Player player) {
return new HouseServantDialogue(player);
}
@Override
public boolean open(Object... args) {
npc = (NPC) args[0];
HouseManager manager = player.getHouseManager();
boolean inHouse = manager.isInHouse(player);
if (args.length > 1) { //Parse options from our "use-with" handler
sawmill = (boolean) args[1];
logs = (Item) args[2];
}
if (player.getIronmanManager().checkRestriction(IronmanMode.ULTIMATE)) {
player.sendMessage("Ultimate Ironmen cannot hire butlers.");
return true;
}
if (!manager.hasHouse() && inHouse) {
interpreter.sendDialogues(npc, npc.getId() == 4243 ? FacialExpression.HALF_GUILTY : null, "You don't have a house that I can work in.", "I'll be waiting here if you decide to buy a house.");
stage = 100;
return true;
}
if (!manager.hasServant()) {
ServantType type = ServantType.forId(npc.getId());
if(player.getSkills().getLevel(Skills.CONSTRUCTION) >= type.getLevel()){
interpreter.sendDialogues(npc, npc.getId() == 4243 ? FacialExpression.HALF_GUILTY : null, "You're not aristocracy, but I suppose you'd do. Do you", "want a good cook for " + type.getCost() + " coins?");
stage = 0;
return true;
}
interpreter.sendDialogues(npc, npc.getId() == 4243 ? FacialExpression.HALF_GUILTY : null, "You need a Construction level of " + type.getLevel() + " and you must not", "currently have another person working for you", "in order to hire me.");
stage = 100;
return true;
} else {
Servant servant = manager.getServant();
if(servant.getItem() == null){
servant.setItem(new Item(0, 0));
}
if (inHouse) {
follow(player, servant);
if (sawmill) {
interpreter.sendDialogues(servant, servant.getId() == 4243 ? FacialExpression.HALF_GUILTY : null, "Very well, I will take these logs to the mill and", "have them converted into planks.");
stage = 110;
return true;
}
if (servant.getItem().getAmount() > 0) {
if(player.getInventory().freeSlots() < 1){
interpreter.sendDialogues(servant, servant.getId() == 4243 ? FacialExpression.HALF_GUILTY : null, "I have returned with what you asked me to", "retrieve. As I see your inventory is full, I shall wait", "with these " + servant.getItem().getAmount()+" items until you are ready.");
stage = 100;
return true;
}
interpreter.sendDialogues(servant, servant.getId() == 4243 ? FacialExpression.HALF_GUILTY : null, "I have returned with what you asked me to", "retrieve.");
stage = 150;
return true;
}
interpreter.sendDialogues(servant, servant.getId() == 4243 ? FacialExpression.HALF_GUILTY : null, "Yes, " + (player.getAppearance().isMale() ? "sir" : "ma'am") + "?", "You have " + (8 - servant.getUses()) + " uses of my services remaining.");
stage = 50;
} else if(npc.getId() != servant.getId()){
interpreter.sendDialogues(npc, npc.getId() == 4243 ? FacialExpression.HALF_GUILTY : null, "You already have someone working for you.", "Fire them first before hiring me.");
stage = 100;
}
}
return true;
}
@Override
public boolean handle(int interfaceId, int buttonId) {
HouseManager manager = player.getHouseManager();
Servant servant = manager.getServant();
ServantType type = ServantType.forId(npc.getId());
switch(stage) {
case 0:
options("What can you do?", "Tell me about your previous jobs.", "You're hired!");
stage++;
break;
case 1:
switch(buttonId) {
case 1: //TODO:
break;
case 2: //TODO:
break;
case 3:
player("You're hired!");
stage = 2;
break;
}
break;
case 2:
interpreter.sendDialogues(npc, npc.getId() == 4243 ? FacialExpression.HALF_GUILTY : null, "Alright, " + (player.getAppearance().isMale() ? "sir" : "ma'am") + ". I can start work immediately.");
stage++;
break;
case 3:
if (type != null && player.getInventory().getAmount(995) >= type.getCost() && player.getInventory().remove(new Item(995, type.getCost()))) {
manager.setServant(new Servant(type));
interpreter.sendDialogue("The servant heads to your house.");
stage = 100;
break;
}
interpreter.sendDialogue("You don't have enough money to pay the servant's hiring fee.");
stage = 100;
break;
case 50:
options("Go to the bank/sawmill...", "Misc...", "Stop following me.", "You're fired!");
stage++;
break;
case 51:
type = servant.getType();
switch(buttonId) {
case 1:
options(!servant.getAttributes().containsKey("con:lastfetch") ? "Repeat last fetch task" : "Fetch another " + (type.getCapacity() + " x " + ((Item) servant.getAttribute("con:lastfetch")).getName().toLowerCase()) + " (" + (servant.getAttribute("con:lastfetchtype")) + ")", "Go to the bank", "Go to the sawmill", "Pay wages (" + servant.getUses()+"/8 uses)");
stage++;
break;
case 2:
options("Greet guests", "Cook me something");
stage = 56;
break;
case 3:
player("Stop following me.");
if (servant.getPulseManager().isMovingPulse()) {
servant.getPulseManager().clear(PulseType.STANDARD);
}
stage = 100;
break;
case 4:
player("You're fired!");
stage = 75;
break;
}
break;
case 52:
switch(buttonId){
case 1:
if (!servant.getAttributes().containsKey("con:lastfetch")) {
interpreter.sendDialogues(servant, servant.getId() == 4243 ? FacialExpression.HALF_GUILTY : null, "I haven't recently fetched anything from the bank or", "sawmill for you.");
stage = 50;
break;
} else {
if (servant.getAttribute("con:lastfetchtype") == "bank") {
bankFetch(player, (Item) servant.getAttribute("con:lastfetch"));
return true;
}
end();
sawmillRun(player, (Item) servant.getAttribute("con:lastfetch"));
}
break;
case 2:
options("Planks", "Oak planks", "Teak planks", "Mahogany planks", "More options");
stage = 60;
break;
case 3:
if (type == ServantType.MAID || type == ServantType.RICK) {
interpreter.sendDialogues(servant, servant.getId() == 4243 ? FacialExpression.HALF_GUILTY : null, "I am unable to travel to the sawmill for you.");
stage = 100;
break;
}
interpreter.sendDialogues(servant, servant.getId() == 4243 ? FacialExpression.HALF_GUILTY : null, "Hand the logs to me and I will take them to the", "sawmill for you.");
stage = 100;
break;
case 4:
stage = 100;
if (servant.getUses() < 1) {
interpreter.sendDialogues(servant, servant.getId() == 4243 ? FacialExpression.HALF_GUILTY : null, "You have no need to pay me yet, I haven't performed", "any of my services for you.");
break;
}
if (!player.getInventory().containsItem(new Item(995, type.getCost()))) {
interpreter.sendDialogues(servant, servant.getId() == 4243 ? FacialExpression.HALF_GUILTY : null, "Thanks for the kind gesture, but you don't have enough", "money to pay me. I require " + type.getCost() + " coins every eight uses", "of my services.");
break;
}
if (player.getInventory().remove(new Item(995, type.getCost()))) {
interpreter.sendDialogues(servant, servant.getId() == 4243 ? FacialExpression.HALF_GUILTY : null, "Thank you very much.");
servant.setUses(0);
}
break;
}
break;
case 56:
switch(buttonId) {
case 1:
servant.setGreet(!servant.isGreet());
player("Please " + (servant.isGreet() ? "greet" : "do not greet") + " all new guests upon arrival.");
stage++;
break;
case 2:
if (type.getFood() == null) {
interpreter.sendDialogues(servant, servant.getId() == 4243 ? FacialExpression.HALF_GUILTY : null, "I don't know any recipes.");
stage = 100;
break;
}
if (type.getFood().length > 1) {
options(type.getFood()[0].getName(), type.getFood()[1].getName(), "Nevermind.");
stage = 58;
} else {
options(type.getFood()[0].getName(), "Nevermind.");
stage = 59;
}
break;
}
break;
case 57:
interpreter.sendDialogues(servant, servant.getId() == 4243 ? FacialExpression.HALF_GUILTY : null, "Whatever you command.");
stage = 50;
break;
case 58:
if (player.getInventory().freeSlots() < 1) {
interpreter.sendDialogues(servant, servant.getId() == 4243 ? FacialExpression.HALF_GUILTY : null, "I would love to share my fine cooking with you,", "but your hands are currently full.");
stage = 100;
break;
}
if (!prereqs(player, null, false)) {
end();
return true;
}
switch(buttonId) {
case 1:
player.getInventory().add(type.getFood()[0]);
stage = 50;
break;
case 2:
player.getInventory().add(type.getFood()[1]);
stage = 50;
break;
case 3:
player("Nevermind.");
stage = 100;
return true;
}
servant.setUses(servant.getUses() + 1);
interpreter.sendDialogues(servant, servant.getId() == 4243 ? FacialExpression.HALF_GUILTY : null, "Luckily for you, I already have some made. Here you", "go.");
stage = 50;
break;
case 59:
if (player.getInventory().freeSlots() < 1) {
interpreter.sendDialogues(servant, servant.getId() == 4243 ? FacialExpression.HALF_GUILTY : null, "I would love to share my fine cooking with", "you, but you have no space to take anything.");
stage = 50;
break;
}
if (!prereqs(player, null, false)) {
end();
return true;
}
switch(buttonId) {
case 1:
player.getInventory().add(type.getFood()[0]);
stage = 100;
break;
case 2:
player("Nevermind.");
stage = 100;
return true;
}
servant.setUses(servant.getUses() + 1);
interpreter.sendDialogues(servant, servant.getId() == 4243 ? FacialExpression.HALF_GUILTY : null, "Luckily for you, I already have some made. Here you", "go.");
stage = 100;
break;
case 60:
switch(buttonId) {
case 1: //planks
bankFetch(player, new Item(960));
stage = 100;
break;
case 2: //oak
bankFetch(player, new Item(8778));
stage = 100;
break;
case 3: //teak
bankFetch(player, new Item(8780));
break;
case 4: //mahog
bankFetch(player, new Item(8782));
break;
case 5:
options("Soft clay", "Limestone bricks", "Steel bars", "Cloth", "More options");
stage++;
break;
}
break;
case 61:
switch(buttonId) {
case 1: //clay
bankFetch(player, new Item(1761));
break;
case 2: //lime
bankFetch(player, new Item(3420));
break;
case 3: //steel bars
bankFetch(player, new Item(2353));
break;
case 4: //cloth
bankFetch(player, new Item(8790));
break;
case 5:
options("Gold leaves", "Marble blocks", "Magic stones");
stage++;
break;
}
break;
case 62:
switch(buttonId) {
case 1: //leaves
bankFetch(player, new Item(4692));
break;
case 2: //marble
bankFetch(player, new Item(8786));
break;
case 3: //magic stones
bankFetch(player, new Item(4703));
break;
}
break;
case 75:
interpreter.sendDialogues(servant, servant.getId() == 4243 ? FacialExpression.HALF_GUILTY : null, "Very well. I will return to the Guild of the Servants", "in Ardougne if you wish to re-hire me.");
stage++;
break;
case 76:
end();
servant.getItem().setAmount(0);
servant.setUses(0);
servant.clear();
servant.setLocation(new Location(0, 0));
manager.setServant(null);
break;
case 100:
end();
break;
case 110:
end();
sawmillRun(player, logs);
break;
case 150:
if (servant.getItem()== null) {
end();
return true;
}
int amtLeft = servant.getItem().getAmount();
boolean flag = false;
if (amtLeft < 1 || servant.getItem() == null) {
interpreter.sendDialogues(servant, servant.getId() == 4243 ? FacialExpression.HALF_GUILTY : null, "I don't have any items left.");
stage = 100;
break;
}
if (amtLeft > player.getInventory().freeSlots()) {
amtLeft = player.getInventory().freeSlots();
flag = true;
}
servant.getItem().setAmount(servant.getItem().getAmount() - amtLeft);
player.getInventory().add(new Item(servant.getItem().getId(), amtLeft));
if (flag) {
interpreter.sendDialogues(servant, servant.getId() == 4243 ? FacialExpression.HALF_GUILTY : null, "I still have " + servant.getItem().getAmount() + " left for you to take from me.");
stage = 100;
} else{
end();
}
break;
}
return true;
}
@Override
public int[] getIds() {
return new int[] { 4235, 4237, 4239, 4241, 4243 };
}
/**
* Checks the pre-reqs for a sawmill run or a bank run.
* @param player
* @param item
* @return true or false if they have the requirements to use the servant.
*/
private boolean prereqs(final Player player, final Item item, boolean sawmill) {
HouseManager manager = player.getHouseManager();
Servant servant = manager.getServant();
if (!sawmill && player.getInventory().freeSlots() < 1) {
interpreter.sendDialogues(servant, servant.getId() == 4243 ? FacialExpression.HALF_GUILTY : null, "You don't have any space in your inventory.");
stage = 100;
return false;
}
if (servant.getUses() >= 8) {
player.sendMessage("<col=CC0000>The servant has left your service due to a lack of payment.</col>");
servant.getItem().setAmount(0);
servant.setUses(0);
servant.clear();
servant.setLocation(new Location(0, 0));
manager.setServant(null);
end();
return false;
}
if (servant.getItem().getAmount() > 0) {
interpreter.sendDialogues(servant, servant.getId() == 4243 ? FacialExpression.HALF_GUILTY : null, "You can't send me off again, I'm still holding some of", "your previous items.");
return false;
}
return true;
}
/**
* Goes to the sawmill.
* @param player
* @param item
*/
private void sawmillRun(final Player player, final Item item) {
HouseManager manager = player.getHouseManager();
final Servant servant = manager.getServant();
final ServantType type = manager.getServant().getType();
if (servant == null || item == null || !prereqs(player, item, true)) {
return;
}
if (type == ServantType.MAID || type == ServantType.RICK) {
interpreter.sendDialogues(servant, servant.getId() == 4243 ? FacialExpression.HALF_GUILTY : null, "I am unable to take planks to the sawmill.");
return;
}
int amt = player.getInventory().getAmount(item);
if (amt < 1) {
interpreter.sendDialogues(servant, servant.getId() == 4243 ? FacialExpression.HALF_GUILTY : null, "You don't have any more of that type of log.");
return;
}
for (Plank plank : Plank.values()) {
if (plank.getLog().getId() == item.getId()) {
if (amt > type.getCapacity()) {
amt = type.getCapacity();
}
if (!player.getInventory().contains(995, plank.getPrice() * amt)) {
interpreter.sendDialogues(servant, servant.getId() == 4243 ? FacialExpression.HALF_GUILTY : null, "You don't have enough coins for me to do that.", "I can hold " + type.getCapacity() + " logs and each of this type of log", "costs " + plank.getPrice() + " coins each to convert into plank form.");
return;
}
end();
if (player.getInventory().remove(new Item(item.getId(), amt)) && player.getInventory().remove(new Item(995, amt * plank.getPrice()))) {
manager.getServant().setItem(new Item(plank.getPlank().getId(), amt));
servant.setInvisible(true);
servant.getLocks().lockMovement(100);
GameWorld.getPulser().submit(new Pulse((int) (type.getTimer() / 0.6)){
@Override
public boolean pulse() {
servant.setInvisible(false);
servant.getLocks().unlockMovement();
servant.setAttribute("con:lastfetch", new Item(item.getId(), 1));
servant.setAttribute("con:lastfetchtype", "sawmill");
interpreter.open(servant.getId(), servant);
return true;
}
});
}
break;
}
}
}
/**
* Gets items from the player's bank.
* @param player
* @param item
*/
private void bankFetch(final Player player, final Item item) {
final HouseManager manager = player.getHouseManager();
final Servant servant = manager.getServant();
final ServantType type = manager.getServant().getType();
if (servant == null || item == null || !prereqs(player, item, false)) {
return;
}
if (!player.getBank().containsItem(item)) {
interpreter.sendDialogues(servant, servant.getId() == 4243 ? FacialExpression.HALF_GUILTY : null, "You don't seem to have any of those in the bank.");
stage = 100;
return;
}
end();
servant.setInvisible(true);
servant.getLocks().lockMovement(100);
GameWorld.getPulser().submit(new Pulse((int) (type.getTimer() / 0.6)) {
@Override
public boolean pulse() {
if (player == null || player.getHouseManager().getHouseRegion() != player.getViewport().getRegion()) { //TODO: Check if in dungeon?
return true;
}
int amt = player.getBank().getAmount(item.getId());
if (amt < 1) {
return true;
}
if (amt > type.getCapacity()) {
amt = type.getCapacity();
}
servant.setInvisible(false);
servant.getLocks().unlockMovement();
Item fetch = new Item(item.getId(), amt);
if (player.getBank().remove(fetch)) {
manager.getServant().setItem(fetch);
interpreter.open(servant.getId(), servant);
}
servant.setAttribute("con:lastfetch", new Item(fetch.getId(), 1));
servant.setAttribute("con:lastfetchtype", "bank");
manager.getServant().setUses(manager.getServant().getUses() + 1);
follow(player, servant);
return true;
}
});
}
/**
* Follows the person who is talking to them.
* @param player
* @param npc
*/
private void follow(Player player, NPC npc) {
npc.getPulseManager().run(new MovementPulse(npc, player, Pathfinder.SMART) {
@Override
public boolean pulse() {
return false;
}
}, PulseType.STANDARD);
}
}
@@ -0,0 +1,55 @@
package content.global.skill.construction.npc;
import core.game.interaction.NodeUsageEvent;
import core.game.interaction.UseWithHandler;
import core.plugin.Initializable;
import core.plugin.Plugin;
import core.plugin.ClassScanner;
/**
* Handles interaction with the house servant.
* @author Splinter
* @date 9/24/2015
* @version 0.1
*
* @see {@link HouseServantDialogue}
* For the other associated classes that deal with house servants.
*
*/
@Initializable
public class HouseServantPlugin extends UseWithHandler {
/**
* The item IDS to use.
*/
final static int[] IDS = { 1511, 1521, 6333, 6332 };
/**
* Constructs a new {@code HouseServantPlugin} {@code Object}.
*/
public HouseServantPlugin() {
super(IDS);
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
addHandler(4235, NPC_TYPE, this);
addHandler(4237, NPC_TYPE, this);
addHandler(4239, NPC_TYPE, this);
addHandler(4241, NPC_TYPE, this);
addHandler(4243, NPC_TYPE, this);
ClassScanner.definePlugin(new HouseServantDialogue());
return this;
}
@Override
public boolean handle(NodeUsageEvent event) {
if (event.getUsedItem() == null || event.getUsedWith() == null) {
return true;
}
event.getPlayer().getDialogueInterpreter().open(event.getUsedWith().asNpc().getId(), event.getUsedWith().asNpc(), true, event.getUsedItem());
return true;
}
}
@@ -0,0 +1,76 @@
package content.global.skill.construction.npc;
import core.cache.def.impl.ItemDefinition;
import core.cache.def.impl.NPCDefinition;
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 Keldagrim Stonemason.
* @author Splinter
*/
@Initializable
public class StonemasonPlugin extends OptionHandler {
/*
*//**
* The store that sells supplies.
*//*
private static final SupplyStore STORE = new SupplyStore();*/
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
NPCDefinition.forId(4248).getHandlers().put("option:trade", this);
NPCDefinition.forId(4248).getHandlers().put("option:talk-to", this);
return this;
}
@Override
public boolean handle(Player player, Node node, String option) {
switch (option) {
case "trade":
case "talk-to":
break;
}
return true;
}
/*
*//**
* Stonemason's store.
* @author Splinter
*//*
public static class SupplyStore extends Shop {
*//**
* Constructs a new {@Code SupplyStore} {@Code Object}
*//*
public SupplyStore() {
super("Keldagrim Stonemason", new Item[] { new Item(3420, 1000), new Item(8786, 20), new Item(8784, 20), new Item(8788, 10) }, false);
}
@Override
public boolean canSell(Player player, Item item, ItemDefinition def) {
player.sendMessage("You cannot sell items to this store.");
return false;
}
@Override
public int getBuyPrice(Item item, Player player) {
switch (item.getId()) {
case 3420:
return 26;
case 8786:
return 325_000;
case 8784:
return 130_000;
case 8788:
return 975_000;
}
return -1;
}
}*/
}
@@ -0,0 +1,69 @@
package content.global.skill.cooking;
import core.game.interaction.NodeUsageEvent;
import core.game.interaction.UseWithHandler;
import core.game.node.item.Item;
import core.plugin.Initializable;
import core.plugin.Plugin;
/**
* Represents the plugin used to make a cake.
* @author 'Vexia
* @version 1.0
*/
@Initializable
public final class CakeMakingPlugin extends UseWithHandler {
/**
* Represents the bucket of milk item.
*/
private static final Item BUCKET_OF_MILK = new Item(1927);
/**
* Represents the egg item.
*/
private static final Item EGG = new Item(1944);
/**
* Represents the cake tin item.
*/
private static final Item CAKE_TIN = new Item(1887);
/**
* Represents the pot of flour item.
*/
private static final Item POT_OF_FLOUR = new Item(1933);
/**
* Represents the uncooked cake item.
*/
private static final Item UNCOOKED_CAKE = new Item(1889);
/**
* Constructs a new {@code CakeMakingPlugin} {@code Object}.
*/
public CakeMakingPlugin() {
super(1933);
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
addHandler(1887, ITEM_TYPE, this);
return this;
}
@Override
public boolean handle(NodeUsageEvent event) {
if (event.getUsedItem().getId() == 1887 && ((Item) event.getUsedWith()).getId() == 1933 || event.getUsedWith().getName().equalsIgnoreCase("cake tin") && ((Item) event.getUsedItem()).getName().equalsIgnoreCase("pot of flour")) {
if (event.getPlayer().getInventory().contains(1933, 1) && event.getPlayer().getInventory().contains(1927, 1) && event.getPlayer().getInventory().contains(1944, 1)) {
if (event.getPlayer().getInventory().remove(BUCKET_OF_MILK, EGG, CAKE_TIN, POT_OF_FLOUR)) {
event.getPlayer().getInventory().add(UNCOOKED_CAKE);
event.getPlayer().getPacketDispatch().sendMessage("You mix the milk, flour and egg together to make a raw cake mix.");
return true;
}
}
}
return false;
}
}
@@ -0,0 +1,34 @@
package content.global.skill.cooking
import core.game.interaction.NodeUsageEvent
import core.game.interaction.UseWithHandler
import core.game.node.item.Item
import core.game.system.task.Pulse
import core.game.world.update.flag.context.Animation
import core.plugin.Initializable
import core.plugin.Plugin
import org.rs09.consts.Items
@Initializable
class ChocolateBarCutter : UseWithHandler(946){
override fun newInstance(arg: Any?): Plugin<Any> {
addHandler(1973, ITEM_TYPE, this)
return this
}
override fun handle(event: NodeUsageEvent?): Boolean {
event ?: return false
val player = event.player
player.pulseManager.run(object : Pulse(1){
val cut_animation = Animation(1989)
override fun pulse(): Boolean {
super.setDelay(4)
val amount = player.inventory.getAmount(Items.CHOCOLATE_BAR_1973)
if(amount > 0) player.inventory.remove(Item(1973)).also { player.animator.animate(cut_animation); player.inventory.add(Item(1975)) }
return amount <= 0
}
})
return true
}
}
@@ -0,0 +1,56 @@
package content.global.skill.cooking;
import core.game.interaction.NodeUsageEvent;
import core.game.interaction.UseWithHandler;
import core.game.node.entity.player.Player;
import core.game.node.item.Item;
import core.plugin.Initializable;
import core.plugin.Plugin;
/**
* Represents the plugin used to make a coconut.
* @author 'Vexia
* @version 1.0
*/
@Initializable
public final class CoconutMakePlugin extends UseWithHandler {
/**
* Represents the items related to coconut making plugin.
*/
private static final Item[] ITEMS = new Item[] { new Item(5974, 1), new Item(5976, 1), new Item(229), new Item(5935, 1), new Item(5978) };
/**
* Constructs a new {@code CoconutMakePlugin} {@code Object}.
*/
public CoconutMakePlugin() {
super(5974, 5976);
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
addHandler(2347, ITEM_TYPE, this);
addHandler(229, ITEM_TYPE, this);
return this;
}
@Override
public boolean handle(NodeUsageEvent event) {
final Player player = event.getPlayer();
final Item usedWith = (Item) event.getUsedWith();
if (usedWith.getId() == 5974 && event.getUsedItem().getId() == 2347 || usedWith.getId() == 2347 && event.getUsedItem().getId() == 5974) {
player.getInventory().remove(ITEMS[0]);
player.getInventory().add(ITEMS[1]);
player.getPacketDispatch().sendMessage("You crush the coconut with a hammer.");
}
if (usedWith.getId() == 5976 && event.getUsedItem().getId() == 229 || usedWith.getId() == 229 && event.getUsedItem().getId() == 5976) {
player.getInventory().remove(ITEMS[1]);
player.getInventory().remove(ITEMS[2]);
player.getInventory().add(ITEMS[3]);
player.getInventory().add(ITEMS[4]);
player.getPacketDispatch().sendMessage("You overturn the coconut into a vial.");
}
return true;
}
}
@@ -0,0 +1,153 @@
package content.global.skill.cooking;
import org.rs09.consts.Items;
import core.game.node.item.Item;
import java.util.HashMap;
public enum CookableItems {
/** meats */
CHICKEN(2140,2138,2144,1,30,34,128,512),
UGTHANKI(2140,2138,2144,1,40,100,0,512),
RABBIT(3228,3226,7222,1,30,34,128,512),
CRAB(7521, 7518, 7520,21, 100, 62,85,438),
/** fish */
CRAYFISH(13433, 13435, 13437,1, 30, 34,128,512),
SHRIMP(315, 317, 7954,1, 30, 34,128,512),
KARAMBWANJI(3151, 3150, 592,1, 10, 28,128,512),
SARDINE(325, 327, 369,1, 40, 38,118,492),
ANCHOVIES(319, 321, 323,1, 30, 34,128,512),
HERRING(347, 345, 357,5, 50, 41,108,472),
MACKEREL(355, 353, 357,10, 60, 45,98,452),
TROUT(333, 335, 343,15, 70, 50,88,432),
COD(339, 341, 343,18, 75, 52,74,420),
PIKE(351, 349, 343,20, 80, 53,78,412),
SALMON(329, 331, 343,25, 90, 58,68,392),
SLIMY_EEL(3381, 3379, 3383,28, 95, 58,72,406),
TUNA(361, 359, 367,30, 100, 65,58,372),
RAINBOW_FISH(10136, 10138, 10140,35, 110, 60,48,387),
CAVE_EEL(5003, 5001, 5002,38, 115, 74,42,386),
LOBSTER(379, 377, 381,40, 120, 74,38,332),
BASS(365, 363, 367,43, 130, 79,28,312),
SWORDFISH(373, 371, 375,45, 140, 86,18,292),
LAVA_EEL(2149, 2148, 3383,53, 30, 53,12,282),
MONKFISH(7946, 7944, 7948,62, 150, 92,11,275),
SHARK(385, 383, 387,80, 210, 100,0,202),
SEA_TURTLE(397, 395, 399,82, 212, 100,0,202),
MANTA_RAY(391, 389, 393,91, 216, 100,0,202),
KARAMBWAN(3144, 3142, 3146,30, 190, 100,0,255),
/** snails */
THIN_SNAIL(3369, 3363, 3375,12, 70, 47,109,502),
LEAN_SNAIL(3371, 3365, 3375,17, 80, 50,100,486),
FAT_SNAIL(3373, 3367, 3375,22, 95, 56,95,456),
//Bread
BREAD(2309, 2307, 2311,1,40,37,118,492),
//Cake
CAKE(1891, 1889, 1903, 40, 180, 74,38,332),
//Beef(s) (Rat, Bear, Cow, Yak)
BEEF(2142,2132,2146,1,30,34,128,512),
RAT_MEAT(2142,2134,2146,1,30,34,128,512),
BEAR_MEAT(2142,2136,2146,1,30,34,128,512),
YAK_MEAT(2142,10816,2146,1,30,34,128,512),
//Skewered foods
SKEWER_ROAST_BEAST(9988, 9986, 9990,21, 99, 82,108,496),
SKEWER_CHOMPY(2878, 2876, 7226,30, 140, 99,85,476),
SKEWER_JUBBLY(7568, 7566, 7570,41, 160, 140,75,456),
SKEWER_ROAST_BIRD(9980, 9984, 9982,11, 62, 99,115,502),
SKEWER_ROAST_RABBIT(7223, 7224, 7222,16, 72, 99,113,499),
//Pies
PIE_REDBERRY(2325, 2321, 2329, 10, 78, 50,78,412),
PIE_MEAT(2327, 2319, 2329, 20, 110, 53,78,412),
PIE_MUD(7170, 7168, 2329, 29,128,63,78,412),
PIE_APPLE(2323,2317,2329,30,130,63,78,412),
GARDEN_PIE(7178,7176,2329,34,138, 68,78,412),
FISH_PIE(7188,7186,2329,47,164,74,78,412),
ADMIRAL_PIE(7198,7196,2329,70,210,94,78,412),
WILD_PIE(7208,7206,2329,85,240,140,78,412),
SUMMER_PIE(7218,7216,2329,95,260,160,78,412),
//Pizzas
PIZZA_PLAIN(2289, 2287,2305, 35, 143, 68,48,352),
//Bowl foods
BOWL_STEW(2003, 2001, 2005,25, 117, 58,68,392),
BOWL_NETTLE(4239, 4237, 4239,20, 52, 1,68,392),
BOWL_EGG(7078, 7076, 7090,13, 50, 48,68,392),
BOWL_ONION(7084, 1871, 7092,43, 60, 77,68,392),
BOWL_MUSHROOM(7082, 7080, 7094,46, 60, 90,68,392),
/* Vegetables */
BAKED_POTATO(6701, 1942, 6699, 7, 15, 41, 108, 472),
SWEETCORN(5988, 5986, 5990, 28, 104, 54, 90, 424),
//Miscellaneous
RAW_OOMLIE(Items.RAW_OOMLIE_2337, 0, Items.BURNT_OOMLIE_2426, 50, 0, 999,0,0), // always burns
OOMLIE_WRAP(Items.COOKED_OOMLIE_WRAP_2343, Items.WRAPPED_OOMLIE_2341, Items.BURNT_OOMLIE_WRAP_2345, 50, 110, 999,0,0),
SEAWEED(Items.SEAWEED_401,0,Items.SODA_ASH_1781,0,0,999,0,0),
/**
* Sinew gets overridden by BEEF in this enum, due to values being looked up by the items RAW id.
* This gets corrected in {@link SinewCookingPulse}
*/
SINEW(Items.SINEW_9436,Items.RAW_BEEF_2132,Items.SINEW_9436,0,3,0,0,0);
public final static HashMap<Integer,CookableItems>cookingMap = new HashMap<>();
public final static HashMap<Integer, CookableItems>intentionalBurnMap = new HashMap<>();
public final int raw,cooked,level,burnLevel,burnt;
public final double experience;
double low,high;
CookableItems(int cooked, int raw, int burnt, int level, double experience, int burnLevel, double low, double high){
this.raw = raw;
this.cooked = cooked;
this.burnt = burnt;
this.level = level;
this.experience = experience;
this.burnLevel = burnLevel;
this.low = low;
this.high = high;
}
static{
CookableItems[] cookableItems = values();
int cookableItemsLength = cookableItems.length;
for(int x = 0; x < cookableItemsLength; x++){
CookableItems item = cookableItems[x];
cookingMap.putIfAbsent(item.raw,item);
intentionalBurnMap.putIfAbsent(item.cooked,item);
}
}
public static CookableItems forId(int id){
return cookingMap.get(id);
}
public static Item getCooked(int id){
return new Item(cookingMap.get(id).cooked);
}
public static Item getBurnt(int id){
return new Item(cookingMap.get(id).burnt);
}
public static Item getRaw(int id){
return new Item(cookingMap.get(id).raw);
}
public static boolean intentionalBurn(int id){
return (intentionalBurnMap.get(id) != null);
}
public static Item getIntentionalBurn(int id){
return new Item(intentionalBurnMap.get(id).burnt);
}
public static int getBurnLevel(int id){
return cookingMap.get(id).burnLevel;
}
}
@@ -0,0 +1,110 @@
package content.global.skill.cooking
import core.api.*
import core.cache.def.impl.ItemDefinition
import core.game.node.scenery.Scenery
import content.global.skill.cooking.CookableItems
import content.global.skill.cooking.CookingRewrite.Companion.cook
import core.net.packet.PacketRepository
import core.net.packet.context.ChildPositionContext
import core.net.packet.out.RepositionChild
import org.rs09.consts.Items
import core.game.dialogue.DialogueFile
import core.tools.START_DIALOGUE
/**
* @author Ceikry
* @author bushtail - fixing it up
*/
class CookingDialogue(vararg val args: Any) : DialogueFile(){
var initial = 0
var product = 0
var `object`: Scenery? = null
var sinew = false
var itemid = 0
override fun handle(componentID: Int, buttonID: Int) {
when(stage){
START_DIALOGUE -> {
when (args.size) {
2 -> {
initial = args.get(0) as Int
if (CookableItems.intentionalBurn(initial)) { // checks intentional burning
product = CookableItems.getIntentionalBurn(initial).id
} else {
product = CookableItems.forId(initial).cooked
}
`object` = args.get(1) as Scenery
}
5 -> {
initial = args.get(0) as Int
product = args.get(1) as Int
sinew = args.get(2) as Boolean
`object` = args.get(3) as Scenery
itemid = args.get(4) as Int
if (sinew) {
options(
"Dry the meat into sinew",
"Cook the meat"
)
stage = 100
return
}
}
}
display()
}
1 -> {
end()
val amount = getAmount(buttonID)
when (amount) {
-1 -> sendInputDialogue(player!!, true, "Enter the amount:") { value ->
if (value is String) {
cook(player!!, `object`, initial, product, value.toInt())
} else {
cook(player!!, `object`, initial, product, value as Int)
}
}
else -> {
end()
cook(player!!, `object`, initial, product, amount)
}
}
}
100 -> {
when (buttonID) {
1 -> {
product = Items.SINEW_9436
display(Items.COOKED_MEAT_2142)
}
2 -> {
product = CookableItems.forId(initial).cooked
display()
}
}
}
}
}
private fun getAmount(buttonId: Int): Int {
when (buttonId) {
5 -> return 1
4 -> return 5
3 -> return -1
2 -> return player!!.inventory.getAmount(initial)
}
return -1
}
fun display(vararg args : Int) {
player!!.interfaceManager.openChatbox(307)
PacketRepository.send(RepositionChild::class.java, ChildPositionContext(player, 307, 3, 60, 90))
PacketRepository.send(RepositionChild::class.java, ChildPositionContext(player, 307, 2, 208, 20))
player!!.packetDispatch.sendItemZoomOnInterface(if(args.size == 1) args[0] else product, 160, 307, 2)
player!!.packetDispatch.sendString(ItemDefinition.forId(product).name, 307, 3)
stage = 1
}
}
@@ -0,0 +1,199 @@
/*
package core.game.node.entity.skill.cooking;
import core.game.dialogue.DialoguePlugin;
import org.crandor.game.content.global.consumable.Consumables;
import org.crandor.game.content.global.consumable.Food;
import core.game.node.entity.skill.cooking.CookableItems;
import core.game.node.entity.skill.cooking.CookingPulse;
import org.crandor.game.node.entity.player.Player;
import org.crandor.game.node.entity.player.link.RunScript;
import org.crandor.game.node.item.Item;
import org.crandor.game.node.object.GameObject;
import org.crandor.net.packet.PacketRepository;
import org.crandor.net.packet.context.ChildPositionContext;
import org.crandor.net.packet.out.RepositionChild;
import org.crandor.plugin.InitializablePlugin;
*/
/**
* Represents the dialogue used to handle the amount to make of a cookable item.
* @author 'Vexia
* @version 1.0
*//*
@InitializablePlugin
public final class CookingDialoguePlugin extends DialoguePlugin {
*/
/**
* Represents the cooking dialogue id.
*//*
public static final int DIALOGUE_ID = 43989;
*/
/**
* Represents the sinew item.
*//*
private static final Item SINEW = new Item(9436);
*/
/**
* Represents the meat item.
*//*
private static final Item MEAT = new Item(2142);
*/
/**
* Represents the food we're cooking.
*//*
private int food;
*/
/**
* Represents the obejct we're cooking on.
*//*
private GameObject object;
*/
/**
* Constructs a new {@code CookingDialoguePlugin} {@code Object}.
*//*
public CookingDialoguePlugin() {
*/
/**
* empty.
*//*
}
*/
/**
* Constructs a new {@code CookingDialoguePlugin} {@code Object}.
* @param player the player.
*//*
public CookingDialoguePlugin(Player player) {
super(player);
}
@Override
public DialoguePlugin newInstance(Player player) {
return new CookingDialoguePlugin(player);
}
@Override
public boolean open(Object... args) {
food = ((int) args[0]);
object = ((GameObject) args[1]);
if (args.length == 3) {
interpreter.sendOptions("Select an Option", "Dry the meat into sinew.", "Cook the meat.");
stage = 100;
return true;
}
if (player.getInventory().getAmount(CookableItems.forId(food).raw) == 1) {
end();
cook(player,object,food,1);
return true;
}
display();
stage = 0;
return true;
}
@Override
public boolean handle(int interfaceId, int buttonId) {
switch (stage) {
case 0:
end();
int amount = getAmount(buttonId);
if (amount == -1) {
player.setAttribute("runscript", new RunScript() {
@Override
public boolean handle() {
int amount = (int) value;
cook(player, object, food, amount);
return false;
}
});
player.getDialogueInterpreter().sendInput(false, "Enter the amount:");
} else if (amount == 28) {
player.setAttribute("runscript", new RunScript() {
@Override
public boolean handle() {
cook(player, object, food, amount);
return false;
}
});
}
cook(player, object, food, amount);
break;
*/
/*case 100:
switch (buttonId) {
case 1:
food = Consumables.forFood(SINEW);
display();
break;
case 2:
food = Consumables.forFood(MEAT);
display();
break;
}
break;*//*
}
return true;
}
@Override
public int[] getIds() {
return new int[] { DIALOGUE_ID };
}
*/
/**
* Method used to display the content food.
*//*
public void display() {
player.getInterfaceManager().openChatbox(307);
PacketRepository.send(RepositionChild.class, new ChildPositionContext(player, 307, 3, 60, 79));
player.getPacketDispatch().sendItemZoomOnInterface(CookableItems.getRaw(food).getId(), 160, 307, 2);
player.getPacketDispatch().sendString(CookableItems.getRaw(food).getName(), 307, 3);
stage = 0;
}
public void cook(Player player, GameObject object, int food, int amount){
player.getPulseManager().run(new CookingPulse(player,object,food,amount));
}
*/
/**
* Method used to get the amount to make based off the button id.
* @param buttonId the button id.
* @return the amount to make.
*//*
private final int getAmount(final int buttonId) {
switch (buttonId) {
case 5:
return 1;
case 4:
return 5;
case 3:
return -1;
case 2:
return 28;
}
return -1;
}
}
*/
@@ -0,0 +1,263 @@
/*
package core.game.node.entity.skill.cooking;
import org.crandor.cache.def.impl.ItemDefinition;
import core.game.dialogue.DialoguePlugin;
import org.crandor.game.content.global.consumable.Consumables;
import org.crandor.game.content.global.consumable.Food;
import core.game.node.entity.skill.cooking.CookableItems;
import core.game.node.entity.skill.cooking.CookingPulse;
import org.crandor.game.interaction.NodeUsageEvent;
import org.crandor.game.interaction.UseWithHandler;
import org.crandor.game.node.Node;
import org.crandor.game.node.entity.player.Player;
import org.crandor.game.node.entity.player.link.RunScript;
import org.crandor.game.node.item.Item;
import org.crandor.game.node.object.GameObject;
import org.crandor.game.world.map.Direction;
import org.crandor.game.world.map.Location;
import org.crandor.net.packet.PacketRepository;
import org.crandor.net.packet.context.ChildPositionContext;
import org.crandor.net.packet.out.RepositionChild;
import org.crandor.plugin.InitializablePlugin;
import org.crandor.plugin.Plugin;
*/
/**
* Handles the interaction of a raw food (or if intentionally burning cooked food)
* with a range/fire.
* @author ceik
*//*
@InitializablePlugin
public class CookingPlugin extends UseWithHandler {
public static int DIALOGUE_ID = 43989;
*/
/**
* Represents the objects allowed to cook {@code Food} on.
*//*
public static final int[] OBJECTS = new int[] { 21302, 13528, 13529, 13533, 13531, 13536, 13539, 13542, 2728, 2729, 2730, 2731, 2732, 2859, 3038, 3039, 3769, 3775, 4265, 4266, 5249, 5499, 5631, 5632, 5981, 9682, 10433, 11404, 11405, 11406, 12102, 12796, 13337, 13881, 14169, 14919, 15156, 20000, 20001, 21620, 21792, 22713, 22714, 23046, 24283, 24284, 25155, 25156, 25465, 25730, 27297, 29139, 30017, 32099, 33500, 34495, 34546, 36973, 37597, 37629, 37726, 114, 4172, 5275, 8750, 16893, 22154, 34410, 34565, 114, 9085, 9086, 9087, 12269, 15398, 25440, 25441, 2724, 2725, 2726, 4618, 4650, 5165, 6093, 6094, 6095, 6096, 8712, 9439, 9440, 9441, 10824, 17640, 17641, 17642, 17643, 18039, 21795, 24285, 24329, 27251, 33498, 35449, 36815, 36816, 37426, 40110 };
*/
/**
* Constructs a new {@code CookingPlugin} {@code Object}.
*//*
public CookingPlugin() {
super(2140, 1861, 3228, 7521, 3151, 325, 319, 347, 355, 333, 339, 351, 329, 3381, 361, 10136, 5003, 379, 365, 373, 2149, 7946, 385, 397, 391, 3369, 3371, 3373, 1893, 1895, 1897, 1899, 1901, 1963, 2102, 2120, 2108, 5972, 5504, 1982, 1965, 1957, 5988, 1781, 6701, 6703, 6705, 7056, 7058, 7060, 1933, 1783, 1927, 1929, 6032, 6034, 2011, 227, 1921, 1937, 7934, 7086, 4239, 7068, 7086, 2003, 7078, 7072, 4239, 7062, 7064, 7084, 1871, 7082, 2309, 1891, 1967, 1971, 2142, 9436, 2142, 2142, 2325, 2333, 2327, 2331, 7170, 2323, 2335, 7178, 7180, 7188, 7190, 7198, 7200, 7208, 7210, 7218, 7220, 2289, 2291, 2293, 2295, 2297, 2299, 2301, 2303, 315, 9988, 2878, 7568, 9980, 7223, 5982, 598, 4293, 10816, 2138, 2134, 3142, 2136, 1859, 3226, 7518, 3150, 327, 321, 345, 353, 335, 341, 349, 331, 3379, 359, 10138, 5001, 377, 363, 371, 2148, 7944, 383, 395, 389, 3363, 3365, 3367, 5986, 401, 1942, 4237, 2001, 7076, 1871, 7080, 2307, 1889, 2132, 2132, 2132, 2132, 2321, 2319, 7168, 2317, 7176, 7186, 7196, 7206, 7216, 2287, 317, 9986, 2876, 7566, 9984, 7224);
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
new CookingDialoguePlugin().init();
for (int object : OBJECTS) {
addHandler(object, OBJECT_TYPE, this);
}
return this;
}
@Override
public boolean handle(NodeUsageEvent event) {
final GameObject object = (GameObject) event.getUsedWith();
final int food = event.getUsedItem().getId();
//handles intentional burning (deprecates BurnMeatPlugin)
if(CookableItems.intentionalBurn(food)){
event.getPlayer().getPulseManager().run(new CookingPulse(event.getPlayer(),object,event.getUsedItem().getId(),true));
return true;
}
event.getPlayer().getDialogueInterpreter().open(DIALOGUE_ID, food, event.getUsedWith());
return true;
}
@Override
public Location getDestination(final Player player, final Node node) {
if (node.getName().toLowerCase().equals("fire")) {
return player.getLocation().getY() > node.getLocation().getY() ? node.getLocation().transform(0, 1, 0) : player.getLocation().getX() < node.getLocation().getX() ? node.getLocation().transform(-1, 0, 0) : player.getLocation().getX() > node.getLocation().getX() ? node.getLocation().transform(1, 0, 0) : node.getLocation().transform(0, -1, 0);
} else {
Direction direction = node.getDirection();
if (direction == Direction.NORTH) {
return node.getLocation().transform(1, 1, 0);
} else if (direction == Direction.SOUTH) {
return node.getLocation().transform(-1, 0, 0);
}
return null;
}
}
public final class CookingDialoguePlugin extends DialoguePlugin {
*/
/**
* Represents the sinew item.
*//*
private final Item SINEW = new Item(9436);
*/
/**
* Represents the meat item.
*//*
private final Item MEAT = new Item(2142);
*/
/**
* Represents the food we're cooking.
*//*
private int food;
private int product;
private boolean nonFood = false;
*/
/**
* Represents the obejct we're cooking on.
*//*
private GameObject object;
*/
/**
* Constructs a new {@code CookingDialoguePlugin} {@code Object}.
*//*
public CookingDialoguePlugin() {
*/
/**
* empty.
*//*
}
*/
/**
* Constructs a new {@code CookingDialoguePlugin} {@code Object}.
* @param player the player.
*//*
public CookingDialoguePlugin(Player player) {
super(player);
}
@Override
public DialoguePlugin newInstance(Player player) {
return new CookingDialoguePlugin(player);
}
@Override
public boolean open(Object... args) {
food = ((int) args[0]);
if (args.length == 3){
nonFood = true;
stage = 0;
product = (int)args[1];
display();
return true;
}
if (player.getInventory().getAmount(CookableItems.forId(food).raw) == 1) {
end();
cook(player,object,food,1);
return true;
}
display();
stage = 0;
return true;
}
@Override
public boolean handle(int interfaceId, int buttonId) {
switch (stage) {
case 0:
end();
int amount = getAmount(buttonId);
if (amount == -1) {
player.setAttribute("runscript", new RunScript() {
@Override
public boolean handle() {
int amount = (int) value;
if(nonFood){
cookNonFood(player,food,product,amount);
return false;
}
cook(player, object, food, amount);
return false;
}
});
player.getDialogueInterpreter().sendInput(false, "Enter the amount:");
} else if (amount == 28) {
player.setAttribute("runscript", new RunScript() {
@Override
public boolean handle() {
if(nonFood){
cookNonFood(player,food,product,amount);
}
cook(player, object, food, amount);
return false;
}
});
}
if(nonFood){
cookNonFood(player,food,product,amount);
break;
}
cook(player, object, food, amount);
break;
}
return true;
}
@Override
public int[] getIds() {
return new int[] { DIALOGUE_ID };
}
*/
/**
* Method used to display the content food.
*//*
public void display() {
player.getInterfaceManager().openChatbox(307);
PacketRepository.send(RepositionChild.class, new ChildPositionContext(player, 307, 3, 60, 79));
player.getPacketDispatch().sendItemZoomOnInterface(nonFood ? product : CookableItems.getCooked(food).getId(), 160, 307, 2);
player.getPacketDispatch().sendString(nonFood ? ItemDefinition.forId(product).getName() : CookableItems.getCooked(food).getName(), 307, 3);
stage = 0;
}
public void cookNonFood(Player player, int food, int product, int amount){
player.getPulseManager().run(new CookingPulse(player,food,amount,product,false));
}
public void cook(Player player, GameObject object, int food, int amount){
player.getPulseManager().run(new CookingPulse(player,object,food,amount));
}
*/
/**
* Method used to get the amount to make based off the button id.
* @param buttonId the button id.
* @return the amount to make.
*//*
private final int getAmount(final int buttonId) {
switch (buttonId) {
case 5:
return 1;
case 4:
return 5;
case 3:
return -1;
case 2:
return 28;
}
return -1;
}
}
}
*/
@@ -0,0 +1,244 @@
/*
package core.game.node.entity.skill.cooking;
import org.crandor.game.content.global.SkillcapePerks;
import plugin.tutorial.TutorialSession;
import plugin.tutorial.TutorialStage;
import core.game.node.entity.skill.SkillPulse;
import core.game.node.entity.skill.Skills;
import org.crandor.game.node.entity.impl.Animator;
import org.crandor.game.node.entity.player.Player;
import org.crandor.game.node.entity.player.link.audio.Audio;
import org.crandor.game.node.entity.player.link.diary.DiaryType;
import org.crandor.game.node.item.Item;
import org.crandor.game.node.object.GameObject;
import org.crandor.game.system.task.Pulse;
import org.crandor.game.world.update.flag.context.Animation;
import static org.crandor.tools.RandomFunction.RANDOM;
*/
/**
* Pulse for cooking
* @author ceik
*//*
public final class CookingPulse extends Pulse {
private static Player player;
private static GameObject node;
private static boolean intentionalBurn = false;
//range animation
private static final Animation RANGE_ANIMATION = new Animation(883, Animator.Priority.HIGH);
//fire animation
private static final Animation FIRE_ANIMATION = new Animation(897, Animator.Priority.HIGH);
//Cooking sound
public static final Audio SOUND = new Audio(2393, 1, 1);
//food's ID
private final int food;
//amount to cook
private int amount;
//whether or not we are cooking food
private boolean isFood = true;
*/
/**
* Constructs a new {@code CookingPulse} {@code Object}.
* @param player the player.
* @param node the object node (fire/range)
* @param food the food to cook.
* @param amount the amount to cook
*//*
public CookingPulse(Player player, GameObject node, final int food, final int amount) {
this.player = player;
this.node = node;
this.food = food;
this.amount = amount;
}
*/
/**
* Another constructor for the Cooking Pulse, this time flags it as an intentional burn
* @param player the player cooking
* @param node the object being used to cook (range/fire)
* @param food the item being cooked
* @param intentionalBurn whether or not it's an intentional burn
*//*
public CookingPulse(Player player, GameObject node, final int food, final boolean intentionalBurn) {
this.player = player;
this.food = food;
this.amount = 1;
this.intentionalBurn = intentionalBurn;
}
*/
/**
* handler for cooking non-food items
* @param player the player cooking
* @param item the item being cooked
* @param amount the amount the player has
* @param isFood whether we are cooking food
*//*
public CookingPulse(Player player, final int item, int amount, int product, final boolean isFood){
this.player = player;
this.food = item;
this.amount = amount;
this.isFood = isFood;
}
@Override
public void start() {
if (intentionalBurn || checkRequirements()) {
super.start();
}
}
@Override
public boolean pulse() {
if(intentionallyBurn(food) || !checkRequirements()){
return true;
}
return reward();
}
public boolean checkRequirements() { //check if the player has the requirements
if (!node.isActive()) {
return true;
}
//handle cook's assistant range
if(node.getId() == 114 && !player.getQuestRepository().isComplete("Cook's Assistant")){
player.getPacketDispatch().sendMessage("You need to have completed the Cook's Assistant quest in order to use that range.");
return false;
}
if (player.getSkills().getLevel(Skills.COOKING) < CookableItems.forId(food).level) {
player.getDialogueInterpreter().sendDialogue("You need a cooking level of " + CookableItems.forId(food).level + " to cook this.");
return false;
}
int inventoryAmount = player.getInventory().getAmount(CookableItems.forId(food).raw);
if (amount > inventoryAmount) {
amount = inventoryAmount;
}
if (amount < 1) {
return false;
}
return true;
}
public void animate() {
player.animate(getAnimation(node));
}
public boolean reward() {
if (getDelay() == 1) {
setDelay(node.getName().toLowerCase().equals("range") ? 5 : 4);
return false;
}
//handle tutorial stuff
if(!TutorialSession.getExtension(player).finished()){
updateTutorial(player);
amount --;
return true;
}
if (cook(player,node,isBurned(player,node,food),food)) {
amount--;
} else {
return true;
}
return amount < 1;
}
public boolean cook(final Player player, final GameObject object, final boolean burned, final int food) {
Item item = CookableItems.getRaw(food);
if(intentionalBurn){ //stops the cook function from being ran if we burning on purpose
return false;
}
//lumbridge diary
if (CookableItems.forId(food) != null && player.getInventory().remove(item)) {
if (!burned) {
player.getInventory().add(CookableItems.getCooked(food));
} else {
player.getInventory().add(CookableItems.getBurnt(food));
}
player.getSkills().addExperience(Skills.COOKING, burned ? 0 : CookableItems.forId(food).experience, true);
player.getPacketDispatch().sendMessage(getMessage(item, burned));
player.getAudioManager().send(SOUND);
return true;
}
return false;
}
public boolean intentionallyBurn(int food){
if(intentionalBurn && player.getInventory().remove(new Item(food))){ //only runs if it's flagged as intentional burning
player.getInventory().add(CookableItems.getIntentionalBurn(food));
player.getPacketDispatch().sendMessage("You deliberately burn the perfectly good piece of meat.");
return true;
} else {
return false;
}
}
public String getMessage(Item food, boolean burned){
if(!burned) {
return "You manage to cook some " + food.getName().replace("Raw ", "");
} else {
return "You accidentally burn some " + food.getName().replace("Raw ","");
}
}
public boolean isBurned(final Player player, final GameObject object, int food) {
double burn_stop = (double)CookableItems.getBurnLevel(food);
if (SkillcapePerks.hasSkillcapePerk(player, SkillcapePerks.COOKING)) {
return false;
}
if (player.getSkills().getLevel(Skills.COOKING) > burn_stop) {
return false;
}
double burn_chance = 60.0 + (object.getName().equals("fire") ? 1.00 : 0) - (object.getId() == 114 ? 1.00 : 0);
double cook_level = (double) player.getSkills().getLevel(Skills.COOKING);
double lev_needed = (double) CookableItems.forId(food).level;
double multi_a = (burn_stop - lev_needed);
double burn_dec = (burn_chance / multi_a);
double multi_b = (cook_level - lev_needed);
burn_chance -= (multi_b * burn_dec);
double randNum = RANDOM.nextDouble() * 100.0;
return !(burn_chance <= randNum);
}
public boolean updateTutorial(Player player){
if (TutorialSession.getExtension(player).getStage() == 14) {
TutorialStage.load(player, 15, false);
return cook(player, node,true, food);
} else if (TutorialSession.getExtension(player).getStage() == 15) {
TutorialStage.load(player, 16, false);
return cook(player, node, false, food);
}
if (TutorialSession.getExtension(player).getStage() == 20) {
TutorialStage.load(player, 21, false);
return cook(player, node, false, food);
}
return cook(player, node, isBurned(player,node,food),food);
}
*/
/**
* Gets the animation to use based on the interacting object.
* @param object the object.
* @return the animation.
*//*
private final Animation getAnimation(final GameObject object) {
return !object.getName().toLowerCase().equals("fire") ? RANGE_ANIMATION : FIRE_ANIMATION;
}
}
*/
@@ -0,0 +1,132 @@
package content.global.skill.cooking;
import content.global.skill.cooking.recipe.Recipe;
import core.game.interaction.NodeUsageEvent;
import core.game.interaction.UseWithHandler;
import core.game.node.entity.player.Player;
import core.game.node.item.Item;
import core.game.system.task.Pulse;
import core.plugin.Initializable;
import core.plugin.Plugin;
import core.game.dialogue.SkillDialogueHandler.SkillDialogue;
import core.game.dialogue.SkillDialogueHandler;
import java.util.ArrayList;
import java.util.List;
/**
* Represents a cooking recipe plugin. This is used to handle the multiple
* recipes used in cooking these recipes can range from making a pizza or making
* a pie.
* @author 'Vexia
* @version 1.9
*/
@Initializable
public final class CookingRecipePlugin extends UseWithHandler {
/**
* Constructs a new {@code CookingRecipePlugin} {@code Object}.
*/
public CookingRecipePlugin() {
super(getAllowedNodes());
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
for (Recipe recipe : Recipe.RECIPES) {
for (Item ingredient : recipe.getIngredients()) {
addHandler(ingredient.getId(), ITEM_TYPE, this);
}
}
return this;
}
@Override
public boolean handle(NodeUsageEvent event) {
Recipe recipe = null;
// TODO: Transitioning to a Listener would save an O(n) pass through the recipes list on every use-with
for (Recipe temp : Recipe.RECIPES) {
if (temp.isSingular()) {
if (temp.getBase().getId() == event.getUsedItem().getId() || temp.getBase().getId() == event.getBaseItem().getId()) {
for (Item ingredient : temp.getIngredients()) {
if (ingredient.getId() == event.getBaseItem().getId() || ingredient.getId() == event.getUsedItem().getId()) {
recipe = temp;
break;
}
}
}
} else {
Item part = null;
Item ingredient = null;
for (int k = 0; k < temp.getParts().length; k++) {
for (int i = 0; i < temp.getIngredients().length; i++) {
part = temp.getParts()[k];
ingredient = temp.getIngredients()[i];
if (part.getId() == event.getUsedItem().getId() && ingredient.getId() == event.getBaseItem().getId() || part.getId() == event.getBaseItem().getId() && ingredient.getId() == event.getUsedItem().getId()) {
if (k == i) {// represents that this ingredient can
// mix with the other.
recipe = temp;
break;
}
}
}
}
}
}
if (recipe != null) {
final Player player = event.getPlayer();
final Recipe recipe_ = recipe;
SkillDialogueHandler handler = new SkillDialogueHandler(player, SkillDialogue.ONE_OPTION, recipe.getProduct()) {
@Override
public void create(final int amount, int index) {
player.getPulseManager().run(new Pulse(2) {
int count = 0;
@Override
public boolean pulse() {
recipe_.mix(player, event);
return ++count >= amount;
}
});
}
@Override
public int getAll(int index) {
return player.getInventory().getAmount(recipe_.getBase());
}
};
if (player.getInventory().getAmount(recipe.getBase()) == 1) {
recipe_.mix(player, event);
} else {
handler.open();
}
return true;
}
return false;
}
/**
* Method used to get the allowed nodes for this plugin.
* @return the allowed nodes.
*/
private final static int[] getAllowedNodes() {
List<Integer> bases = new ArrayList<>(10);
for (Recipe recipe : Recipe.RECIPES) {
for (Item base : recipe.getParts()) {
if (bases.contains(base.getId())) {
continue;
}
bases.add(base.getId());
}
if (bases.contains(recipe.getBase().getId())) {
continue;
}
bases.add(recipe.getBase().getId());
}
int[] baseArray = new int[bases.size()];
for (int i = 0; i < bases.size(); i++) {
baseArray[i] = bases.get(i);
}
return baseArray;
}
}
@@ -0,0 +1,73 @@
package content.global.skill.cooking
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
import org.rs09.consts.Items.BREAD_DOUGH_2307
import org.rs09.consts.Items.RAW_BEAR_MEAT_2136
import org.rs09.consts.Items.RAW_BEEF_2132
import org.rs09.consts.Items.SEAWEED_401
import org.rs09.consts.Items.UNCOOKED_CAKE_1889
/**
* @author Ceikry
* @author bushtail - added bear meat for sinew making
*/
class CookingRewrite : InteractionListener {
val RAW_FOODS: IntArray
init {
val list = CookableItems.values().map { it.raw }.toMutableList()
list.add(Items.COOKED_MEAT_2142)
list.add(RAW_BEEF_2132)
list.add(RAW_BEAR_MEAT_2136)
list.add(SEAWEED_401)
RAW_FOODS = list.toIntArray()
}
override fun defineListeners() {
onUseWith(IntType.SCENERY,RAW_FOODS, *COOKING_OBJs){ player, used, with ->
val item = used.asItem()
val obj = with.asScenery()
val range = obj.name.toLowerCase().contains("range")
when (item.id) {
RAW_BEEF_2132, RAW_BEAR_MEAT_2136 -> if (range) {
player.dialogueInterpreter.open(CookingDialogue(item.id,9436,true,obj,item.id))
return@onUseWith true
}
BREAD_DOUGH_2307, UNCOOKED_CAKE_1889 -> if (!range) {
player.packetDispatch.sendMessage("You need to cook this on a range.")
return@onUseWith false
}
}
//cook a standard item
player.dialogueInterpreter.open(CookingDialogue(item.id,obj))
return@onUseWith true
}
}
companion object {
val COOKING_OBJs = intArrayOf(24313,21302, 13528, 13529, 13533, 13531, 13536, 13539, 13542, 2728, 2729, 2730, 2731, 2732, 2859, 3038, 3039, 3769, 3775, 4265, 4266, 5249, 5499, 5631, 5632, 5981, 9682, 10433, 11404, 11405, 11406, 12102, 12796, 13337, 13881, 14169, 14919, 15156, 20000, 20001, 21620, 21792, 22713, 22714, 23046, 24283, 24284, 25155, 25156, 25465, 25730, 27297, 29139, 30017, 32099, 33500, 34495, 34546, 36973, 37597, 37629, 37726, 114, 4172, 5275, 8750, 16893, 22154, 34410, 34565, 114, 9085, 9086, 9087, 12269, 15398, 25440, 25441, 2724, 2725, 2726, 4618, 4650, 5165, 6093, 6094, 6095, 6096, 8712, 9374, 9439, 9440, 9441, 10824, 17640, 17641, 17642, 17643, 18039, 21795, 24285, 24329, 27251, 33498, 35449, 36815, 36816, 37426, 40110, 10377)
@JvmStatic
fun cook(player: Player, `object`: Scenery?, initial: Int, product: Int, amount: Int) {
val food = Item(initial)
if (food.name.toLowerCase().contains("pizza")) {
player.pulseManager.run(PizzaCookingPulse(player, `object`, initial, product, amount))
} else if (food.name.toLowerCase().contains("pie")) {
player.pulseManager.run(PieCookingPulse(player, `object`, initial, product, amount))
} else if (CookableItems.intentionalBurn(initial)) {
player.pulseManager.run(IntentionalBurnPulse(player, `object`, initial, product, amount))
} else {
player.pulseManager.run(StandardCookingPulse(player, `object`, initial, product, amount))
}
}
}
}
@@ -0,0 +1,89 @@
package content.global.skill.cooking
import core.api.*
import core.game.event.ResourceProducedEvent
import core.game.node.entity.skill.Skills
import core.game.node.item.Item
import org.rs09.consts.Items
import core.game.dialogue.DialogueFile
import core.game.interaction.InteractionListener
import core.game.interaction.IntType
class DoughMakingListener : InteractionListener {
companion object {
private val FULL_WATER_CONTAINERS_TO_EMPTY_CONTAINERS = hashMapOf(
Items.BUCKET_OF_WATER_1929 to Items.BUCKET_1925,
Items.BOWL_OF_WATER_1921 to Items.BOWL_1923,
Items.JUG_OF_WATER_1937 to Items.JUG_1935
)
}
override fun defineListeners() {
onUseWith(
IntType.ITEM,
FULL_WATER_CONTAINERS_TO_EMPTY_CONTAINERS.keys.toIntArray(),
Items.POT_OF_FLOUR_1933
) { player, waterContainer, flourContainer ->
openDialogue(player, DoughMakeDialogue(waterContainer.asItem(), flourContainer.asItem()))
return@onUseWith true
}
}
private class DoughMakeDialogue(val waterContainer: Item, val flourContainer: Item) : DialogueFile() {
companion object {
private const val STAGE_PRESENT_OPTIONS = 0
private const val STAGE_PROCESS_OPTION = 1
private enum class DoughProduct(val itemId: Int, val itemName: String, val requiredCookingLevel: Int) {
BREAD_DOUGH(Items.BREAD_DOUGH_2307, getItemName(Items.BREAD_DOUGH_2307), 1),
PASTRY_DOUGH(Items.PASTRY_DOUGH_1953, getItemName(Items.PASTRY_DOUGH_1953), 1),
PIZZA_DOUGH(Items.PIZZA_BASE_2283, getItemName(Items.PIZZA_BASE_2283), 35),
PITTA_DOUGH(Items.PITTA_DOUGH_1863, getItemName(Items.PITTA_DOUGH_1863), 58),
}
}
override fun handle(componentID: Int, buttonID: Int) {
when (stage) {
STAGE_PRESENT_OPTIONS -> {
player!!.dialogueInterpreter.sendOptions(
"What do you wish to make?",
*(DoughProduct.values().map { "${it.itemName}." }.toTypedArray())
).also { stage++ }
}
STAGE_PROCESS_OPTION -> runTask(player!!, 1) {
end()
val selectedDoughProduct = DoughProduct.values()[buttonID - 1]
if (hasLevelDyn(player!!, Skills.COOKING, selectedDoughProduct.requiredCookingLevel)) {
if (freeSlots(player!!) < 1) {
sendMessage(
player!!,
"Not enough space in your inventory."
)
return@runTask
}
if (removeItem(player!!, waterContainer) && removeItem(player!!, flourContainer)) {
addItem(player!!, selectedDoughProduct.itemId)
player!!.dispatch(ResourceProducedEvent(selectedDoughProduct.itemId, 1, player!!))
val emptyWaterContainerId = FULL_WATER_CONTAINERS_TO_EMPTY_CONTAINERS[waterContainer.id]!!
addItem(player!!, emptyWaterContainerId)
addItem(player!!, Items.EMPTY_POT_1931)
sendMessage(
player!!,
"You mix the flower and the water to make some ${selectedDoughProduct.itemName.toLowerCase()}."
)
}
} else {
sendDialogue(
player!!,
"You need a Cooking level of at least ${selectedDoughProduct.requiredCookingLevel} in order to make ${selectedDoughProduct.itemName.toLowerCase()}."
)
}
}
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More