Merge branch 2009scape:master into master

This commit is contained in:
Tooze 2025-08-03 23:55:01 +00:00
commit f376945ebc
80 changed files with 1471 additions and 1612 deletions

View file

@ -6727,6 +6727,10 @@
"npc_id": "3205",
"loc_data": "{3139,3448,0,1,3}-"
},
{
"npc_id": "3207",
"loc_data": "{1970,5002,0,1,4}-"
},
{
"npc_id": "3213",
"loc_data": "{2568,3334,0,1,0}-"

View file

@ -342,7 +342,7 @@ public enum Consumables {
ZAMMY_BREW(new Potion(new int[] {2450, 189, 191, 193}, new MultiEffect(new DamageEffect(10, true), new SkillEffect(Skills.ATTACK, 0, 0.25), new SkillEffect(Skills.STRENGTH, 0, 0.15), new SkillEffect(Skills.DEFENCE, 0, -0.1)))),
ANTIFIRE(new Potion(new int[] {2452, 2454, 2456, 2458}, new AddTimerEffect("dragonfire:immunity", 600, true))),
GUTH_REST(new Potion(new int[] {4417, 4419, 4421, 4423}, new MultiEffect(new RemoveTimerEffect("poison"), new EnergyEffect(5), new HealingEffect(5)))),
MAGIC_ESS(new Potion(new int[] {11491, 11489}, new SkillEffect(Skills.MAGIC,3,0))),
MAGIC_ESS(new Potion(new int[] {9021, 9022, 9023, 9024}, new SkillEffect(Skills.MAGIC,3,0))),
SANFEW(new Potion(new int[] {10925, 10927, 10929, 10931}, new MultiEffect(new RestoreEffect(8,0.25, true), new AddTimerEffect("poison:immunity", secondsToTicks(90)), new RemoveTimerEffect("disease")))),
SUPER_ENERGY(new Potion(new int[] {3016, 3018, 3020, 3022}, new EnergyEffect(20))),
BLAMISH_OIL(new FakeConsumable(1582, new String[] {"You know... I'd really rather not."})),
@ -365,9 +365,13 @@ public enum Consumables {
SUPER_ENERGY_MIX(new BarbarianMix(new int[] {11481, 11483}, new MultiEffect(new EnergyEffect(20), new HealingEffect(6)))),
HUNTING_MIX(new BarbarianMix(new int[] {11517, 11519}, new MultiEffect(new SkillEffect(Skills.HUNTER, 3, 0), new HealingEffect(6)))),
SUPER_STR_MIX(new BarbarianMix(new int[] {11485, 11487}, new MultiEffect(new SkillEffect(Skills.STRENGTH, 5, 0.15), new HealingEffect(6)))),
ANTIDOTE_PLUS_MIX(new BarbarianMix(new int[] {11501, 11503}, new MultiEffect(new AddTimerEffect("poison:immunity", minutesToTicks(9)), new RandomHealthEffect(3, 7)))),
ANTIP_SUPERMIX(new BarbarianMix(new int[] {11473, 11475}, new MultiEffect(new AddTimerEffect("poison:immunity", minutesToTicks(6)), new RandomHealthEffect(3, 7)))),
ANTIFIRE_MIX(new BarbarianMix(new int[] {11505, 11507}, new MultiEffect(new AddTimerEffect("dragonfire:immunity", 600, true), new RandomHealthEffect(3, 7)))),
ANTIDOTE_PLUS_MIX(new BarbarianMix(new int[] {11501, 11503}, new MultiEffect(new AddTimerEffect("poison:immunity", minutesToTicks(9)), new HealingEffect(6)))),
ANTIP_SUPERMIX(new BarbarianMix(new int[] {11473, 11475}, new MultiEffect(new AddTimerEffect("poison:immunity", minutesToTicks(6)), new HealingEffect(6)))),
ANTIFIRE_MIX(new BarbarianMix(new int[] {11505, 11507}, new MultiEffect(new AddTimerEffect("dragonfire:immunity", 600, true), new HealingEffect(6)))),
MAGIC_ESS_MIX(new BarbarianMix(new int[] {11489, 11491}, new MultiEffect(new SkillEffect(Skills.MAGIC, 3, 0), new HealingEffect(6)))),
SUPER_DEF_MIX(new BarbarianMix(new int[] {11497, 11499}, new MultiEffect(new SkillEffect(Skills.DEFENCE, 5, 0.15), new HealingEffect(6)))),
RANGING_MIX(new BarbarianMix(new int[] {11509, 11511}, new MultiEffect(new SkillEffect(Skills.RANGE, 4, 0.1), new HealingEffect(6)))),
MAGIC_MIX(new BarbarianMix(new int[] {11513, 11515}, new MultiEffect(new SkillEffect(Skills.MAGIC, 4, 0), new HealingEffect(6)))),
/** Stealing creation potions */
SC_PRAYER(new Potion(new int[] {14207, 14209, 14211, 14213, 14215}, new PrayerEffect(7, 0.25))),

View file

@ -10,6 +10,7 @@ import content.global.ame.events.evilchicken.EvilChickenNPC
import content.global.ame.events.freakyforester.FreakyForesterNPC
import content.global.ame.events.maze.MazeNPC
import content.global.ame.events.genie.GenieNPC
import content.global.ame.events.candlelight.PiousPeteNPC
import content.global.ame.events.pillory.PilloryNPC
import content.global.ame.events.rickturpentine.RickTurpentineNPC
import content.global.ame.events.rivertroll.RiverTrollRENPC
@ -21,6 +22,7 @@ import content.global.ame.events.strangeplant.StrangePlantNPC
import content.global.ame.events.swarm.SwarmNPC
import content.global.ame.events.treespirit.TreeSpiritRENPC
import content.global.ame.events.zombie.ZombieRENPC
import core.ServerConstants
import core.api.utils.WeightBasedTable
import core.api.utils.WeightedItem
@ -29,6 +31,7 @@ import core.game.node.entity.skill.Skills
enum class RandomEvents(val npc: RandomEventNPC, val loot: WeightBasedTable? = null, val skillIds: IntArray = intArrayOf(), val type: String = "") {
SANDWICH_LADY(npc = SandwichLadyRENPC()),
GENIE(npc = GenieNPC()),
CANDLELIGHT(npc = PiousPeteNPC(), skillIds = intArrayOf(Skills.PRAYER)),
CERTER(npc = CerterNPC(), loot = WeightBasedTable.create(
WeightedItem(Items.UNCUT_SAPPHIRE_1623,1,1,3.4),
WeightedItem(Items.KEBAB_1971,1,1,1.7),
@ -82,6 +85,9 @@ enum class RandomEvents(val npc: RandomEventNPC, val loot: WeightBasedTable? = n
private fun populateMappings() {
for (event in values()) {
if (!ServerConstants.INAUTHENTIC_CANDLELIGHT_RANDOM && event == CANDLELIGHT) {
continue
}
for (id in event.skillIds) {
val list = skillMap[id] ?: ArrayList<RandomEvents>().also { skillMap[id] = it }
list.add (event)

View file

@ -0,0 +1,164 @@
package content.global.ame.events.candlelight
import core.api.*
import core.api.utils.PlayerCamera
import core.game.interaction.InteractionListener
import core.game.interaction.InterfaceListener
import core.game.node.entity.Entity
import core.game.node.entity.player.Player
import core.game.world.map.Direction
import core.game.world.map.Location
import core.game.world.map.zone.ZoneBorders
import core.game.world.map.zone.ZoneRestriction
import org.rs09.consts.Scenery
/**
* Candlelight Interface CANDLELIGHT_178
*
*/
class CandlelightInterface : InterfaceListener, InteractionListener, MapArea {
companion object {
const val CANDLELIGHT_INTERFACE = 178
const val CANDLELIGHT_RETURN_LOC = "/save:original-loc"
const val CANDLELIGHT_CANDLE_ARRAY = "/save:candlelight:candle-array"
const val CANDLELIGHT_CAMERA_AT = "candlelight:camera-at"
val CANDLE_LOC_ARRAY = arrayOf(
Location(1967, 4997),
Location(1968, 4998),
Location(1967, 4999),
Location(1968, 5000),
Location(1967, 5001),
Location(1968, 5002),
Location(1967, 5003),
Location(1968, 5004),
Location(1967, 5005),
Location(1968, 5006),
Location(1967, 5007),
)
fun initCandlelight(player: Player) {
val candleArray = intArrayOf(0,0,0,0,0,0,2,2,2,2,2)
candleArray.shuffle()
setAttribute(player, CANDLELIGHT_CANDLE_ARRAY, candleArray)
for (candleIndex in 0..10) {
setVarbit(player, 1771 + candleIndex, candleArray[candleIndex])
}
}
fun areCandlesLit(player: Player): Boolean {
val candleArray = getAttribute(player, CANDLELIGHT_CANDLE_ARRAY, intArrayOf(0,0,0,0,0,0,0,0,0,0,0))
for (candle in candleArray) {
if (candle == 0) {
return false
}
}
return true
}
fun lightCandle(player: Player) {
var currentCamLoc = getAttribute(player, CANDLELIGHT_CAMERA_AT, Location(1968, 5002))
val candleIndex = CANDLE_LOC_ARRAY.indexOf(currentCamLoc)
val varbit = candleIndex + 1771 // Essentially all varbits are 1771 .. 1881
if (candleIndex != -1) {
val candleArray = getAttribute(player, CANDLELIGHT_CANDLE_ARRAY, intArrayOf(0,0,0,0,0,0,0,0,0,0,0))
if (candleArray[candleIndex] == 0) {
candleArray[candleIndex] = 1
setAttribute(player, CANDLELIGHT_CANDLE_ARRAY, candleArray)
setVarbit(player, varbit, 1)
sendMessage(player, "You light the candle.")
} else if (candleArray[candleIndex] == 1) {
sendMessage(player, "This candle is already lit.")
} else {
sendMessage(player, "This candle is too short to light.")
}
} else {
sendMessage(player, "There is nothing to light here.")
}
}
fun moveCamera(player: Player, direction: Direction, firstTime: Boolean = false) {
var currentCamLoc = getAttribute(player, CANDLELIGHT_CAMERA_AT, Location(1968, 5002))
when(direction) {
Direction.NORTH -> currentCamLoc = currentCamLoc.transform(Direction.NORTH)
Direction.SOUTH -> currentCamLoc = currentCamLoc.transform(Direction.SOUTH)
Direction.EAST -> currentCamLoc = currentCamLoc.transform(Direction.EAST)
Direction.WEST -> currentCamLoc = currentCamLoc.transform(Direction.WEST)
else -> {}
}
if (currentCamLoc.x < 1967) { currentCamLoc.x = 1967 }
if (currentCamLoc.x > 1968) { currentCamLoc.x = 1968 }
if (currentCamLoc.y < 4997) { currentCamLoc.y = 4997 }
if (currentCamLoc.y > 5007) { currentCamLoc.y = 5007 }
setAttribute(player, CANDLELIGHT_CAMERA_AT, currentCamLoc)
PlayerCamera(player).rotateTo(currentCamLoc.x - 30, currentCamLoc.y,0,200) // height is kind of a relative value?
PlayerCamera(player).panTo(currentCamLoc.x + 2, currentCamLoc.y,350, if(firstTime) 400 else 10)
}
}
override fun defineInterfaceListeners() {
on(CANDLELIGHT_INTERFACE){ player, component, opcode, buttonID, slot, itemID ->
when (buttonID) {
1 -> moveCamera(player, Direction.WEST)
2 -> moveCamera(player, Direction.EAST)
3 -> lightCandle(player)/* Light */
4 -> moveCamera(player, Direction.SOUTH)
5 -> moveCamera(player, Direction.NORTH)
9 -> closeInterface(player)
}
return@on true
}
onOpen(CANDLELIGHT_INTERFACE){ player, component ->
// Move camera
return@onOpen true
}
onClose(CANDLELIGHT_INTERFACE){ player, component ->
PlayerCamera(player).reset()
// Reset camera
return@onClose true
}
}
override fun defineListeners() {
on((11364 .. 11394).toIntArray(), SCENERY, "light") { player, node ->
setAttribute(player, CANDLELIGHT_CAMERA_AT, Location(node.location.x, node.location.y))
moveCamera(player, Direction.NORTH_WEST, true)
openInterface(player, CANDLELIGHT_INTERFACE)
return@on true
}
}
override fun defineDestinationOverrides() {
setDest(SCENERY, (11364 .. 11394).toIntArray(),"light"){ player, node ->
return@setDest Location(1970, node.location.y)
}
}
override fun defineAreaBorders(): Array<ZoneBorders> {
return arrayOf(ZoneBorders.forRegion(7758))
}
override fun getRestrictions(): Array<ZoneRestriction> {
return arrayOf(ZoneRestriction.RANDOM_EVENTS, ZoneRestriction.CANNON, ZoneRestriction.FOLLOWERS, ZoneRestriction.TELEPORT, ZoneRestriction.OFF_MAP)
}
override fun areaEnter(entity: Entity) {
if (entity is Player) {
initCandlelight(entity)
entity.interfaceManager.removeTabs(0, 1, 2, 3, 4, 5, 6, 12)
}
}
override fun areaLeave(entity: Entity, logout: Boolean) {
if (entity is Player) {
entity.interfaceManager.restoreTabs()
}
}
}

View file

@ -0,0 +1,94 @@
package content.global.ame.events.candlelight
import content.global.ame.RandomEvents
import content.global.ame.events.pillory.PilloryInterface
import content.global.ame.returnPlayer
import core.api.*
import core.game.dialogue.*
import core.game.interaction.QueueStrength
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.Graphics
import core.plugin.Initializable
import core.tools.END_DIALOGUE
import org.rs09.consts.Items
import org.rs09.consts.NPCs
import org.rs09.consts.Sounds
// iface 178
@Initializable
class PiousPeteDialogue (player: Player? = null) : DialoguePlugin(player) {
override fun newInstance(player: Player): DialoguePlugin {
return PiousPeteDialogue(player)
}
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
openDialogue(player, PiousPeteDialogueFile(), npc)
return false
}
override fun getIds(): IntArray {
return intArrayOf(NPCs.PIOUS_PETE_3207, NPCs._6564)
}
}
class PiousPeteDialogueFile : DialogueLabeller() {
override fun addConversation() {
npc(ChatAnim.THINKING, "Have you lit all the tall candles?")
exec { player, npc ->
if (CandlelightInterface.areCandlesLit(player)) {
loadLabel(player, "yeslit")
} else {
loadLabel(player, "nolit")
}
}
label("nolit")
player(ChatAnim.HALF_GUILTY, "Sorry, not yet.")
npc(ChatAnim.SAD, "Please help me in lighting the candles. I just need you to light all the tall candles, but not the short ones.")
line("Click on the pillars to open an interface", "to move around and light the candles.")
label("yeslit")
player(ChatAnim.FRIENDLY, "Yes, the tall ones are all lit.")
npc(ChatAnim.HAPPY, "Thank you my brother! I will now return you where you came from with a parting gift.")
npc(ChatAnim.FRIENDLY, "Take care brother!")
exec { player, npc ->
queueScript(player, 0, QueueStrength.SOFT) { stage: Int ->
when (stage) {
0 -> {
lock(player, 6)
sendGraphics(Graphics(1576, 0, 0), player.location)
animate(player,8939)
playAudio(player, Sounds.TELEPORT_ALL_200)
return@queueScript delayScript(player, 3)
}
1 -> {
returnPlayer(player)
sendGraphics(Graphics(1577, 0, 0), player.location)
animate(player,8941)
closeInterface(player)
return@queueScript delayScript(player, 3)
}
2 -> {
val loot = RandomEvents.CERTER.loot!!.roll(player)[0]
addItemOrDrop(player, loot.id, loot.amount)
return@queueScript stopExecuting(player)
}
else -> return@queueScript stopExecuting(player)
}
}
}
}
}
class PiousPeteStartingDialogueFile : DialogueLabeller() {
override fun addConversation() {
npc("I'm sorry to drag you away from your tasks, but I need a little help with something.")
player(ChatAnim.THINKING,"How can I help?")
npc("This is a chapel dedicated to our lord, Saradomin, and I'm tasked with maintaining this chapel.")
npc(ChatAnim.SAD,"My task is to light the chapel candles, but I couldn't reach them myself and I kept getting dazzled by the light whenever I tried.")
npc("So I need your help in lighting the candles. I need you to light all the tall candles, but not the short ones.")
npc(ChatAnim.FRIENDLY, "Once all the tall candles are all lit, come back and see me, and I will reward you for your work.")
}
}

View file

@ -0,0 +1,49 @@
package content.global.ame.events.candlelight
import content.global.ame.RandomEventNPC
import content.global.ame.kidnapPlayer
import core.api.*
import core.api.utils.WeightBasedTable
import core.game.interaction.QueueStrength
import core.game.node.entity.npc.NPC
import core.game.node.entity.player.link.TeleportManager
import core.game.world.map.Location
import core.game.world.update.flag.context.Graphics
import org.rs09.consts.NPCs
import org.rs09.consts.Sounds
/** "::revent -p player_name -e candlelight" **/
class PiousPeteNPC(override var loot: WeightBasedTable? = null) : RandomEventNPC(NPCs.PRIEST_3206) {
override fun init() {
super.init()
// Supposed to be "I'm sorry to drag you away from your tasks, but I need a little help with something." but it's too goddamn long.
sendChat("${player.username.capitalize()}! I need a little help with something.")
face(player)
queueScript(player, 4, QueueStrength.SOFT) { stage: Int ->
when (stage) {
0 -> {
lock(player, 6)
sendGraphics(Graphics(1576, 0, 0), player.location)
animate(player,8939)
playAudio(player, Sounds.TELEPORT_ALL_200)
return@queueScript delayScript(player, 3)
}
1 -> {
CandlelightInterface.initCandlelight(player)
kidnapPlayer(player, Location(1972, 5002, 0), TeleportManager.TeleportType.INSTANT)
// AntiMacro.terminateEventNpc(player)
sendGraphics(Graphics(1577, 0, 0), player.location)
animate(player,8941)
openDialogue(player, PiousPeteStartingDialogueFile(), NPC(NPCs.PIOUS_PETE_3207))
return@queueScript stopExecuting(player)
}
else -> return@queueScript stopExecuting(player)
}
}
}
override fun talkTo(npc: NPC) {
player.dialogueInterpreter.open(PiousPeteDialogueFile(),npc)
}
}

View file

@ -1,159 +0,0 @@
package content.global.handlers.iface;
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.player.link.RunScript;
import core.game.system.communication.ClanRank;
import core.game.system.communication.ClanRepository;
import core.net.amsc.MSPacketRepository;
import core.net.amsc.WorldCommunicator;
import core.plugin.Initializable;
import core.plugin.Plugin;
import core.tools.StringUtils;
import kotlin.Unit;
import static core.api.ContentAPIKt.sendInputDialogue;
import static core.api.ContentAPIKt.setInterfaceText;
/**
* Represents the plugin used to handle the clan interfaces.
* @author Vexia
*/
@Initializable
public final class ClanInterfacePlugin extends ComponentPlugin {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.put(590, this);
ComponentDefinition.put(589, this);
return this;
}
@Override
public boolean handle(Player player, Component component, int opcode, int button, int slot, int itemId) {
switch (component.getId()) {
case 589:
switch (button) {
case 9:
if (player.getInterfaceManager().getComponent(590) != null) {
player.getPacketDispatch().sendMessage("Please close the interface you have open before using 'Clan Setup'");
return true;
}
ClanRepository.openSettings(player);
return true;
case 14:
if (player.getIronmanManager().checkRestriction()) {
return false;
}
player.getDetails().getCommunication().toggleLootshare(player);
return true;
}
break;
case 590:
final ClanRepository clan = ClanRepository.get(player.getName(), true);
switch (button) {
case 23:
if (opcode == 155) {
clan.setJoinRequirement(ClanRank.NONE);
} else {
clan.setJoinRequirement(getRank(opcode));
}
player.getDetails().getCommunication().setJoinRequirement(clan.getJoinRequirement());
MSPacketRepository.setClanSetting(player, 0, clan.getJoinRequirement());
player.getPacketDispatch().sendString(clan.getJoinRequirement().getInfo(), 590, 23);
break;
case 24:
clan.setMessageRequirement(getRank(opcode));
player.getDetails().getCommunication().setMessageRequirement(clan.getMessageRequirement());
MSPacketRepository.setClanSetting(player, 1, clan.getMessageRequirement());
player.getPacketDispatch().sendString(clan.getMessageRequirement().getInfo(), 590, 24);
break;
case 25:
clan.setKickRequirement(getRank(opcode));
player.getDetails().getCommunication().setKickRequirement(clan.getKickRequirement());
MSPacketRepository.setClanSetting(player, 2, clan.getKickRequirement());
player.getPacketDispatch().sendString(clan.getKickRequirement().getInfo(), 590, 25);
clan.update();
break;
case 26:
if (opcode == 230) {
clan.setLootRequirement(ClanRank.ADMINISTRATOR);
} else {
clan.setLootRequirement(getRank(opcode));
}
player.getDetails().getCommunication().setLootRequirement(clan.getLootRequirement());
MSPacketRepository.setClanSetting(player, 3, clan.getLootRequirement());
player.getPacketDispatch().sendString(clan.getLootRequirement().getInfo(), 590, 26);
break;
case 22:
switch (opcode) {
case 196:
clan.setName("Chat disabled");
player.getCommunication().setClanName("");
player.getPacketDispatch().sendString(clan.getName(), 590, 22);
if (WorldCommunicator.isEnabled()) {
MSPacketRepository.sendClanRename(player, "");
break;
}
clan.clean(true);
break;
default:
sendInputDialogue(player, false, "Enter clan prefix:", (value) -> {
String name = StringUtils.formatDisplayName((String) value);
setInterfaceText(player, name, 590, 22);
if(WorldCommunicator.isEnabled()){
MSPacketRepository.sendClanRename(player, name);
clan.setName(name);
return Unit.INSTANCE;
}
if (clan.getName().equals("Chat disabled")) {
player.getPacketDispatch().sendMessage("Your clan channel has now been enabled!");
player.getPacketDispatch().sendMessage("Join your channel by clicking 'Join Chat' and typing: " + player.getUsername());
}
clan.setName(name);
player.getCommunication().setClanName(name);
clan.update();
return Unit.INSTANCE;
});
break;
}
break;
}
break;
}
return true;
}
/**
* Gets the value to set.
* @param opcode the opcode.
* @return the value.
*/
public static ClanRank getRank(int opcode) {
switch (opcode) {
case 155:
return ClanRank.NONE;
case 196:
return ClanRank.FRIEND;
case 124:
return ClanRank.RECRUIT;
case 199:
return ClanRank.CORPORAL;
case 234:
return ClanRank.SERGEANT;
case 168:
return ClanRank.LIEUTENANT;
case 166:
return ClanRank.CAPTAIN;
case 64:
return ClanRank.GENERAL;
case 53:
return ClanRank.OWNER;
}
return ClanRank.NONE;
}
}

View file

@ -1,50 +0,0 @@
package content.global.handlers.iface;
import core.game.component.Component;
import core.game.component.ComponentDefinition;
import core.game.component.ComponentPlugin;
import core.game.node.entity.player.Player;
import core.plugin.Initializable;
import core.plugin.Plugin;
@Initializable
public class CrystalKeyChestPlugin extends ComponentPlugin {
private final Integer CHEST_INTERFACE = 501;
private Player player;
public CrystalKeyChestPlugin() {
/*
* Empty
*/
}
public CrystalKeyChestPlugin(Player player) {
this.player = player;
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.put(CHEST_INTERFACE, this);
return this;
}
@Override
public boolean handle(Player player, Component component, int opcode, int button, int slot, int itemId) {
return false;
}
public void constructInterface(Player player) {
Integer[] hiddenChildren = new Integer[] { 3, 4, 5, 6, 7};
Component component = new Component(CHEST_INTERFACE);
for (int i = 3; i < hiddenChildren.length; i++) {
player.getPacketDispatch().sendInterfaceConfig(CHEST_INTERFACE, i, true);
}
player.getPacketDispatch().sendItemOnInterface(989, 1, CHEST_INTERFACE, hiddenChildren[2]);
player.getInterfaceManager().open(component);
this.player = player;
}
}

View file

@ -0,0 +1,17 @@
package content.global.handlers.iface
import core.api.closeInterface
import core.game.interaction.InterfaceListener
import org.rs09.consts.Components
class DeathInterface : InterfaceListener {
override fun defineInterfaceListeners() {
on(Components.AIDE_DEATH_153) { player, _, _, buttonID, _, _ ->
if (buttonID == 1) {
player.savedData.globalData.setDisableDeathScreen(true)
closeInterface(player)
}
return@on true
}
}
}

View file

@ -1,32 +0,0 @@
package content.global.handlers.iface;
import core.game.component.Component;
import core.game.component.ComponentDefinition;
import core.game.component.ComponentPlugin;
import core.game.node.entity.player.Player;
import core.plugin.Initializable;
import core.plugin.Plugin;
/**
* Handles the death interface.
* @author Vexia
*/
@Initializable
public final class DeathInterfacePlugin extends ComponentPlugin {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.forId(153).setPlugin(this);
return this;
}
@Override
public boolean handle(Player player, Component component, int opcode, int button, int slot, int itemId) {
if (button == 1) {
player.getSavedData().getGlobalData().setDisableDeathScreen(true);
player.getInterfaceManager().close();
}
return true;
}
}

View file

@ -1,30 +0,0 @@
package content.global.handlers.iface;
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.player.link.emote.Emotes;
import core.plugin.Initializable;
import core.plugin.Plugin;
/**
* Handles the emote tab interface.
* @author Vexia
*
*/
@Initializable
public final class EmoteTabInterface extends ComponentPlugin {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.put(464, this);
return this;
}
@Override
public boolean handle(Player player, Component component, int opcode, int button, int slot, int itemId) {
Emotes.handle(player, button);
return true;
}
}

View file

@ -1,231 +0,0 @@
package content.global.handlers.iface;
import content.global.skill.summoning.familiar.BurdenBeast;
import core.api.ContentAPIKt;
import core.cache.def.impl.ItemDefinition;
import core.game.component.Component;
import core.game.component.ComponentDefinition;
import core.game.component.ComponentPlugin;
import core.game.container.Container;
import core.game.container.ContainerEvent;
import core.game.container.ContainerListener;
import core.game.container.access.InterfaceContainer;
import core.game.container.impl.EquipmentContainer;
import core.game.interaction.OptionHandler;
import core.game.node.entity.combat.DeathTask;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.prayer.PrayerType;
import core.game.node.item.Item;
import core.game.system.task.Pulse;
import core.net.packet.PacketRepository;
import core.net.packet.context.ContainerContext;
import core.net.packet.out.ContainerPacket;
import core.plugin.Initializable;
import core.plugin.Plugin;
import core.game.global.action.EquipHandler;
import core.game.interaction.IntType;
import core.game.interaction.InteractionListeners;
import core.game.world.GameWorld;
import core.tools.Log;
/**
* Represents the equipment interface.
* @author Emperor
*
*/
@Initializable
public final class EquipmentInterface extends ComponentPlugin {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.put(102, this);
ComponentDefinition.put(387, this);
ComponentDefinition.put(667, this);
ComponentDefinition.put(670, this);
return this;
}
@Override
public boolean handle(final Player p, Component component, int opcode, int button, final int slot, final int itemId) {
if (component.getId() == 667) {
if (button != 14) {
return false;
}
switch (opcode) {
case 155:
p.getPulseManager().clear();
GameWorld.getPulser().submit(new Pulse(1, p) {
@Override
public boolean pulse() {
EquipHandler.unequip(p, slot, itemId);
return true;
}
});
return true;
case 9:
p.sendMessage(p.getEquipment().get(slot).getDefinition().getExamine());
return true;
case 196:
GameWorld.getPulser().submit(new Pulse(1, p) {
@Override
public boolean pulse() {
operate(p, slot, itemId);
return true;
}
});
return true;
}
return false;
}
else if (component.getId() == 670) {
switch (opcode) {
case 155:
p.getPulseManager().clear();
final Item item = p.getInventory().get(slot);
GameWorld.getPulser().submit(new Pulse(1, p) {
@Override
public boolean pulse() {
if (item == null) return true;
InteractionListeners.run(item.getId(), IntType.ITEM,"equip",p, item);
return true;
}
});
return true;
case 9:
p.sendMessage(p.getInventory().get(slot).getDefinition().getExamine());
return true;
}
}
switch (opcode) {
case 206:
if (button != 28) {
return false;
}
GameWorld.getPulser().submit(new Pulse(1, p) {
@Override
public boolean pulse() {
operate(p, slot, itemId);
return true;
}
});
return true;
default:
switch (button) {
case 52:
if (p.getInterfaceManager().isOpened() && p.getInterfaceManager().getOpened().getId() == 102) {
return true;
}
// (Highlight white items are auto destroyed on death Enum#616 (Items kept on death interface) TODO: Parse server sided
// SCRIPT 118 - Items kept on death interface CS
// ARG 0: Safe location check Takes: 0 Safe Area/2 in POH/3 in Castle Wars/4 in Trouble Brewing/5 in Barbass
int zoneType = p.getZoneMonitor().getType();
// ARG 1: Amount of items kept on death Takes: 0/1/3/4
Container[] itemArray = DeathTask.getContainers(p);
Container kept = itemArray[0];
int amtKeptOnDeath = kept.itemCount();
if (amtKeptOnDeath > 4 && zoneType == 0) {
ContentAPIKt.log(this.getClass(), Log.ERR, "Items kept on death interface should not contain more than 4 items when not in a safe zone!");
}
// ARG 2: Item kept on death slot 0
int slot0 = kept.getId(0);
// ARG 3: Item kept on death slot 1
int slot1 = kept.getId(1);
// ARG 4: Item kept on death slot 2
int slot2 = kept.getId(2);
// ARG 5: Item kept on death slot 3
int slot3 = kept.getId(3);
// ARG 6: Player skulled Takes: 0 not skulled/1 skulled
int skulled = p.getSkullManager().isSkulled() ? 1 : 0;
// ARG 7: Player has summoning creature out Takes: 0 not out/1 Creature summoned
int hasBoB;
if (p.getFamiliarManager().hasFamiliar()) {
if (p.getFamiliarManager().getFamiliar().isBurdenBeast()) {
hasBoB = ((BurdenBeast) p.getFamiliarManager().getFamiliar()).getContainer().isEmpty() ? 0 : 1;
} else {
hasBoB = 0;
}
} else {
hasBoB = 0;
}
// ARG 8: String for effect:
// if (arg1 == 0) arg8 + " This reduces the items you keep from three to zero!"
// if (arg1 == 1) arg8 + " This reduces the items you keep from three to zero!" + "<br>" + "<br>" + "However, you also have the " + "<col=ff3333>" + "Protect Items" + "<col=ff981f>" + " prayer active, which saves you one extra item!");
Object[] params = new Object[] { hasBoB, skulled, slot3, slot2, slot1, slot0, amtKeptOnDeath, zoneType, "You are skulled." };
p.getPacketDispatch().sendRunScript(118, "siiooooii", params);
p.getInterfaceManager().openComponent(102);
break;
case 28:
if (opcode == 81) {
p.getPulseManager().clear();
GameWorld.getPulser().submit(new Pulse(1, p) {
@Override
public boolean pulse() {
EquipHandler.unequip(p, slot, itemId);
return true;
}
});
return true;
}
break;
case 55:
if (p.getInterfaceManager().isOpened() && p.getInterfaceManager().getOpened().getId() == 667) {
return true;
}
final ContainerListener listener = new ContainerListener() {
@Override
public void update(Container c, ContainerEvent e) {
PacketRepository.send(ContainerPacket.class, new ContainerContext(p, -1, -1, 98, e.getItems(), false, e.getSlots()));
}
@Override
public void refresh(Container c) {
PacketRepository.send(ContainerPacket.class, new ContainerContext(p, -1, -1, 98, c, false));
}
};
p.getInterfaceManager().openComponent(667).setCloseEvent((player, c) -> {
player.removeAttribute("equip_stats_open");
player.getInterfaceManager().closeSingleTab();
player.getInventory().getListeners().remove(listener);
return true;
});
p.setAttribute("equip_stats_open", true);
EquipmentContainer.update(p);
p.getInterfaceManager().openSingleTab(new Component(670));
InterfaceContainer.generateItems(p, p.getInventory().toArray(), new String[] { "Equip" }, 670, 0, 7, 4, 93);
p.getInventory().getListeners().add(listener);
p.getInventory().refresh();
ItemDefinition.statsUpdate(p);
p.getPacketDispatch().sendIfaceSettings(1278, 14, 667, 0, 13);
break;
}
}
return true;
}
/**
* Operates an item.
* @param player The player.
* @param slot The container slot.
* @param itemId The item id.
*/
public void operate(Player player, int slot, int itemId) {
if (slot < 0 || slot > 13) {
return;
}
Item item = player.getEquipment().get(slot);
if (item == null) {
return;
}
if(InteractionListeners.run(item.getId(),IntType.ITEM,"operate",player,item)){
return;
}
OptionHandler handler = item.getOperateHandler();
if (handler != null && handler.handle(player, item, "operate")) {
return;
}
player.getPacketDispatch().sendMessage("You can't operate that.");
}
}

View file

@ -1,185 +0,0 @@
package content.global.handlers.iface;
import core.game.component.Component;
import core.game.component.ComponentDefinition;
import core.game.component.ComponentPlugin;
import core.plugin.Initializable;
import core.game.node.entity.combat.equipment.WeaponInterface;
import core.game.node.entity.combat.equipment.WeaponInterface.WeaponInterfaces;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.info.Rights;
import core.game.world.GameWorld;
import core.plugin.Plugin;
/**
* Represents the component plugin used for the game interface.
* @author Vexia
*
*/
@Initializable
public final class GameInterface extends ComponentPlugin {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.put(740, this);
return this;
}
@Override
public boolean handle(final Player player, Component component, int opcode, int button, int slot, int itemId) {
switch (component.getId()) {
case 740:
switch (button){
case 3:
player.getInterfaceManager().closeChatbox();
break;
}
return true;
case 746:
switch (button){
case 12:
player.getPacketDispatch().sendString("When you have finished playing " + GameWorld.getSettings().getName() + ", always use the button below to logout safely. ", 182, 0);
break;
case 49:
player.getPacketDispatch().sendString("Friends List - " + GameWorld.getSettings().getName() + " " + GameWorld.getSettings().getWorldId(), 550, 3);
break;
case 110:
configureWorldMap(player);
break;
}
return true;
case 548:
if (button >= 38 && button<= 44 || button >= 20 && button <= 26) {
player.getInterfaceManager().setCurrentTabIndex(getTabIndex(button));
}
//Interface buttons that advance the Tutorial Island stages
switch (button) {
case 21://Friends Tab
player.getPacketDispatch().sendString("Friends List -" + GameWorld.getSettings().getName() + " " + GameWorld.getSettings().getWorldId(), 550, 3);
break;
case 22://Ignore Tab
break;
case 24://Settings Tab
break;
case 25://Emotes Tab
break;
case 26://Music Tab
break;
case 38://Attack Tab
if (player.getExtension(WeaponInterface.class) == WeaponInterfaces.STAFF) {
final Component c = new Component(WeaponInterfaces.STAFF.getInterfaceId());
player.getInterfaceManager().openTab(0, c);
final WeaponInterface inter = player.getExtension(WeaponInterface.class);
inter.updateInterface();
}
break;
case 39://Skill Tab
break;
case 40://Quest Tab
/*if (GameWorld.isEconomyWorld()) {
player.getQuestRepository().syncronizeTab(player);
} else {
player.getSavedData().getSpawnData().drawStatsTab(player);
}*/
player.getQuestRepository().syncronizeTab(player);
break;
case 41://Inventory Tab
player.getInventory().refresh();
break;
case 42://Worn Equipment Tab
break;
case 43://Prayer Tab
break;
case 44://Magic Tab
break;
case 66://World map
case 110:
configureWorldMap(player);
break;
case 69://Logout
player.getPacketDispatch().sendString("When you have finished playing " + GameWorld.getSettings().getName() + ", always use the button below to logout safely. ", 182, 0);
break;
}
return true;
case 750:
switch (opcode) {
case 155:
switch (button) {
case 1:
player.getSettings().toggleRun();
break;
}
break;
}
return true;
case 751:
switch (opcode) {
case 155:
switch (button) {
case 27:
openReport(player);
break;
}
break;
}
return true;
}
return true;
}
/**
* World map
* Thanks, Snickerize!
*/
private void configureWorldMap(Player player) {
if (player.inCombat()) {
player.getPacketDispatch().sendMessage("It wouldn't be very wise opening the world map during combat.");
return;
}
if(player.getLocks().isInteractionLocked() || player.getLocks().isMovementLocked()){
player.getPacketDispatch().sendMessage("You can't do this right now.");
return;
}
player.getInterfaceManager().openWindowsPane(new Component(755));
int posHash = (player.getLocation().getZ() << 28) | (player.getLocation().getX() << 14) | player.getLocation().getY();
player.getPacketDispatch().sendScriptConfigs(622, posHash, "", 0);
player.getPacketDispatch().sendScriptConfigs(674, posHash, "", 0);
}
/**
* Method used to open the report interface.
* @param player the player.
*/
public static void openReport(final Player player) {
player.getInterfaceManager().open(new Component(553)).setCloseEvent((player1, c) -> {
player1.getPacketDispatch().sendRunScript(80, "");
player1.getPacketDispatch().sendRunScript(137, "");
return true;
});
player.getPacketDispatch().sendRunScript(508, "");
if (player.getDetails().getRights() != Rights.REGULAR_PLAYER) {
for (int i = 0; i < 18; i++) {
player.getPacketDispatch().sendInterfaceConfig(553, i, false);
}
}
}
/**
* Gets the tab index.
* @param button The button id.
* @return The tab index.
*/
private static int getTabIndex(int button) {
int tabIndex = button - 38;
if (button < 27) {
tabIndex = (button - 20) + 7;
}
return tabIndex;
}
/**
* Configures the world map for a player.
* @param player The player.
*/
}

View file

@ -152,11 +152,11 @@ class HairDresserInterface : ComponentPlugin(){
player.setAttribute("beard-setting",false)
if(!pl.getAttribute("hairdresser-paid",false)){
val original_hair = player.getAttribute("original-hair",0)
val original_beard = player.getAttribute("original_beard",-1)
val original_color = player.getAttribute("original_color",0)
val original_beard = player.getAttribute("original-beard",-1)
val original_color = player.getAttribute("original-color",0)
pl.appearance.hair.changeLook(original_hair)
pl.appearance.hair.changeColor(original_color)
if(original_beard != -1) {
if (original_beard != -1) {
pl.appearance.beard.changeLook(original_beard)
}
pl.appearance.sync()
@ -174,7 +174,7 @@ class HairDresserInterface : ComponentPlugin(){
when(button){
199 -> player.setAttribute("beard-setting",false)
200 -> player.setAttribute("beard-setting",true)
68,196,274 -> pay(player)
196,274 -> pay(player)
else -> when(component?.id){
592 -> { //Female
if(femaleColorButtonRange.contains(button)){

View file

@ -0,0 +1,34 @@
package content.global.handlers.iface
import core.api.closeInterface
import core.api.runTask
import core.game.interaction.InterfaceListener
import core.game.node.entity.player.info.login.LoginConfiguration
import org.rs09.consts.Components
class LoginInterface : InterfaceListener {
override fun defineInterfaceListeners() {
on(Components.WELCOME_SCREEN_378) { player, _, _, buttonID, _, _ ->
val playButton = 140
val creditButton = 145
val discordButton = 204
when (buttonID) {
playButton -> {
player.locks.lock("login", 2)
closeInterface(player)
runTask(player, 1, 0) {
LoginConfiguration.configureGameWorld(player)
}
}
creditButton -> return@on true
discordButton -> return@on true
}
return@on true
}
onClose(Components.WELCOME_SCREEN_378) { player, _ ->
return@onClose player.locks.isLocked("login")
}
}
}

View file

@ -1,51 +0,0 @@
package content.global.handlers.iface;
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.player.info.login.LoginConfiguration;
import core.game.system.task.Pulse;
import core.plugin.Initializable;
import core.plugin.Plugin;
/**
* Represents the plugin used for the login interface.
* @author 'Vexia
* @version 1.0
*/
@Initializable
public final class LoginInterfacePlugin extends ComponentPlugin {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.put(378, this);
return null;
}
@Override
public boolean handle(final Player player, Component component, int opcode, int button, int slot, int itemId) {
switch (button) {
case 140:
if (player.getLocks().isLocked("login")) {
return true;
}
player.getLocks().lock("login", 2);
player.getInterfaceManager().close();
player.getPulseManager().run(new Pulse(1) {
@Override
public boolean pulse() {
LoginConfiguration.configureGameWorld(player);
return true;
}
});
break;
case 145://credits
break;
case 204://message centre
break;
}
return true;
}
}

View file

@ -1,42 +0,0 @@
package content.global.handlers.iface;
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.world.GameWorld;
import core.plugin.Initializable;
import core.plugin.Plugin;
import core.game.world.repository.Repository;
/**
* Represents the interface used to logout of the game.
* @author 'Vexia
* @version 1.0
*/
@Initializable
public final class LogoutInterface extends ComponentPlugin {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.put(182, this);
return this;
}
@Override
public boolean handle(Player player, Component component, int opcode, int button, int slot, int itemId) {
if (!player.getZoneMonitor().canLogout()) {
return true;
}
if (player.inCombat()) {
player.getPacketDispatch().sendMessage("You can't log out until 10 seconds after the end of combat.");
return true;
}
if (player.isTeleporting()) {
player.sendMessage("Please finish your teleport before logging out.");
return true;
}
Repository.getDisconnectionQueue().add(player);
return true;
}
}

View file

@ -1,50 +0,0 @@
package content.global.handlers.iface;
import content.global.skill.magic.SpellListener;
import content.global.skill.magic.SpellListeners;
import content.global.skill.magic.SpellUtils;
import core.game.event.SpellCastEvent;
import core.game.component.Component;
import core.game.component.ComponentDefinition;
import core.game.component.ComponentPlugin;
import core.plugin.Initializable;
import core.game.node.entity.combat.spell.MagicSpell;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.SpellBookManager.SpellBook;
import core.game.world.GameWorld;
import core.plugin.Plugin;
/**
* Represents the magic book interface handling of non-combat spells.
* @author 'Vexia
* @version 1.0
*/
@Initializable
public final class MagicBookInterface extends ComponentPlugin {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.put(192, this);
ComponentDefinition.put(193, this);
ComponentDefinition.put(430, this);
return this;
}
@Override
public boolean handle(final Player player, Component component, int opcode, int button, int slot, int itemId) {
if (GameWorld.getTicks() < player.getAttribute("magic:delay", -1)) {
return true;
}
SpellBook spellBook = component.getId() == 192
? SpellBook.MODERN
: component.getId() == 193
? SpellBook.ANCIENT
: SpellBook.LUNAR;
SpellListeners.run(button, SpellListener.NONE, SpellUtils.getBookFromInterface(component.getId()),player,null);
boolean result = MagicSpell.castSpell(player, spellBook, button, player);
return result;
}
}

View file

@ -31,32 +31,13 @@ class MainGameInterface : InterfaceListener {
}
on(TOPLEVEL_FS){player, _, _, buttonID, _, _ ->
when (buttonID) {
12 -> setInterfaceText(player,
"When you have finished playing " + settings!!.name + ", always use the button below to logout safely. ",
182,
0
)
49 -> setInterfaceText(player,
"Friends List - " + settings!!.name + " " + settings!!.worldId,
550,
3
)
110 -> configureWorldMap(player)
}
if (buttonID == 110)
configureWorldMap(player)
return@on true
}
on(TOPLEVEL){player, _, _, buttonID, _, _ ->
when (buttonID) {
21 -> {
player.packetDispatch.sendString(
"Friends List -" + settings!!.name + " " + settings!!.worldId,
550,
3
)
}
38 -> {
if (player.getExtension<Any>(WeaponInterface::class.java) === WeaponInterfaces.STAFF) {
val c = Component(WeaponInterfaces.STAFF.interfaceId)
@ -67,12 +48,7 @@ class MainGameInterface : InterfaceListener {
}
40 -> player.questRepository.syncronizeTab(player)
41 -> player.inventory.refresh()
66, 110 -> configureWorldMap(player)
69 -> player.packetDispatch.sendString(
"When you have finished playing " + settings!!.name + ", always use the button below to logout safely. ",
182,
0
)
66 -> configureWorldMap(player)
}
return@on true
}
@ -95,11 +71,11 @@ class MainGameInterface : InterfaceListener {
private fun configureWorldMap(player: Player) {
if (player.inCombat()) {
player.packetDispatch.sendMessage("It wouldn't be very wise opening the world map during combat.")
sendMessage(player, "It wouldn't be very wise opening the world map during combat.")
return
}
if (player.locks.isInteractionLocked || player.locks.isMovementLocked) {
player.packetDispatch.sendMessage("You can't do this right now.")
sendMessage(player, "You can't do this right now.")
return
}
player.interfaceManager.close()

View file

@ -1,57 +0,0 @@
package content.global.handlers.iface;
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.player.info.Rights;
import core.game.node.entity.player.link.music.MusicEntry;
import core.plugin.Initializable;
import core.plugin.Plugin;
/**
* Handles the interface tab buttons.
* @author Emperor
*/
@Initializable
public final class MusicTabInterface extends ComponentPlugin {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.put(187, this);
return this;
}
@Override
public boolean handle(Player player, Component component, int opcode, int button, int slot, int itemId) {
switch (opcode) {
case 155:
switch (button) {
case 11:
player.getMusicPlayer().toggleLooping();
return true;
case 1:
MusicEntry entry = player.getMusicPlayer().getUnlocked().get(slot);
if (entry == null) {
if(player.getRights().equals(Rights.ADMINISTRATOR)){
for(MusicEntry ent : MusicEntry.getSongs().values()){
if(ent.getIndex() == slot){
player.getMusicPlayer().unlock(ent.getId());
break;
}
}
} else {
player.getPacketDispatch().sendMessage("You have not unlocked this piece of music yet!</col>");
}
return true;
}
player.getMusicPlayer().setPlaying(false);
player.getMusicPlayer().play(entry);
return true;
}
break;
}
return false;
}
}

View file

@ -0,0 +1,58 @@
package content.global.handlers.iface
import core.api.*
import core.game.dialogue.FacialExpression
import core.game.interaction.InterfaceListener
import core.game.node.item.Item
import core.tools.StringUtils
import org.rs09.consts.Items
import org.rs09.consts.NPCs
class MysticStaffEnchantInterface : InterfaceListener {
override fun defineInterfaceListeners() {
on(INTERFACE_332) { player, _, _, buttonID, _, _ ->
val staff = buttonMap[buttonID] ?: return@on true
val price = if (inEquipment(player, Items.SEERS_HEADBAND_14631)) 27000 else 40000
if (!inInventory(player, staff.basicID)) {
sendMessage(player, "You don't have a${if (StringUtils.isPlusN(getItemName(staff.basicID))) "n" else ""} ${getItemName(staff.basicID)} to enchant.")
return@on true
}
closeInterface(player)
if (!inInventory(player, Items.COINS_995, price)) {
sendNPCDialogue(player, NPCs.THORMAC_389, "I need ${String.format("%,d", price)} coins for materials. Come back when you have the money!", FacialExpression.NEUTRAL)
return@on true
}
if (removeItem(player, Item(staff.basicID, 1)) && removeItem(player, Item(Items.COINS_995, price))) {
sendNPCDialogue(player, NPCs.THORMAC_389, "Just a moment... hang on... hocus pocus abra-cadabra... there you go! Enjoy your enchanted staff!", FacialExpression.NEUTRAL)
addItem(player, staff.enchantedID, 1)
}
return@on true
}
}
enum class EnchantedStaff(val enchantedID: Int, val basicID: Int, val buttonID: Int) {
AIR(Items.MYSTIC_AIR_STAFF_1405, Items.AIR_BATTLESTAFF_1397, 21),
WATER(Items.MYSTIC_WATER_STAFF_1403, Items.WATER_BATTLESTAFF_1395, 22),
EARTH(Items.MYSTIC_EARTH_STAFF_1407, Items.EARTH_BATTLESTAFF_1399, 23),
FIRE(Items.MYSTIC_FIRE_STAFF_1401, Items.FIRE_BATTLESTAFF_1393, 24),
LAVA(Items.MYSTIC_LAVA_STAFF_3054, Items.LAVA_BATTLESTAFF_3053, 25),
MUD(Items.MYSTIC_MUD_STAFF_6563, Items.MUD_BATTLESTAFF_6562, 26),
STEAM(Items.MYSTIC_STEAM_STAFF_11738, Items.STEAM_BATTLESTAFF_11736, 27),
}
companion object {
private const val INTERFACE_332 = 332
val buttonMap = HashMap<Int, EnchantedStaff>()
init {
for (staff in EnchantedStaff.values()) {
buttonMap[staff.buttonID] = staff
}
}
}
}

View file

@ -1,95 +0,0 @@
package content.global.handlers.iface;
import core.game.component.Component;
import core.game.component.ComponentDefinition;
import core.game.component.ComponentPlugin;
import org.rs09.consts.Items;
import core.game.node.entity.player.Player;
import core.game.node.item.Item;
import core.plugin.Plugin;
import core.plugin.Initializable;
import core.tools.StringUtils;
import java.util.HashMap;
/**
* Represents the plugin used to handle the agility ticket interface.
* @author afaroutdude
*/
@Initializable
public final class MysticStaffEnchantingPlugin extends ComponentPlugin {
private final Component COMPONENT = new Component(332);
protected enum EnchantedStaff {
AIR(Items.MYSTIC_AIR_STAFF_1405, Items.AIR_BATTLESTAFF_1397, 21),
WATER(Items.MYSTIC_WATER_STAFF_1403, Items.WATER_BATTLESTAFF_1395, 22),
EARTH(Items.MYSTIC_EARTH_STAFF_1407, Items.EARTH_BATTLESTAFF_1399, 23),
FIRE(Items.MYSTIC_FIRE_STAFF_1401, Items.FIRE_BATTLESTAFF_1393, 24),
LAVA(Items.MYSTIC_LAVA_STAFF_3054, Items.LAVA_BATTLESTAFF_3053, 25),
MUD(Items.MYSTIC_MUD_STAFF_6563, Items.MUD_BATTLESTAFF_6562, 26),
STEAM(Items.MYSTIC_STEAM_STAFF_11738, Items.STEAM_BATTLESTAFF_11736, 27);
public final int enchanted;
public final int basic;
public final int child;
private static final HashMap<Integer, Integer> basicToEnchanted = new HashMap<>();
private static final HashMap<Integer, Integer> childToBasic = new HashMap<>();
static {
for (EnchantedStaff staff : EnchantedStaff.values()) {
basicToEnchanted.put(staff.basic, staff.enchanted);
childToBasic.put(staff.child, staff.basic);
}
}
EnchantedStaff(int enchantedId, int basicId, int childId) {
this.enchanted = enchantedId;
this.basic = basicId;
this.child = childId;
}
}
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.forId(332).setPlugin(this);
return this;
}
@Override
public void open(Player player, Component component) {
super.open(player, component);
// zoom doesn't work, but based on https://youtu.be/qxxhhCdxBsQ?t=75 seems correct anyway
for (EnchantedStaff staff : EnchantedStaff.values()) {
player.getPacketDispatch().sendItemZoomOnInterface(staff.basic, 240, COMPONENT.getId(), staff.child);
}
}
@Override
public boolean handle(Player player, Component component, int opcode, int buttonId, int slot, int itemId) {
if (EnchantedStaff.childToBasic.containsKey(buttonId)) {
Item basicStaff = new Item(EnchantedStaff.childToBasic.get(buttonId));
Item enchantedStaff = new Item(EnchantedStaff.basicToEnchanted.get(basicStaff.getId()));
if (!player.getInventory().containsItem(basicStaff)) {
player.getPacketDispatch().sendMessage("You don't have a" + (StringUtils.isPlusN(basicStaff.getName()) ? "n " : " ") + basicStaff.getName() + " to enchant.");
return true;
}
int cost = player.getEquipment().contains(Items.SEERS_HEADBAND_14631, 1)? 27000 : 40000;
if (!player.getInventory().contains(995, cost)) {
player.getInterfaceManager().close();
player.getDialogueInterpreter().sendDialogues(389, null, "I need " + String.format("%,d", cost) + " coins for materials. Come", "back when you have the money!");
return true;
}
if (player.getInventory().remove(basicStaff, new Item(995, cost))) {
player.getInterfaceManager().close();
player.getDialogueInterpreter().sendDialogues(389, null, "Just a moment... hang on... hocus pocus abra-", "cadabra... there you go! Enjoy your enchanted staff!");
player.getInventory().add(enchantedStaff);
}
}
return true;
}
}

View file

@ -1,39 +0,0 @@
package content.global.handlers.iface;
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.player.link.prayer.PrayerType;
import core.plugin.Initializable;
import core.plugin.Plugin;
import static core.api.ContentAPIKt.hasRequirement;
import content.data.Quests;
/**
* Represents the prayer interface.
* @author 'Vexia
*/
@Initializable
public final class PrayerTabInterface extends ComponentPlugin {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.put(271, this);
return this;
}
@Override
public boolean handle(Player player, Component component, int opcode, int button, int slot, int itemId) {
final PrayerType type = PrayerType.get(button);
if (type == PrayerType.CHIVALRY || type == PrayerType.PIETY)
if (!hasRequirement(player, Quests.KINGS_RANSOM))
return true;
if (type == null) {
return true;
}
player.getPrayer().toggle(type);
return true;
}
}

View file

@ -1,71 +0,0 @@
package content.global.handlers.iface;
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.player.link.diary.AchievementDiary;
import core.game.node.entity.player.link.diary.DiaryType;
import core.game.node.entity.player.link.quest.Quest;
import core.plugin.Initializable;
import core.plugin.Plugin;
/**
* Handles the quest tab reward buttons.
* @author Emperor
* @author Vexia
*/
@Initializable
public class QuestTabInterface extends ComponentPlugin {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.put(274, this); // Quests
ComponentDefinition.put(259, this); // Achievement diary
return this;
}
@Override
public boolean handle(Player p, Component component, int opcode, int button, int slot, int itemId) {
p.getPulseManager().clear();
switch (component.getId()) {
case 274:
// if (!GameWorld.isEconomyWorld()) {
// p.getSavedData().getSpawnData().handleButton(p, button);
// }
switch (button) {
case 3:
p.getAchievementDiaryManager().openTab();
return true;
case 10:
break;
default:
// if (GameWorld.isEconomyWorld()) {
Quest quest = p.getQuestRepository().forButtonId(button);
if (quest != null) {
p.getInterfaceManager().open(new Component(275));
quest.drawJournal(p, quest.getStage(p));
return true;
} else QuestTabUtils.showRequirementsInterface(p, button);
// }
return false;
}
break;
case 259:
switch (button) {
case 8:
p.getInterfaceManager().openTab(2, new Component(274));
return true;
default:
AchievementDiary diary = p.getAchievementDiaryManager().getDiary(DiaryType.forChild(button));
if (diary != null) {
diary.open(p);
}
return true;
}
}
return true;
}
}

View file

@ -1,89 +0,0 @@
package content.global.handlers.iface;
import static core.api.ContentAPIKt.*;
import core.game.component.Component;
import core.game.component.ComponentDefinition;
import core.game.component.ComponentPlugin;
import core.plugin.Initializable;
import core.game.node.entity.player.Player;
import core.plugin.Plugin;
/**
* @author 'Vexia
*/
@Initializable
public class SettingTabInterface extends ComponentPlugin {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.put(261, this);
return this;
}
@Override
public boolean handle(Player p, Component component, int opcode, int button, int slot, int itemId) {
switch (button) {
case 10:// brightness
int brightness = button - 7;
p.getSettings().setBrightness(brightness);
break;
case 11:
case 12:
case 13:
case 14:
case 15:// music
int volume = 15 - button;
p.getSettings().setMusicVolume(volume);
break;
case 16://530 settings
/* if (TutorialSession.getExtension(p).getStage() != TutorialSession.MAX_STAGE) {
p.sendMessage("You must finish the tutorial before opening the graphic settings.");
break;
}*/
p.getInterfaceManager().open(new Component(742));
break;
case 18://530 settings
p.getInterfaceManager().open(new Component(743));
break;
case 17:
case 19:
case 20:// sonund
int volume1 = 20 - button;
p.getSettings().setSoundEffectVolume(volume1);
break;
case 29:
case 30:
case 31:
case 32:
case 33:// all sound
int volume11 = 33 - button;
p.getSettings().setAreaSoundVolume(volume11);
break;
case 6:// mouse
p.getSettings().toggleMouseButton();
break;
case 4:// effects
p.getSettings().toggleChatEffects();
break;
case 5:// private chat
p.getSettings().toggleSplitPrivateChat();
break;
case 7:// aid
if (p.getIronmanManager().checkRestriction()) {
return true;
}
p.getSettings().toggleAcceptAid();
break;
case 3:// run
p.getSettings().toggleRun();
break;
case 8:// house
p.getInterfaceManager().close();
setVarp(p, 261, getVarp(p, 261) & 0x1);
p.getInterfaceManager().openSingleTab(new Component(398));
break;
}
return true;
}
}

View file

@ -1,32 +0,0 @@
package content.global.handlers.iface;
import core.game.component.Component;
import core.game.component.ComponentDefinition;
import core.game.component.ComponentPlugin;
import core.game.node.entity.player.Player;
import core.plugin.Initializable;
import core.plugin.Plugin;
import static core.api.ContentAPIKt.*;
/**
* Represents the plugin used for the skilling interface.
* @author 'Vexia
* @version 1.0
*/
@Initializable
public final class SkillInterface extends ComponentPlugin {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.put(499, this);
return this;
}
@Override
public boolean handle(Player player, Component component, int opcode, int button, int slot, int itemId) {
setVarbit(player, 3288, player.getAttribute("skillMenu", -1));
setVarbit(player, 3289, button - 10);
return true;
}
}

View file

@ -1,162 +0,0 @@
package content.global.handlers.iface;
import core.game.component.Component;
import core.game.component.ComponentDefinition;
import core.game.component.ComponentPlugin;
import core.game.node.entity.skill.LevelUp;
import core.game.node.entity.skill.Skills;
import core.game.node.entity.player.Player;
import core.game.world.GameWorld;
import core.plugin.Initializable;
import core.plugin.Plugin;
import static core.api.ContentAPIKt.*;
/**
* Represents the plugin used to handle the skilling tab.
* @author Vexia
* @author Splinter
* @version 1.1
*/
@Initializable
public final class SkillTabInterface extends ComponentPlugin {
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.put(320, this);
return this;
}
@Override
public boolean handle(Player p, Component component, int opcode, int button, int slot, int itemId) {
final SkillConfig config = SkillConfig.forId(button);
if (config == null) {
return true;
}
if (!GameWorld.getSettings().isPvp()) {
if (p.getAttribute("levelup:" + config.getSkillId(), false)) {
p.removeAttribute("levelup:" + config.getSkillId());
LevelUp.sendFlashingIcons(p, -1);
setVarp(p, 1230, ADVANCE_CONFIGS[config.getSkillId()]);
p.getInterfaceManager().open(new Component(741));
} else {
p.getPulseManager().clear();
p.getInterfaceManager().open(new Component(499));
setVarp(p, 965, config.getConfig());
p.getAttributes().put("skillMenu", config.getConfig());
}
} else {
if (config.getSkillId() > 6) {
p.getPacketDispatch().sendMessage("You cannot set a target level for this skill.");
return false;
}
if (p.canSpawn()) {
p.sendMessage("You must be inside Edgeville bank to set levels.");
return false;
}
}
return true;
}
/**
* Holds all the config values of the skill advances.
*/
public static final int[] ADVANCE_CONFIGS = {
9, 40, 17, 49,
25, 57, 33, 641,
659, 664, 121, 649,
89, 114, 107, 72,
64, 80, 673, 680,
99, 698, 689, 705,
};
public enum SkillConfig {
ATTACK(125, 1, Skills.ATTACK),
STRENGTH(126, 2, Skills.STRENGTH),
DEFENCE(127, 5, Skills.DEFENCE),
RANGE(128, 3, Skills.RANGE),
PRAYER(129, 7, Skills.PRAYER),
MAGIC(130, 4, Skills.MAGIC),
RUNECRAFTING(131, 12, Skills.RUNECRAFTING),
HITPOINTS(133, 6, Skills.HITPOINTS),
AGILITY(134, 8, Skills.AGILITY),
HERBLORE(135, 9, Skills.HERBLORE),
THIEVING(136, 10, Skills.THIEVING),
CRAFTING(137, 11, Skills.CRAFTING),
FLETCHING(138, 19, Skills.FLETCHING),
SLAYER(139, 20, Skills.SLAYER),
MINING(141, 13, Skills.MINING),
SMITHING(142, 14, Skills.SMITHING),
FISHING(143, 15, Skills.FISHING),
COOKING(144, 16, Skills.COOKING),
FIREMAKING(145, 17, Skills.FIREMAKING),
WOODCUTTING(146, 18, Skills.WOODCUTTING),
FARMING(147, 21, Skills.FARMING),
CONSTRUCTION(132, 22, Skills.CONSTRUCTION),
HUNTER(140, 23, Skills.HUNTER),
SUMMONING(148, 24, Skills.SUMMONING);
/**
* Constructs a new {@code SkillConfig} {@code Object}.
* @param button the button.
* @param config the config.
*/
SkillConfig(int button, int config, int skillId) {
this.button = button;
this.config = config;
this.skillId = skillId;
}
/**
* Represents the button.
*/
private int button;
/**
* Represents the config.
*/
private int config;
/**
* The skill id.
*/
private int skillId;
/**
* Gets the skill config.
* @param id the id.
* @return the skill config.
*/
public static SkillConfig forId(int id) {
for (SkillConfig config : SkillConfig.values()) {
if (config.button == id)
return config;
}
return null;
}
/**
* Gets the button.
* @return the button.
*/
public int getButton() {
return button;
}
/**
* Gets the config.
* @return the config.
*/
public int getConfig() {
return config;
}
/**
* Gets the skill id.
* @return The skill id.
*/
public int getSkillId() {
return skillId;
}
}
}

View file

@ -0,0 +1,109 @@
package content.global.handlers.iface.tabs
import core.api.sendInputDialogue
import core.api.sendMessage
import core.game.interaction.InterfaceListener
import core.game.system.communication.ClanRank
import core.game.system.communication.ClanRepository
import core.net.amsc.MSPacketRepository
import core.net.amsc.WorldCommunicator
import core.tools.StringUtils
import org.rs09.consts.Components
class ClanTabInterface : InterfaceListener {
override fun defineInterfaceListeners() {
on(Components.CLANJOIN_589) { player, _, _, buttonID, _, _ ->
if (buttonID == 9) {
if (player.interfaceManager.opened != null) {
sendMessage(player, "Please close the interface you have open before using 'Clan Setup'")
} else {
ClanRepository.openSettings(player)
}
}
if (buttonID == 14) {
player.communication.toggleLootshare(player)
}
return@on true
}
on(Components.CLANSETUP_590) { player, _, opcode, buttonID, _, _ ->
val clan = ClanRepository.get(player.name, true)
when (buttonID) {
22 -> {
if (opcode == 155) {
sendInputDialogue(player, false, "Enter clan prefix:", ) { value ->
val clanName = StringUtils.formatDisplayName(value.toString())
if (WorldCommunicator.isEnabled()) { MSPacketRepository.sendClanRename(player, clanName) }
if (clan.name == "Chat disabled") {
sendMessage(player, "Your clan channel has now been enabled!")
sendMessage(player, "Join your channel by clicking 'Join Chat' and typing: ${player.username}")
}
clan.name = clanName
player.communication.clanName = clanName
clan.updateSettings(player)
clan.update()
}
}
if (opcode == 196) {
clan.name = "Chat disabled"
player.communication.clanName = ""
if (WorldCommunicator.isEnabled()) { MSPacketRepository.sendClanRename(player, player.communication.clanName) }
clan.updateSettings(player)
clan.delete()
}
}
23 -> {
clan.joinRequirement = getRank(opcode)
player.communication.joinRequirement = clan.joinRequirement
MSPacketRepository.setClanSetting(player, 0, clan.joinRequirement)
}
24 -> {
clan.messageRequirement = getRank(opcode)
player.communication.messageRequirement = clan.messageRequirement
MSPacketRepository.setClanSetting(player, 1, clan.messageRequirement)
}
25 -> {
clan.kickRequirement = getRank(opcode)
player.communication.kickRequirement = clan.kickRequirement
MSPacketRepository.setClanSetting(player, 2, clan.kickRequirement)
}
26 -> {
clan.lootRequirement = if (opcode == 155) ClanRank.ADMINISTRATOR else getRank(opcode)
player.communication.lootRequirement = clan.lootRequirement
MSPacketRepository.setClanSetting(player, 3, clan.lootRequirement)
}
33 -> sendMessage(player, "CoinShare is not available.")
}
clan.updateSettings(player)
clan.update()
return@on true
}
}
fun getRank(opcode: Int): ClanRank {
return when (opcode) {
155 -> ClanRank.NONE
196 -> ClanRank.FRIEND
124 -> ClanRank.RECRUIT
199 -> ClanRank.CORPORAL
234 -> ClanRank.SERGEANT
168 -> ClanRank.LIEUTENANT
166 -> ClanRank.CAPTAIN
64 -> ClanRank.GENERAL
53 -> ClanRank.OWNER
else -> ClanRank.NONE
}
}
}

View file

@ -1,4 +1,4 @@
package content.global.handlers.iface;
package content.global.handlers.iface.tabs;
import core.game.component.Component;
import core.game.component.ComponentDefinition;

View file

@ -0,0 +1,14 @@
package content.global.handlers.iface.tabs
import core.game.interaction.InterfaceListener
import core.game.node.entity.player.link.emote.Emotes
import org.rs09.consts.Components
class EmoteTabInterface : InterfaceListener {
override fun defineInterfaceListeners() {
on(Components.EMOTES_464) { player, _, _, buttonID, _, _ ->
Emotes.handle(player, buttonID)
return@on true
}
}
}

View file

@ -0,0 +1,136 @@
package content.global.handlers.iface.tabs
import content.global.skill.summoning.familiar.BurdenBeast
import core.api.*
import core.game.container.access.InterfaceContainer
import core.game.container.impl.EquipmentContainer
import core.game.global.action.EquipHandler
import core.game.interaction.IntType
import core.game.interaction.InteractionListeners
import core.game.interaction.InterfaceListener
import core.game.node.entity.combat.DeathTask
import core.game.node.entity.player.Player
import core.game.node.entity.player.link.prayer.PrayerType
import core.tools.Log
import org.rs09.consts.Components
import org.rs09.consts.Items
class EquipmentTabInterface : InterfaceListener {
override fun defineInterfaceListeners() {
onOpen(ITEMS_KEPT_ON_DEATH_102) { player, component ->
/**
* (Highlight white items are auto destroyed on death Enum#616 (Items kept on death interface) TODO: Parse server sided
* CS2 Script 118 - Items kept on death interface
* Credit Woahscam for figuring this all out.
* @arg_0 (Int): Zone type - 0 Default/1 Safe/2 POH/3 Castle Wars/4 Trouble Brewing/5 Barbarian Assault
* @arg_1 (Int): Amount of items kept on death - 0/1/3/4
* @arg_2 (Object): Item kept on death - slot 0 item id
* @arg_3 (Object): Item kept on death - slot 1 item id
* @arg_4 (Object): Item kept on death - slot 2 item id
* @arg_5 (Object): Item kept on death - slot 3 item id
* @arg_6 (Int): Player is skulled - 0 Not Skulled/1 Skulled
* @arg_7 (Int): Player has BoB summoned with items - 0 BoB not summoned or has no items /1 BoB summoned with items
* @arg_8 (String): String to append based on amount of items kept on death.
*/
val zoneType = player.zoneMonitor.type
val itemsKeptOnDeath = DeathTask.getContainers(player)[0]
val amountKeptOnDeath = if (!player.skullManager.isSkulled && itemsKeptOnDeath.itemCount() < 3) {
if (player.prayer[PrayerType.PROTECT_ITEMS]) 4 else 3
} else {
itemsKeptOnDeath.itemCount()
}
val slot0 = itemsKeptOnDeath.getId(0)
val slot1 = itemsKeptOnDeath.getId(1)
val slot2 = itemsKeptOnDeath.getId(2)
val slot3 = itemsKeptOnDeath.getId(3)
val hasSkull = if (player.skullManager.isSkulled) 1 else 0
val beast: BurdenBeast? = if (player.familiarManager.hasFamiliar() && player.familiarManager.familiar.isBurdenBeast) player.familiarManager.familiar as BurdenBeast else null
val hasBob = if (beast != null && !beast.container.isEmpty) 1 else 0
val message = "You are skulled."
val cs2Args = arrayOf<Any>(hasBob, hasSkull, slot3, slot2, slot1, slot0, amountKeptOnDeath, zoneType, message)
if (amountKeptOnDeath > 4 && zoneType == 0) {
log(this::class.java, Log.ERR, "Items kept on death interface should not contain more than 4 items when not in a safe zone!")
}
player.packetDispatch.sendRunScript(118, "siiooooii", *cs2Args)
val settings = IfaceSettingsBuilder().enableAllOptions().build()
player.packetDispatch.sendIfaceSettings(settings, 18, component.id, 0, itemsKeptOnDeath.itemCount())
player.packetDispatch.sendIfaceSettings(settings, 21, component.id, 0, DeathTask.getContainers(player)[1].itemCount())
return@onOpen true
}
on(Components.WORNITEMS_387) { player, component, opcode, buttonID, slot, itemID ->
when (buttonID) {
28 -> {
if (opcode == 81) EquipHandler.unequip(player, slot, itemID)
if (opcode == 206) operateItem(player, slot)
}
52 -> openInterface(player, ITEMS_KEPT_ON_DEATH_102)
55 -> openInterface(player, Components.EQUIP_SCREEN2_667)
}
return@on true
}
onOpen(Components.EQUIP_SCREEN2_667) { player, component ->
val settings = IfaceSettingsBuilder().enableAllOptions().build()
player.packetDispatch.sendIfaceSettings(settings, 14, component.id, 0, 13)
EquipmentContainer.update(player)
openSingleTab(player, Components.INVENTORY_WEAR2_670)
return@onOpen true
}
on(Components.EQUIP_SCREEN2_667) { player, _, opcode, buttonID, slot, itemID ->
if (buttonID == 14) {
when (opcode) {
9 -> sendMessage(player, player.equipment.get(slot).definition.examine)
155 -> EquipHandler.unequip(player, slot, itemID)
196 -> operateItem(player, slot)
}
}
return@on true
}
onClose(Components.EQUIP_SCREEN2_667) { player, _ ->
closeTabInterface(player)
return@onClose true
}
onOpen(Components.INVENTORY_WEAR2_670) { player, component ->
InterfaceContainer.generateItems(player, player.inventory.toArray(), arrayOf("Equip"), component.id, 0, 7, 4, 93)
return@onOpen true
}
on(Components.INVENTORY_WEAR2_670) { player, _, opcode, _, slot, _ ->
if (opcode == 9) sendMessage(player, player.inventory.get(slot).definition.examine)
if (opcode == 155) equipItem(player, slot)
return@on true
}
}
private fun equipItem(player: Player, slot: Int) {
val item = player.inventory.get(slot) ?: return
if (item.definition.options.any { it in arrayOf("Equip", "Wield", "Wear") } || item.id == Items.BEER_1917) {
InteractionListeners.run(item.id, IntType.ITEM, "equip", player, item)
} else {
sendMessage(player, "You can't wear that.")
}
}
private fun operateItem(player: Player, slot: Int) {
val item = player.equipment.get(slot) ?: return
when {
InteractionListeners.run(item.id, IntType.ITEM, "operate", player, item) -> return
item.operateHandler?.handle(player, item, "operate") == true -> return
else -> sendMessage(player, "You can't operate that.")
}
}
companion object {
private const val ITEMS_KEPT_ON_DEATH_102 = 102
}
}

View file

@ -0,0 +1,34 @@
package content.global.handlers.iface.tabs
import core.api.sendMessage
import core.game.interaction.InterfaceListener
import core.game.world.repository.Repository
import org.rs09.consts.Components
class LogoutTabInterface : InterfaceListener {
override fun defineInterfaceListeners() {
on(Components.LOGOUT_182) { player, _, _, buttonID, _, _ ->
if (buttonID == 6) {
return@on when {
!player.zoneMonitor.canLogout() -> true
player.inCombat() -> {
sendMessage(player, "You can't log out until 10 seconds after the end of combat.")
true
}
player.isTeleporting -> {
sendMessage(player, "Please finish your teleport before logging out.")
true
}
else -> {
Repository.disconnectionQueue.add(player)
true
}
}
}
return@on true
}
}
}

View file

@ -0,0 +1,23 @@
package content.global.handlers.iface.tabs
import content.global.skill.magic.SpellListener
import content.global.skill.magic.SpellListeners
import core.api.getAttribute
import core.game.interaction.InterfaceListener
import core.game.node.entity.combat.spell.MagicSpell
import core.game.node.entity.player.link.SpellBookManager.SpellBook
import core.game.world.GameWorld
class MagicTabInterface : InterfaceListener {
override fun defineInterfaceListeners() {
SpellBook.values().forEach {
on(it.interfaceId) { player, _, _, buttonID, _, _ ->
if (GameWorld.ticks < getAttribute(player, "magic:delay", -1)) return@on true
SpellListeners.run(buttonID, SpellListener.NONE, it.name.lowercase(), player)
return@on MagicSpell.castSpell(player, it, buttonID, player)
}
}
}
}

View file

@ -0,0 +1,38 @@
package content.global.handlers.iface.tabs
import core.api.sendMessage
import core.game.interaction.InterfaceListener
import core.game.node.entity.player.link.music.MusicEntry
import org.rs09.consts.Components
class MusicTabInterface : InterfaceListener {
override fun defineInterfaceListeners() {
on(Components.MUSIC_V3_187) { player, _, opcode, buttonID, slot, _ ->
if (opcode == 155) {
if (buttonID == 11) {
player.musicPlayer.toggleLooping()
return@on true
}
if (buttonID == 1) {
if (player.musicPlayer.unlocked[slot] != null) {
player.musicPlayer.play(player.musicPlayer.unlocked[slot])
return@on true
}
if (player.isAdmin) {
for (entry in MusicEntry.getSongs().values) {
if (entry.index == slot) {
player.musicPlayer.unlock(entry.id)
}
}
} else {
sendMessage(player, "You have not unlocked this piece of music yet!")
}
return@on true
}
}
return@on true
}
}
}

View file

@ -0,0 +1,14 @@
package content.global.handlers.iface.tabs
import core.game.interaction.InterfaceListener
import core.game.node.entity.player.link.prayer.PrayerType
import org.rs09.consts.Components
class PrayerTabInterface : InterfaceListener {
override fun defineInterfaceListeners() {
on(Components.PRAYER_271) { player, _, _, buttonID, _, _ ->
val prayer = PrayerType.get(buttonID) ?: return@on true
return@on player.prayer.toggle(prayer)
}
}
}

View file

@ -0,0 +1,36 @@
package content.global.handlers.iface.tabs
import content.global.handlers.iface.tabs.QuestTabUtils.showRequirementsInterface
import core.api.openInterface
import core.game.component.Component
import core.game.interaction.InterfaceListener
import core.game.node.entity.player.link.diary.DiaryType
import org.rs09.consts.Components
class QuestTabInterface : InterfaceListener {
override fun defineInterfaceListeners() {
on(Components.QUESTJOURNAL_V2_274) { player, _, _, buttonID, _, _ ->
if (buttonID == 3) {
player.achievementDiaryManager.openTab()
} else {
val quest = player.questRepository.forButtonId(buttonID)
if (quest != null) {
openInterface(player, Components.QUESTJOURNAL_SCROLL_275)
quest.drawJournal(player, quest.getStage(player))
} else {
showRequirementsInterface(player, buttonID)
}
}
return@on true
}
on(Components.AREA_TASK_259) { player, _, _, buttonID, _, _ ->
if (buttonID == 8) {
player.interfaceManager.openTab(2, Component(Components.QUESTJOURNAL_V2_274))
} else {
player.achievementDiaryManager.getDiary(DiaryType.forChild(buttonID))?.open(player)
}
return@on true
}
}
}

View file

@ -1,4 +1,4 @@
package content.global.handlers.iface
package content.global.handlers.iface.tabs
import core.game.requirement.*
import core.api.*
@ -242,4 +242,4 @@ object QuestTabUtils {
}
return quest as String
}
}
}

View file

@ -0,0 +1,35 @@
package content.global.handlers.iface.tabs
import core.api.*
import core.game.interaction.InterfaceListener
import core.game.node.entity.player.link.IronmanMode
import org.rs09.consts.Components
class SettingsTabInterface : InterfaceListener {
override fun defineInterfaceListeners() {
on(Components.OPTIONS_261) { player, _, _, buttonID, _, _ ->
when (buttonID) {
RUN -> player.settings.toggleRun()
CHAT_EFFECTS -> player.settings.toggleChatEffects()
SPLIT_PM -> player.settings.toggleSplitPrivateChat()
MOUSE -> player.settings.toggleMouseButton()
AID -> restrictForIronman(player, IronmanMode.STANDARD) { player.settings.toggleAcceptAid() }
HOUSE -> openSingleTab(player, Components.POH_HOUSE_OPTIONS_398)
GRAPHICS -> openInterface(player, Components.GRAPHICS_OPTIONS_742)
AUDIO -> openInterface(player, Components.SOUND_OPTIONS_743)
}
return@on true
}
}
companion object {
const val RUN = 3
const val CHAT_EFFECTS = 4
const val SPLIT_PM = 5
const val MOUSE = 6
const val AID = 7
const val HOUSE = 8
const val GRAPHICS = 16
const val AUDIO = 18
}
}

View file

@ -0,0 +1,87 @@
package content.global.handlers.iface.tabs
import core.api.*
import core.game.interaction.InterfaceListener
import core.game.node.entity.skill.LevelUp
import core.game.node.entity.skill.Skills
import org.rs09.consts.Components
class StatsTabInterface : InterfaceListener {
override fun defineInterfaceListeners() {
on(Components.STATS_320) { player, _, _, buttonID, _, _ ->
val config = skillMap[buttonID] ?: return@on true
if (getAttribute(player, "levelup:${config.skillID}", false)) {
removeAttributes(player, "levelup:${config.skillID}")
LevelUp.sendFlashingIcons(player, -1)
setVarp(player, 1230, ADVANCE_CONFIGS[config.skillID])
openInterface(player, 741)
} else {
openInterface(player, Components.SKILL_GUIDE_V2_499)
setVarp(player, 965, config.configID)
setAttribute(player, "skillMenu", config.configID)
}
return@on true
}
on(Components.SKILL_GUIDE_V2_499) { player, _, _, buttonID, _, _ ->
setVarbit(player, 3288, getAttribute(player, "skillMenu", -1))
setVarbit(player, 3289, buttonID - 10)
return@on true
}
on(LEVEL_UP_INTERFACE_740) { player, component, opcode, buttonID, slot, itemID ->
if (buttonID == 3) {
closeInterface(player)
}
return@on true
}
}
enum class SkillConfig(val buttonID: Int, val configID: Int, val skillID: Int) {
ATTACK(125, 1, Skills.ATTACK),
STRENGTH(126, 2, Skills.STRENGTH),
DEFENCE(127, 5, Skills.DEFENCE),
RANGE(128, 3, Skills.RANGE),
PRAYER(129, 7, Skills.PRAYER),
MAGIC(130, 4, Skills.MAGIC),
RUNECRAFT(131, 12, Skills.RUNECRAFTING),
HITPOINTS(133, 6, Skills.HITPOINTS),
AGILITY(134, 8, Skills.AGILITY),
HERBLORE(135, 9, Skills.HERBLORE),
THIEVING(136, 10, Skills.THIEVING),
CRAFTING(137, 11, Skills.CRAFTING),
FLETCHING(138, 19, Skills.FLETCHING),
SLAYER(139, 20, Skills.SLAYER),
MINING(141, 13, Skills.MINING),
SMITHING(142, 14, Skills.SMITHING),
FISHING(143, 15, Skills.FISHING),
COOKING(144, 16, Skills.COOKING),
FIREMAKING(145, 17, Skills.FIREMAKING),
WOODCUTTING(146, 18, Skills.WOODCUTTING),
FARMING(147, 21, Skills.FARMING),
CONSTRUCTION(132, 22, Skills.CONSTRUCTION),
HUNTER(140, 23, Skills.HUNTER),
SUMMONING(148, 24, Skills.SUMMONING),
}
companion object {
private const val LEVEL_UP_INTERFACE_740 = 740
val skillMap= HashMap<Int, SkillConfig>()
val ADVANCE_CONFIGS = intArrayOf(
9, 40, 17, 49,
25, 57, 33, 641,
659, 664, 121, 649,
89, 114, 107, 72,
64, 80, 673, 680,
99, 698, 689, 705
)
init {
for (skill in SkillConfig.values()) {
skillMap[skill.buttonID] = skill
}
}
}
}

View file

@ -17,7 +17,7 @@ class EmptyOptionListener : InteractionListener {
override fun defineListeners() {
on(EmptyItem.emptyItemList.toIntArray(), IntType.ITEM, "empty", "empty bowl", "empty dish") { player, node ->
if (node.name.contains("brew") || node.name.contains("potion") || node.name.lowercase(Locale.getDefault()).contains("poison") || node.name.lowercase(Locale.getDefault()).contains("serum") || node.name.contains("cure") || node.name.contains("mix") || node.name.contains("balm")) {
if (node.name.contains("brew") || node.name.contains("potion") || node.name.lowercase(Locale.getDefault()).contains("poison") || node.name.lowercase(Locale.getDefault()).contains("serum") || node.name.contains("cure") || node.name.contains("mix") || node.name.contains("balm") || node.name.contains("Super ")) {
replaceSlot(player, node.asItem().slot, Item(EmptyItem.getEmpty(Items.POTION_195)!!), node.asItem())
playAudio(player, EmptyItem.getEmptyAudio(Items.POTION_195)!!)
return@on true
@ -70,7 +70,7 @@ class EmptyOptionListener : InteractionListener {
emptyItemList.add(item.fullId)
}
for (item in ItemDefinition.getDefinitions().values)
if (item.name.contains("potion") || item.name.contains("brew") || item.name.contains("poison") || item.name.lowercase(Locale.getDefault()).contains("serum") || item.name.contains("cure") || item.name.contains("mix") || item.name.contains("balm")) {
if (item.name.contains("potion") || item.name.contains("brew") || item.name.contains("poison") || item.name.lowercase(Locale.getDefault()).contains("serum") || item.name.contains("cure") || item.name.contains("mix") || item.name.contains("balm") || item.name.contains("Super ")) {
emptyItemList.add(item.id)
}
}

View file

@ -3,12 +3,11 @@ package content.global.skill.construction;
import core.game.node.entity.Entity;
import core.game.node.entity.player.Player;
import core.game.world.map.build.DynamicRegion;
import core.game.world.map.zone.MapZone;
import core.game.world.map.RegionManager;
import core.game.world.map.Region;
import core.game.system.task.Pulse;
import core.game.world.map.zone.ZoneRestriction;
import core.game.world.map.zone.ZoneType;
import static core.api.ContentAPIKt.*;
@ -44,6 +43,7 @@ public final class HouseZone extends MapZone {
@Override
public void configure() {
setZoneType(ZoneType.P_O_H.getId());
unregisterOldRegions();
registerRegion(house.getHouseRegion().getId());
if (house.getDungeonRegion() != null) {
@ -82,7 +82,7 @@ public final class HouseZone extends MapZone {
if (e instanceof Player) {
Player p = (Player) e;
HouseManager.leave(p);
return true;
return true;
}
return super.death(e, killer);
}

View file

@ -11,6 +11,14 @@ import org.rs09.consts.Items
class FarmerPayOptionDialogue(val patch: Patch, val quickPay: Boolean = false): DialogueFile() {
var item: Item? = null
var itemSecondary: Item? = null
var itemTertiary: Item? = null
fun hasAllItems(): Boolean {
return (inInventory(player!!, item!!.id, item!!.amount) || inInventory(player!!, note(item!!).id, note(item!!).amount))
&& (inInventory(player!!, itemSecondary!!.id, itemSecondary!!.amount) || inInventory(player!!, note(itemSecondary!!).id, note(itemSecondary!!).amount))
&& (inInventory(player!!, itemTertiary!!.id, itemTertiary!!.amount) || inInventory(player!!, note(itemTertiary!!).id, note(itemTertiary!!).amount))
}
override fun handle(componentID: Int, buttonID: Int) {
when (stage) {
START_DIALOGUE -> {
@ -33,6 +41,9 @@ class FarmerPayOptionDialogue(val patch: Patch, val quickPay: Boolean = false):
npc("That patch is already fully grown!", "I don't know what you want me to do with it!").also { stage = END_DIALOGUE }
} else {
item = patch.plantable?.protectionItem
itemSecondary = patch.plantable?.protectionItemSecondary
itemTertiary = patch.plantable?.protectionItemTertiary
val protectionText = when (item?.id) {
Items.COMPOST_6032 -> if (item?.amount == 1) "bucket of compost" else "buckets of compost"
Items.POTATOES10_5438 -> if (item?.amount == 1) "sack of potatoes" else "sacks of potatoes"
@ -51,10 +62,22 @@ class FarmerPayOptionDialogue(val patch: Patch, val quickPay: Boolean = false):
}
if (item == null) {
npc("Sorry, I won't protect that.").also { stage = END_DIALOGUE }
} else if (patch.patch.type == PatchType.SPIRIT_TREE_PATCH && quickPay
&& !hasAllItems()) {
val amount = if (item?.amount == 1) "one" else item?.amount
npc(FacialExpression.HAPPY, "I want $amount $protectionText, one monkey bar,", "and one ground tooth for that.")
stage = 200
} else if (quickPay && !(inInventory(player!!, item!!.id, item!!.amount) || inInventory(player!!, note(item!!).id, note(item!!).amount))) {
val amount = if (item?.amount == 1) "one" else item?.amount
npc(FacialExpression.HAPPY, "I want $amount $protectionText for that.")
stage = 200
} else if (patch.patch.type == PatchType.SPIRIT_TREE_PATCH && quickPay) {
showTopics(
//Found a 2011 source for quick-pay, but no earlier dialogue sources (https://www.youtube.com/watch?v=RdIcNH50v7I)
Topic("Yes", 20, true),
Topic("No", END_DIALOGUE, true),
title = "Pay the gnome?"
)
} else if (quickPay) {
val amount = if (item?.amount == 1) "one" else item?.amount
showTopics(
@ -62,6 +85,10 @@ class FarmerPayOptionDialogue(val patch: Patch, val quickPay: Boolean = false):
Topic("No", END_DIALOGUE, true),
title = "Pay $amount $protectionText?"
)
} else if (patch.patch.type == PatchType.SPIRIT_TREE_PATCH) {
val amount = if (item?.amount == 1) "one" else item?.amount
npc("If you like, but I want $amount $protectionText,", "one monkey bar, and one ground tooth for that.")
stage++
} else {
val amount = if (item?.amount == 1) "one" else item?.amount
npc("If you like, but I want $amount $protectionText for that.")
@ -71,7 +98,9 @@ class FarmerPayOptionDialogue(val patch: Patch, val quickPay: Boolean = false):
}
1 -> {
if (!(inInventory(player!!, item!!.id, item!!.amount) || inInventory(player!!, note(item!!).id, note(item!!).amount))) {
if (patch.patch.type == PatchType.SPIRIT_TREE_PATCH && !hasAllItems()) {
player("I'm afraid I don't have any of those at the moment.").also { stage = 10 }
} else if (!(inInventory(player!!, item!!.id, item!!.amount) || inInventory(player!!, note(item!!).id, note(item!!).amount))) {
player("I'm afraid I don't have any of those at the moment.").also { stage = 10 }
} else {
showTopics(
@ -84,7 +113,14 @@ class FarmerPayOptionDialogue(val patch: Patch, val quickPay: Boolean = false):
10 -> npc("Well, I'm not wasting my time for free.").also { stage = END_DIALOGUE }
20 -> {
if (removeItem(player!!, item) || removeItem(player!!, note(item!!))) {
if (patch.patch.type == PatchType.SPIRIT_TREE_PATCH
&& (removeItem(player!!, item) || removeItem(player!!, note(item!!)))
&& (removeItem(player!!, itemSecondary) || removeItem(player!!, note(itemSecondary!!)))
&& (removeItem(player!!, itemTertiary) || removeItem(player!!, note(itemTertiary!!)))) {
patch.protectionPaid = true
npc("That'll do nicely, ${if (player!!.isMale) "sir" else "madam"}. Leave it with me - I'll make sure", "that tree grows up good and strong.").also { stage = END_DIALOGUE }
} else if (patch.patch.type != PatchType.SPIRIT_TREE_PATCH
&& removeItem(player!!, item) || removeItem(player!!, note(item!!))) {
patch.protectionPaid = true
// Note: A slight change in this dialogue was seen in a December 2009 video - https://youtu.be/7gVh42ylQ48?t=138
npc("That'll do nicely, ${if (player!!.isMale) "sir" else "madam"}. Leave it with me - I'll make sure", "those crops grow for you.").also { stage = END_DIALOGUE }

View file

@ -21,7 +21,11 @@ enum class Farmers(val id: Int, val patches: Array<FarmingPatch>) {
FRANCIS(2327, arrayOf(FarmingPatch.ENTRANA_HOPS)),
DREVEN(2335, arrayOf(FarmingPatch.CHAMPIONS_GUILD_BUSH)),
TARIA(2336, arrayOf(FarmingPatch.RIMMINGTON_BUSH)),
TORRELL(2338, arrayOf(FarmingPatch.ARDOUGNE_BUSH));
TORRELL(2338, arrayOf(FarmingPatch.ARDOUGNE_BUSH)),
FRIZZY(4560, arrayOf(FarmingPatch.PORT_SARIM_SPIRIT_TREE)),
YULF(4561, arrayOf(FarmingPatch.ETCETERIA_SPIRIT_TREE)),
PRAISTAN(4562, arrayOf(FarmingPatch.KARAMJA_SPIRIT_TREE))
;
companion object{
@JvmField

View file

@ -5,6 +5,7 @@ import core.cache.def.impl.SceneryDefinition
import core.game.interaction.OptionHandler
import core.game.node.Node
import content.global.skill.summoning.familiar.GiantEntNPC
import content.global.skill.summoning.familiar.WolpertingerNPC
import core.game.node.entity.player.Player
import core.game.node.entity.player.link.diary.DiaryType
import core.game.node.entity.skill.Skills
@ -76,8 +77,15 @@ class FruitAndBerryPicker : OptionHandler() {
animate(player, animation)
playAudio(player, Sounds.FARMING_PICK_2437)
addItemOrDrop(player, reward.id, reward.amount)
rewardXP(player, Skills.FARMING, plantable.harvestXP)
if (familiar != null && familiar is WolpertingerNPC && patch.patch.type == PatchType.BUSH_PATCH) {
addItemOrDrop(player, reward.id, reward.amount * 2)
rewardXP(player, Skills.FARMING, plantable.harvestXP * 2)
}
else {
addItemOrDrop(player, reward.id, reward.amount)
rewardXP(player, Skills.FARMING, plantable.harvestXP)
}
patch.setCurrentState(patch.getCurrentState() - 1)
if (patch.patch.type == PatchType.CACTUS_PATCH) {

View file

@ -32,6 +32,11 @@ class FruitTreeChopper : OptionHandler() {
val plantable = patch.plantable
plantable ?: return false
if (SkillingTool.getHatchet(player) == null) {
sendMessage(player, "You do not have an axe to use.")
return true
}
val animation = SkillingTool.getHatchet(player).animation
submitIndividualPulse(player, object : Pulse(animation.duration) {

View file

@ -26,7 +26,7 @@ class HealthChecker : OptionHandler() {
val patch = fPatch.getPatchFor(player)
val type = patch.patch.type
if (type != PatchType.BUSH_PATCH && type != PatchType.FRUIT_TREE_PATCH && type != PatchType.TREE_PATCH && type != PatchType.CACTUS_PATCH) {
if (!patch.isCheckable()) {
sendMessage(player, "This shouldn't be happening. Please report this.")
return true
}
@ -44,6 +44,10 @@ class HealthChecker : OptionHandler() {
patch.setCurrentState(patch.getCurrentState() - 14)
sendMessage(player, "You examine the tree for signs of disease and find that it is in perfect health.")
}
PatchType.SPIRIT_TREE_PATCH -> {
patch.setCurrentState(patch.getCurrentState() - 24)
sendMessage(player, "You examine the tree for signs of disease and find that it is in perfect health.")
}
PatchType.BUSH_PATCH -> {
patch.setCurrentState(patch.plantable!!.value + patch.plantable!!.stages + 4)
sendMessage(player, "You examine the bush for signs of disease and find that it's in perfect health.")

View file

@ -16,6 +16,7 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl
var compost = CompostType.NONE
var protectionPaid = false
var cropLives = 3
val checkablePatches = arrayOf(PatchType.TREE_PATCH, PatchType.BUSH_PATCH, PatchType.FRUIT_TREE_PATCH, PatchType.SPIRIT_TREE_PATCH, PatchType.CACTUS_PATCH)
fun setNewHarvestAmount() {
val compostMod = when(compost) {
@ -162,6 +163,7 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl
PatchType.BUSH_PATCH -> setVarbit(player, patch.varbit, 250 + (plantable!!.ordinal - Plantable.REDBERRY_SEED.ordinal))
PatchType.CACTUS_PATCH -> setVarbit(player, patch.varbit, 31)
PatchType.TREE_PATCH -> setVarbit(player, patch.varbit, plantable!!.value + plantable!!.stages)
PatchType.SPIRIT_TREE_PATCH -> setVarbit(player, patch.varbit, plantable!!.value + plantable!!.stages + 24)
else -> log(this::class.java, Log.WARN, "Invalid setting of isCheckHealth for patch type: " + patch.type.name + "at" + patch.name)
}
} else {
@ -187,6 +189,10 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl
if (state != getVarbit(player, patch.varbit))
setVisualState(state)
}
PatchType.SPIRIT_TREE_PATCH -> {
if(isDead) setVisualState(getSpiritTreeDeathValue())
else if(isDiseased && !isDead) setVisualState(getSpiritTreeDiseaseValue())
}
PatchType.FRUIT_TREE_PATCH -> {
if(isDead) setVisualState(getFruitTreeDeathValue())
else if(isDiseased && !isDead) setVisualState(getFruitTreeDiseaseValue())
@ -256,6 +262,14 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl
}
}
private fun getSpiritTreeDiseaseValue(): Int {
return (plantable?.value ?: 0) + currentGrowthStage + 12
}
private fun getSpiritTreeDeathValue(): Int {
return (plantable?.value ?: 0) + currentGrowthStage + 24
}
private fun getFruitTreeDiseaseValue(): Int {
return (plantable?.value ?: 0) + currentGrowthStage + 12
}
@ -338,7 +352,7 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl
return
}
if((patch.type == PatchType.FRUIT_TREE_PATCH || patch.type == PatchType.TREE_PATCH || patch.type == PatchType.BUSH_PATCH || patch.type == PatchType.CACTUS_PATCH) && plantable != null && plantable?.stages == currentGrowthStage + 1){
if(isCheckable() && plantable != null && plantable?.stages == currentGrowthStage + 1){
isCheckHealth = true
}
@ -412,6 +426,10 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl
// restocking their fruit should take 40 minutes per fruit
minutes = 40
}
else if(plantable == Plantable.WILLOW_SAPLING && isGrown()) {
// Willow Branches grow back in only 5 minutes
minutes = 5
}
return minutes
}
@ -432,4 +450,8 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl
(fpatch.plantable == plantable?.protectionFlower || fpatch.plantable == Plantable.forItemID(Items.WHITE_LILY_SEED_14589))
&& fpatch.isGrown())
}
fun isCheckable(): Boolean{
return (patch.type in checkablePatches)
}
}

View file

@ -3,7 +3,7 @@ package content.global.skill.farming
import core.game.node.item.Item
import org.rs09.consts.Items
enum class Plantable(val itemID: Int, val displayName: String, val value: Int, val stages: Int, val plantingXP: Double, val harvestXP: Double, val checkHealthXP: Double, val requiredLevel: Int, val applicablePatch: PatchType, val harvestItem: Int, val protectionItem: Item? = null, val protectionFlower: Plantable? = null) {
enum class Plantable(val itemID: Int, val displayName: String, val value: Int, val stages: Int, val plantingXP: Double, val harvestXP: Double, val checkHealthXP: Double, val requiredLevel: Int, val applicablePatch: PatchType, val harvestItem: Int, val protectionItem: Item? = null, val protectionFlower: Plantable? = null, val protectionItemSecondary: Item? = null, val protectionItemTertiary: Item? = null) {
// Flowers
MARIGOLD_SEED(Items.MARIGOLD_SEED_5096,"marigold seed",8,4,8.5,47.0,0.0,2,PatchType.FLOWER_PATCH,Items.MARIGOLDS_6010),
@ -80,7 +80,8 @@ enum class Plantable(val itemID: Int, val displayName: String, val value: Int, v
BELLADONNA_SEED(Items.BELLADONNA_SEED_5281, "belladonna seed", 4, 4, 91.0, 128.0, 0.0, 63, PatchType.BELLADONNA_PATCH, Items.CAVE_NIGHTSHADE_2398),
MUSHROOM_SPORE(Items.MUSHROOM_SPORE_5282, "mushroom spore", 4, 6, 61.5, 57.7, 0.0, 53, PatchType.MUSHROOM_PATCH, Items.MUSHROOM_6004),
CACTUS_SEED(Items.CACTUS_SEED_5280, "cactus seed", 8, 7, 66.5, 25.0, 374.0, 55, PatchType.CACTUS_PATCH, Items.CACTUS_SPINE_6016),
EVIL_TURNIP_SEED(Items.EVIL_TURNIP_SEED_12148, "evil turnip seed", 4, 1, 41.0, 46.0, 0.0, 42, PatchType.EVIL_TURNIP_PATCH, Items.EVIL_TURNIP_12134)
EVIL_TURNIP_SEED(Items.EVIL_TURNIP_SEED_12148, "evil turnip seed", 4, 1, 41.0, 46.0, 0.0, 42, PatchType.EVIL_TURNIP_PATCH, Items.EVIL_TURNIP_12134),
SPIRIT_SAPLING(Items.SPIRIT_SAPLING_5375, "spirit tree sapling", 8, 12, 199.5, 0.0, 19301.0, 83, PatchType.SPIRIT_TREE_PATCH, 0, Item(Items.MONKEY_NUTS_4012, 5), null, Item(Items.MONKEY_BAR_4014, 1), Item(Items.GROUND_TOOTH_9082, 1) )
;
constructor(itemID: Int, displayName: String, value: Int, stages: Int, plantingXP: Double, harvestXP: Double, checkHealthXP: Double, requiredLevel: Int, applicablePatch: PatchType, harvestItem: Int, protectionFlower: Plantable)

View file

@ -38,6 +38,7 @@ class UseWithPatchHandler : InteractionListener {
onUseWith(IntType.SCENERY, allowedNodes.toIntArray(), *FarmingPatch.patchNodes.toIntArray()) { player, used, with ->
val patch = FarmingPatch.forObject(with.asScenery()) ?: return@onUseWith true
val usedItem = used.asItem()
val trimmablePatches = arrayOf(PatchType.TREE_PATCH, PatchType.BUSH_PATCH, PatchType.FRUIT_TREE_PATCH, PatchType.SPIRIT_TREE_PATCH)
if (patch == FarmingPatch.TROLL_STRONGHOLD_HERB) {
if (!hasRequirement(player, Quests.MY_ARMS_BIG_ADVENTURE))
@ -79,7 +80,7 @@ class UseWithPatchHandler : InteractionListener {
}
SECATEURS, MAGIC_SECATEURS -> {
val p = patch.getPatchFor(player)
if (patch.type == PatchType.TREE_PATCH) {
if (patch.type in trimmablePatches) {
if (p.isDiseased && !p.isDead) {
submitIndividualPulse(player, object: Pulse() {
override fun pulse(): Boolean {
@ -131,7 +132,7 @@ class UseWithPatchHandler : InteractionListener {
Items.PLANT_CURE_6036 -> {
val p = patch.getPatchFor(player)
val patchName = p.patch.type.displayName()
if (p.isDiseased && !p.isDead) {
if (p.isDiseased && !p.isDead && patch.type !in trimmablePatches) {
sendMessage(player, "You treat the $patchName with the plant cure.")
queueScript(player, 0, QueueStrength.WEAK) { stage: Int ->
when (stage) {
@ -260,12 +261,17 @@ class UseWithPatchHandler : InteractionListener {
}*/
val requiredItem = when (patch.type) {
PatchType.TREE_PATCH, PatchType.FRUIT_TREE_PATCH -> Items.SPADE_952
PatchType.TREE_PATCH, PatchType.FRUIT_TREE_PATCH, PatchType.SPIRIT_TREE_PATCH -> Items.SPADE_952
PatchType.FLOWER_PATCH -> if (plantable == Plantable.SCARECROW) null else Items.SEED_DIBBER_5343
else -> Items.SEED_DIBBER_5343
}
if (requiredItem != null && !inInventory(player, requiredItem)) {
sendMessage(player, "You need ${prependArticle(requiredItem.asItem().name.lowercase())} to plant that.")
sendDialogue(player, "You need ${prependArticle(requiredItem.asItem().name.lowercase())} to plant that.")
return@onUseWith true
}
val spiritTreePlanted = (getVarbit(player, 720) > 3 || getVarbit(player, 722) > 3 || getVarbit(player, 724) > 3)
if (plantable == Plantable.SPIRIT_SAPLING && spiritTreePlanted){
sendDialogue(player, "You already have a spirit tree. You can't plant another one.")
return@onUseWith true
}
@ -278,7 +284,7 @@ class UseWithPatchHandler : InteractionListener {
}
animate(player, anim)
playAudio(player, sound)
val delay = if (patch.type == PatchType.TREE_PATCH || patch.type == PatchType.FRUIT_TREE_PATCH || plantable == Plantable.SCARECROW) 3 else 0
val delay = if (patch.type == PatchType.TREE_PATCH || patch.type == PatchType.FRUIT_TREE_PATCH || patch.type == PatchType.SPIRIT_TREE_PATCH || plantable == Plantable.SCARECROW) 3 else 0
return@queueScript delayScript(player,anim.duration + delay)
}
1 -> {
@ -289,12 +295,12 @@ class UseWithPatchHandler : InteractionListener {
p.plant(plantable)
rewardXP(player, Skills.FARMING, plantable.plantingXP)
p.setNewHarvestAmount()
if (p.patch.type == PatchType.TREE_PATCH || p.patch.type == PatchType.FRUIT_TREE_PATCH) {
if (p.patch.type == PatchType.TREE_PATCH || p.patch.type == PatchType.FRUIT_TREE_PATCH || p.patch.type == PatchType.SPIRIT_TREE_PATCH) {
addItem(player, Items.PLANT_POT_5350)
}
val itemAmount =
if (p.patch.type == PatchType.TREE_PATCH || p.patch.type == PatchType.FRUIT_TREE_PATCH) "the"
if (p.patch.type == PatchType.TREE_PATCH || p.patch.type == PatchType.FRUIT_TREE_PATCH || p.patch.type == PatchType.SPIRIT_TREE_PATCH) "the"
else if (plantItem.amount == 1) "a"
else plantItem.amount
val itemName =

View file

@ -57,7 +57,7 @@ class CropGrowth : PersistTimer (500, "farming:crops", isSoft = true) {
private fun runOfflineCatchupLogic() {
for ((_, patch) in patchMap) {
val type = patch.patch.type
val shouldPlayCatchup = !patch.isGrown() || (type == PatchType.BUSH_PATCH && patch.getFruitOrBerryCount() < 4) || (type == PatchType.FRUIT_TREE_PATCH && patch.getFruitOrBerryCount() < 6)
val shouldPlayCatchup = !patch.isGrown() || (type == PatchType.BUSH_PATCH && patch.getFruitOrBerryCount() < 4) || (type == PatchType.FRUIT_TREE_PATCH && patch.getFruitOrBerryCount() < 6) || (patch.plantable == Plantable.WILLOW_SAPLING && patch.harvestAmt < 6)
if (shouldPlayCatchup && !patch.isDead && !patch.isChoppedFruitTree()) {
var stagesToSimulate = if (!patch.isGrown()) {
if (patch.isWeedy() || patch.isEmptyAndWeeded()) patch.currentGrowthStage % 4
@ -69,6 +69,8 @@ class CropGrowth : PersistTimer (500, "farming:crops", isSoft = true) {
stagesToSimulate += Math.min(4, 4 - patch.getFruitOrBerryCount())
if (type == PatchType.FRUIT_TREE_PATCH)
stagesToSimulate += Math.min(6, 6 - patch.getFruitOrBerryCount())
if (patch.plantable == Plantable.WILLOW_SAPLING)
stagesToSimulate += Math.min(6, 6 - patch.harvestAmt)
}
val nowTime = System.currentTimeMillis()

View file

@ -6,7 +6,7 @@ package content.global.skill.herblore;
* @author treevar
*/
public enum class BarbarianPotion {
ATTACK_POTION(123, 4, 11429, 8.0, true), ANTI_POISION_POTION(177, 6, 11433, 12.0, true), RELIC(4846, 9, 11437, 14.0, true), STRENGTH_POTION(117, 14, 11443, 17.0, true), RESTORE_POTION(129, 24, 11449, 21.0, true), ENERGY_POTION(3012, 29, 11453, 23.0, false), DEFENCE_POTION(135, 33, 11457, 25.0, false), AGILITY_POTION(3036, 37, 11461, 27.0, false), COMBAT_POTION(9743, 40, 11445, 28.0, false), PRAYER_POTION(141, 42, 11465, 29.0, false), SUPER_ATTACK_POTION(147, 47, 11469, 33.0, false), SUPER_ANTIPOISION_POTION(183, 51, 11473, 35.0, false), FISHING_POTION(153, 53, 11477, 38.0, false), SUPER_ENERGY_POTION(3020, 56, 11481, 42.0, false), HUNTER_POTION(10002, 58, 11517, 40.0, false), SUPER_STRENGTH_POTION(159, 59, 11485, 42.0, false), SUPER_RESTORE(3028, 67, 11493, 48.0, false), SUPER_DEFENCE_POTION(165, 71, 11497, 50.0, false), ANTIDOTE_PLUS(5947, 74, 11501, 52.0, false), ANTIFIRE_POTION(2456, 75, 11505, 53.0, false), RANGING_POTION(171, 80, 11509, 54.0, false), MAGIC_POTION(3044, 83, 11513, 57.0, false), ZAMORAK_BREW(191, 85, 11521, 58.0, false);
ATTACK_POTION(123, 4, 11429, 8.0, true), ANTI_POISION_POTION(177, 6, 11433, 12.0, true), RELIC(4846, 9, 11437, 14.0, true), STRENGTH_POTION(117, 14, 11443, 17.0, true), RESTORE_POTION(129, 24, 11449, 21.0, true), ENERGY_POTION(3012, 29, 11453, 23.0, false), DEFENCE_POTION(135, 33, 11457, 25.0, false), AGILITY_POTION(3036, 37, 11461, 27.0, false), COMBAT_POTION(9743, 40, 11445, 28.0, false), PRAYER_POTION(141, 42, 11465, 29.0, false), SUPER_ATTACK_POTION(147, 47, 11469, 33.0, false), SUPER_ANTIPOISION_POTION(183, 51, 11473, 35.0, false), FISHING_POTION(153, 53, 11477, 38.0, false), SUPER_ENERGY_POTION(3020, 56, 11481, 42.0, false), HUNTER_POTION(10002, 58, 11517, 40.0, false), SUPER_STRENGTH_POTION(159, 59, 11485, 42.0, false), MAGIC_ESSENCE_POTION(9023, 61, 11489, 43.0, false), SUPER_RESTORE(3028, 67, 11493, 48.0, false), SUPER_DEFENCE_POTION(165, 71, 11497, 50.0, false), ANTIDOTE_PLUS(5947, 74, 11501, 52.0, false), ANTIFIRE_POTION(2456, 75, 11505, 53.0, false), RANGING_POTION(171, 80, 11509, 54.0, false), MAGIC_POTION(3044, 83, 11513, 57.0, false), ZAMORAK_BREW(191, 85, 11521, 58.0, false);
/**
* Constructs a new {@code BarbarianPotion} {@Code Object}.

View file

@ -7,7 +7,7 @@ import core.game.node.item.Item;
* @author 'Vexia
*/
public enum Herbs {
GUAM(new Item(199), 2.5, 3, new Item(249)), MARRENTILL(new Item(201), 3.8, 5, new Item(251)), TARROMIN(new Item(203), 5, 11, new Item(253)), HARRALANDER(new Item(205), 6.3, 20, new Item(255)), RANARR(new Item(207), 7.5, 25, new Item(257)), TOADFLAX(new Item(3049), 8, 30, new Item(2998)), SPIRIT_WEED(new Item(12174), 7.8, 35, new Item(12172)), IRIT(new Item(209), 8.8, 40, new Item(259)), AVANTOE(new Item(211), 10, 48, new Item(261)), KWUARM(new Item(213), 11.3, 54, new Item(263)), SNAPDRAGON(new Item(3051), 11.8, 59, new Item(3000)), CADANTINE(new Item(215), 12.5, 65, new Item(265)), LANTADYME(new Item(2485), 13.1, 67, new Item(2481)), DWARF_WEED(new Item(217), 13.8, 70, new Item(267)), TORSTOL(new Item(219), 15, 75, new Item(269)), SNAKE_WEED(new Item(1525), 2.5, 3, new Item(1526)), ARDRIGAL(new Item(1527), 2.5, 3, new Item(1528)), SITO_FOIL(new Item(1529), 2.5, 3, new Item(1530)), VOLENCIA_MOSS(new Item(1531), 2.5, 3, new Item(1532)), ROGUES_PURSE(new Item(1533), 0, 8, new Item(1534));
GUAM(new Item(199), 2.5, 3, new Item(249)), MARRENTILL(new Item(201), 3.8, 5, new Item(251)), TARROMIN(new Item(203), 5, 11, new Item(253)), HARRALANDER(new Item(205), 6.3, 20, new Item(255)), RANARR(new Item(207), 7.5, 25, new Item(257)), TOADFLAX(new Item(3049), 8, 30, new Item(2998)), SPIRIT_WEED(new Item(12174), 7.8, 35, new Item(12172)), IRIT(new Item(209), 8.8, 40, new Item(259)), AVANTOE(new Item(211), 10, 48, new Item(261)), KWUARM(new Item(213), 11.3, 54, new Item(263)), SNAPDRAGON(new Item(3051), 11.8, 59, new Item(3000)), CADANTINE(new Item(215), 12.5, 65, new Item(265)), LANTADYME(new Item(2485), 13.1, 67, new Item(2481)), DWARF_WEED(new Item(217), 13.8, 70, new Item(267)), TORSTOL(new Item(219), 15, 75, new Item(269)), SNAKE_WEED(new Item(1525), 2.5, 3, new Item(1526)), ARDRIGAL(new Item(1527), 2.5, 3, new Item(1528)), SITO_FOIL(new Item(1529), 2.5, 3, new Item(1530)), VOLENCIA_MOSS(new Item(1531), 2.5, 3, new Item(1532)), ROGUES_PURSE(new Item(1533), 2.5, 3, new Item(1534));
/**
* Represents the herb item.

View file

@ -16,6 +16,7 @@ import core.game.node.item.Item;
import core.game.world.map.Location;
import core.game.world.map.zone.ZoneRestriction;
import core.game.world.update.flag.context.Animation;
import org.rs09.consts.Items;
import java.util.ArrayList;
import java.util.HashMap;
@ -341,6 +342,9 @@ public final class FamiliarManager {
for (int food : pets.getFood()) {
if (food == foodId) {
player.getInventory().remove(new Item(foodId));
if (foodId == Items.BUCKET_OF_MILK_1927) {
player.getInventory().add(new Item(Items.BUCKET_1925));
}
player.getPacketDispatch().sendMessage("Your pet happily eats the " + ItemDefinition.forId(food).getName() + ".");
player.animate(new Animation(827));
npc.getDetails().updateHunger(-15.0);

View file

@ -67,7 +67,7 @@ public final class KittenInteractDialogue extends DialoguePlugin {
interpreter.sendDialogues(player, null, "That cat sure loves to be stroked.");
stage = 99;
break;
case 2:// chase-vermine
case 2:// chase-vermin
end();
player.sendChat("Go on puss...kill that rat!");
boolean cant = true;

View file

@ -5,7 +5,6 @@ import content.global.skill.summoning.familiar.Familiar;
import content.global.skill.summoning.familiar.FamiliarSpecial;
import core.game.node.entity.player.Player;
import core.game.node.item.Item;
import core.game.world.GameWorld;
import static core.api.ContentAPIKt.*;
@ -67,10 +66,13 @@ public final class Pet extends Familiar {
@Override
public void handleTickActions() {
final PetDetails petDetails = details;
if (getPet().getFood().length > 0) {
if (getPet().getFood().length > 0 && !pet.isGrownCat(itemId)) {
if(!SkillcapePerks.isActive(SkillcapePerks.PET_MASTERY, owner)) {
double amount = itemId == pet.getBabyItemId() ? 0.025 : 0.018;
if (GameWorld.getSettings().isDevMode()) {
if (owner.getAttribute("petrate",1) == 0) {
amount = 0 ;
}
else if (owner.getAttribute("petrate",1) == 2) {
amount *= 100;
}
petDetails.updateHunger(amount);
@ -96,7 +98,10 @@ public final class Pet extends Familiar {
double growth = petDetails.getGrowth();
double growthrate = pet.getGrowthRate();
if (growthrate > 0.000) {
if (GameWorld.getSettings().isDevMode()) {
if (owner.getAttribute("petrate",1) == 0) {
growthrate = 0;
}
else if (owner.getAttribute("petrate",1) == 2) {
growthrate *= 100;
}
petDetails.updateGrowth(growthrate);

View file

@ -25,16 +25,6 @@ public enum Pets {
*/
CLOCKWORK_CAT(7771, 7772, -1, 3598, -1, -1, 0.0, 0),
/**
* The firemaker's curse pets.
*/
SEARING_FLAME(22994, -1, -1, 14769, -1, -1, 0.0, 0), GLOWING_EMBER(22993, -1, -1, 14768, -1, -1, 0.0, 0), TWISTED_FIRESTARTER(22995, -1, -1, 14770, -1, -1, 0.0, 0), WARMING_FLAME(22992, -1, -1, 14767, -1, -1, 0.0, 0),
/**
* Troll baby pet.
*/
TROLL_BABY(23030, 23030, -1, 14846, -1, -1, 0.0, 0),
/**
* A bulldog pet.
*/
@ -63,7 +53,7 @@ public enum Pets {
/**
* A terrier pet.
*/
TERRIER(12512, 12513, -1, 6958, 6859, -1, 0.0033333333333333, 4, 2132, 2134, 2136, 2138, 10816, 9986, 9978, 526), TERRIER_1(12700, 12701, -1, 7237, 7238, -1, 0.0033333333333333, 4, 2132, 2134, 2136, 2138, 10816, 9986, 9978, 526), TERRIER_2(12702, 12703, -1, 7239, 7240, -1, 0.0033333333333333, 4, 2132, 2134, 2136, 2138, 10816, 9986, 9978, 526),
TERRIER(12512, 12513, -1, 6958, 6959, -1, 0.0033333333333333, 4, 2132, 2134, 2136, 2138, 10816, 9986, 9978, 526), TERRIER_1(12700, 12701, -1, 7237, 7238, -1, 0.0033333333333333, 4, 2132, 2134, 2136, 2138, 10816, 9986, 9978, 526), TERRIER_2(12702, 12703, -1, 7239, 7240, -1, 0.0033333333333333, 4, 2132, 2134, 2136, 2138, 10816, 9986, 9978, 526),
/**
* A creeping hand pet.
@ -90,11 +80,6 @@ public enum Pets {
*/
//ABYSSAL_MINION(14651, -1, -1, 8624, -1, -1, 0.0033333333333333, 4, 592),
/**
* Rune guardian pets.
*/
RUNE_GUARDIAN(15626, -1, -1, 9656, -1, -1, 0.0033333333333333, 4), RUNE_GUARDIAN_1(15627, -1, -1, 9657, -1, -1, 0.0033333333333333, 4), RUNE_GUARDIAN_2(15628, -1, -1, 9658, -1, -1, 0.0033333333333333, 4), RUNE_GUARDIAN_3(15629, -1, -1, 9659, -1, -1, 0.0033333333333333, 4), RUNE_GUARDIAN_4(15630, -1, -1, 9660, -1, -1, 0.0033333333333333, 4), RUNE_GUARDIAN_5(15631, -1, -1, 9661, -1, -1, 0.0033333333333333, 4), RUNE_GUARDIAN_6(15632, -1, -1, 9662, -1, -1, 0.0033333333333333, 4), RUNE_GUARDIAN_7(15633, -1, -1, 9663, -1, -1, 0.0033333333333333, 4), RUNE_GUARDIAN_8(15634, -1, -1, 9664, -1, -1, 0.0033333333333333, 4), RUNE_GUARDIAN_9(15635, -1, -1, 9665, -1, -1, 0.0033333333333333, 4), RUNE_GUARDIAN_10(15636, -1, -1, 9666, -1, -1, 0.0033333333333333, 4), RUNE_GUARDIAN_11(15637, -1, -1, 9667, -1, -1, 0.0033333333333333, 4), RUNE_GUARDIAN_12(15638, -1, -1, 9668, -1, -1, 0.0033333333333333, 4), RUNE_GUARDIAN_13(15639, -1, -1, 9669, -1, -1, 0.0033333333333333, 4),
/**
* Gecko pet.
*/
@ -115,11 +100,6 @@ public enum Pets {
*/
PENGUIN(12481, 12482, -1, 6908, 6909, -1, 0.0046296296296296, 30, 321, 363, 341, 15264, 345, 377, 353, 389, 7944, 349, 331, 327, 395, 383, 317, 371, 335, 359, 15264, 15270), PENGUIN_1(12763, 12762, -1, 7313, 7314, -1, 0.0046296296296296, 30, 321, 363, 341, 15264, 345, 377, 353, 389, 7944, 349, 331, 327, 395, 383, 317, 371, 335, 359, 15264, 15270), PENGUIN_2(12765, 12764, -1, 7316, 7317, -1, 0.0046296296296296, 30, 321, 363, 341, 15264, 345, 377, 353, 389, 7944, 349, 331, 327, 395, 383, 317, 371, 335, 359, 15264, 15270),
/**
* A tooth creature pet.
*/
TOOTH_CREATURE(18671, 18669, -1, 11411, 11413, -1, 0.075757575757576, 37, 1927, 1977),
/**
* A giant crab pet.
*/
@ -155,11 +135,6 @@ public enum Pets {
*/
RACCOON(12486, 12487, -1, 6913, 6914, -1, 0.0029444444444444, 80, 321, 363, 341, 15264, 345, 377, 353, 389, 7944, 349, 331, 327, 395, 383, 317, 371, 335, 359, 15264, 15270, 2132, 2134, 2136, 2138, 10816, 9986, 9978), RACCOON_1(12734, 12735, -1, 7271, 7272, -1, 0.0029444444444444, 80, 321, 363, 341, 15264, 345, 377, 353, 389, 7944, 349, 331, 327, 395, 383, 317, 371, 335, 359, 15264, 15270, 2132, 2134, 2136, 2138, 10816, 9986, 9978), RACCOON_2(12736, 12737, -1, 7273, 7274, -1, 0.0029444444444444, 80, 321, 363, 341, 15264, 345, 377, 353, 389, 7944, 349, 331, 327, 395, 383, 317, 371, 335, 359, 15264, 15270, 2132, 2134, 2136, 2138, 10816, 9986, 9978),
/**
* A sneaker peeper pet.
*/
SNEAKER_PEEPER(19894, 19895, -1, 13089, 13090, -1, 0.05, 80, 221),
/**
* A vulture pet.
*/
@ -446,4 +421,24 @@ public enum Pets {
return false;
}
}
/**
* Checks if this pet is a grown cat
* @return a boolean, true if the pet is a grown cat
*/
public boolean isGrownCat(int id) {
switch (this) {
case CAT:
case CAT_1:
case CAT_2:
case CAT_3:
case CAT_4:
case CAT_5:
case CAT_6:
case HELLCAT:
return id == grownItemId || id == overgrownItemId;
default:
return false;
}
}
}

View file

@ -1,9 +1,5 @@
package content.global.travel.trees
import core.api.isQuestComplete
import core.api.openDialogue
import core.api.sendDialogue
import core.api.teleport
import core.game.node.entity.npc.NPC
import core.game.node.entity.player.Player
import core.game.node.entity.player.link.diary.DiaryType
@ -18,9 +14,10 @@ import core.game.interaction.IntType
import core.game.world.GameWorld.Pulser
import core.tools.END_DIALOGUE
import content.data.Quests
import core.api.*
class GnomeSpiritTreeListener: InteractionListener {
val spiritTrees = intArrayOf(1317,1293,1294)
val spiritTrees = intArrayOf(1317,1293,1294,8355)
override fun defineListeners() {
on(spiritTrees, IntType.SCENERY, "talk-to"){ player, _ ->
@ -39,7 +36,11 @@ class GnomeSpiritTreeTeleportDialogue: DialogueFile() {
Location(2542, 3170, 0),
Location(2461, 3444, 0),
Location(2556, 3259, 0),
Location(3184, 3508, 0)
Location(3184, 3508, 0),
Location(3060, 3256, 0), //Port Sarim
Location(2613, 3856, 0), //Etceteria
Location(2800, 3203, 0) //Brimhaven
)
private val ANIMATIONS = arrayOf(Animation(7082), Animation(7084))
@ -86,6 +87,15 @@ class GnomeSpiritTreeTeleportDialogue: DialogueFile() {
stage = END_DIALOGUE
return
}
var plantedSpiritTreeLocation = when {
getVarbit(player!!, 720) == 20 -> "Port Sarim"
getVarbit(player!!, 722) == 20 -> "Etceteria"
getVarbit(player!!, 724) == 20 -> "Brimhaven"
else -> null
//There should never be a case where more than one spirit tree is planted.
}
if(plantedSpiritTreeLocation == null) {
when (stage) {
0 -> interpreter!!.sendOptions(
"Where would you like to go?",
@ -100,6 +110,29 @@ class GnomeSpiritTreeTeleportDialogue: DialogueFile() {
3 -> sendTeleport(player!!, LOCATIONS[2])
4 -> sendTeleport(player!!, LOCATIONS[3])
}
}
}
else when (stage) {
0 -> interpreter!!.sendOptions(
"Where would you like to go?",
"Tree Gnome Village",
"Tree Gnome Stronghold",
"Battlefield of Khazard",
"Grand Exchange",
plantedSpiritTreeLocation
).also { stage++ }
1 -> when (buttonID) {
1 -> sendTeleport(player!!, LOCATIONS[0])
2 -> sendTeleport(player!!, LOCATIONS[1])
3 -> sendTeleport(player!!, LOCATIONS[2])
4 -> sendTeleport(player!!, LOCATIONS[3])
5 -> when (plantedSpiritTreeLocation) {
"Port Sarim" -> sendTeleport(player!!,LOCATIONS[4])
"Etceteria" -> sendTeleport(player!!,LOCATIONS[5])
"Brimhaven" -> sendTeleport(player!!,LOCATIONS[6])
else -> stage = END_DIALOGUE
}
}
}
}
}

View file

@ -0,0 +1,18 @@
package content.minigame.barbassault
import core.api.MapArea
import core.api.getRegionBorders
import core.game.node.entity.Entity
import core.game.world.map.zone.ZoneBorders
import core.game.world.map.zone.ZoneType
class BarbAssaultArea : MapArea {
override fun defineAreaBorders(): Array<ZoneBorders> {
return arrayOf(getRegionBorders(7509))
}
override fun areaEnter(entity: Entity) {
zone.zoneType = ZoneType.BARBARIAN_ASSAULT.id
super.areaEnter(entity)
}
}

View file

@ -7,6 +7,7 @@ import core.game.node.entity.player.Player
import core.game.node.item.Item
import core.game.world.map.Location
import core.game.world.map.zone.ZoneBorders
import core.game.world.map.zone.ZoneType
import core.tools.Log
import core.tools.ticksPerMinute
import org.rs09.consts.Components
@ -70,6 +71,7 @@ class CastleWarsGameArea : CastleWarsArea(), TickListener {
override fun areaEnter(entity: Entity) {
val player = entity as? Player ?: return
super.areaEnter(player)
zone.zoneType = ZoneType.CASTLE_WARS.id
registerTimer (player, spawnTimer("teleblock", (CastleWars.gameTimeMinutes)*60*2))
if (saradominPlayers.contains(player)) {

View file

@ -0,0 +1,18 @@
package content.minigame.troublebrewing
import core.api.MapArea
import core.api.getRegionBorders
import core.game.node.entity.Entity
import core.game.world.map.zone.ZoneBorders
import core.game.world.map.zone.ZoneType
class TroubleBrewingArea : MapArea {
override fun defineAreaBorders(): Array<ZoneBorders> {
return arrayOf(getRegionBorders(15150))
}
override fun areaEnter(entity: Entity) {
zone.zoneType = ZoneType.TROUBLE_BREWING.id
super.areaEnter(entity)
}
}

View file

@ -46,7 +46,7 @@ class ZogrePotionAndFletchingListeners : InteractionListener {
if(removeItem(player, used) && removeItem(player, with)) {
sendMessage(player, "You add the snake weed to the rogues purse solution and make Relicyms Balm.")
addItem(player, Items.RELICYMS_BALM4_4842)
addItem(player, Items.RELICYMS_BALM3_4844)
rewardXP(player, Skills.HERBLORE, 40.0)
}
return@onUseWith true

View file

@ -0,0 +1,104 @@
package content.region.kandarin.gnomestronghold.dialogue
import core.api.addItemOrDrop
import core.api.openDialogue
import core.game.dialogue.ChatAnim
import core.game.dialogue.DialogueLabeller
import core.game.dialogue.DialoguePlugin
import core.game.node.entity.player.Player
import core.game.node.item.Item
import core.plugin.Initializable
import org.rs09.consts.Items
import org.rs09.consts.NPCs
/**
* Handled the dialogue for the Gnome Woman NPCs in the Tree Gnome Stronghold.
* @author Broseki
*/
@Initializable
class GnomeWomanDialogue (player: Player? = null) : DialoguePlugin(player) {
override fun newInstance(player: Player?): DialoguePlugin {
return GnomeWomanDialogue(player)
}
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
// Pick a random number between 0 - 5 to determine the dialogue tree to use
val randomDialogue = (0..5).random()
when (randomDialogue) {
0 -> openDialogue(player, GnomeWomanDialogueFile0(), npc)
1 -> openDialogue(player, GnomeWomanDialogueFile1(), npc)
2 -> openDialogue(player, GnomeWomanDialogueFile2(), npc)
3 -> openDialogue(player, GnomeWomanDialogueFile3(), npc)
4 -> openDialogue(player, GnomeWomanDialogueFile4(), npc)
else -> openDialogue(player, GnomeWomanDialogueFile5(), npc)
}
return false
}
override fun getIds(): IntArray {
return intArrayOf(NPCs.GNOME_WOMAN_168, NPCs.GNOME_WOMAN_169)
}
}
class GnomeWomanDialogueFile0 : DialogueLabeller() {
override fun addConversation() {
player(ChatAnim.FRIENDLY, "Hello.")
npc(ChatAnim.OLD_HAPPY, "Hello adventurer. Here are some wise words:")
player(ChatAnim.FRIENDLY, "OK.")
npc(ChatAnim.OLD_CALM_TALK1, "Happiness is inward and not outward. So it does not depend on what we have but on what we are!")
}
}
class GnomeWomanDialogueFile1 : DialogueLabeller() {
override fun addConversation() {
player(ChatAnim.FRIENDLY, "Hello.")
npc(ChatAnim.OLD_HAPPY, "Hi. I've never seen so many humans in my life.")
player(ChatAnim.LAUGH, "I've never seen so many gnomes!")
npc(ChatAnim.OLD_LAUGH1, "So we're both learning.")
}
}
class GnomeWomanDialogueFile2 : DialogueLabeller() {
override fun addConversation() {
player(ChatAnim.FRIENDLY, "Hello.")
npc(ChatAnim.OLD_HAPPY, "Hello traveller. Are you eating properly? You look tired.")
player(ChatAnim.FRIENDLY, "I think so.")
npc(ChatAnim.OLD_CALM_TALK1, "Here, get this worm down you. It'll do you the world of good.")
item(Item(Items.KING_WORM_2162), "The gnome gives you a worm.")
exec { player, npc ->
addItemOrDrop(player, Items.KING_WORM_2162)
}
player(ChatAnim.HAPPY, "Thanks!")
}
}
class GnomeWomanDialogueFile3 : DialogueLabeller() {
override fun addConversation() {
player(ChatAnim.FRIENDLY, "Hello.")
npc(ChatAnim.OLD_HAPPY, "Well good day to you kind sir. Are you new to these parts?")
player(ChatAnim.FRIENDLY
, "Kind of.")
npc(ChatAnim.OLD_HAPPY, "Well if you're looking for a good night out: Blurberry's cocktail bar is great!")
}
}
class GnomeWomanDialogueFile4 : DialogueLabeller() {
override fun addConversation() {
player(ChatAnim.FRIENDLY, "Hello.")
npc(ChatAnim.OLD_CALM_TALK1, "Some people grumble because roses have thorns. I'm thankful that thorns have roses!")
player(ChatAnim.HAPPY, "Good attitude!")
}
}
class GnomeWomanDialogueFile5 : DialogueLabeller() {
override fun addConversation() {
player(ChatAnim.FRIENDLY, "Hello.")
player(ChatAnim.FRIENDLY, "How are you?")
npc(ChatAnim.OLD_HAPPY, "Not bad, a little worn out.")
player(ChatAnim.FRIENDLY, "Maybe you should have a lie down.")
npc(ChatAnim.OLD_HAPPY, "With three kids to feed I've no time for naps!")
player(ChatAnim.HAPPY, "Sounds like hard work!")
npc(ChatAnim.OLD_HAPPY, "It is but they're worth it.")
}
}

View file

@ -1,37 +1,41 @@
package content.region.kandarin.seers.dialogue
import core.Util
import core.game.dialogue.DialoguePlugin
import core.game.node.entity.player.Player
import core.game.node.entity.player.link.diary.DiaryType
import core.game.node.entity.player.link.diary.AchievementDiary
import core.game.node.item.Item
import core.plugin.Initializable
import org.rs09.consts.Items
import core.ServerStore
import core.ServerStore.Companion.getBoolean
import org.json.simple.JSONObject
@Initializable
class GeoffreyDialogue(player: Player? = null) : DialoguePlugin(player) {
override fun open(vararg args: Any?): Boolean {
val diary = player.achievementDiaryManager.getDiary(DiaryType.SEERS_VILLAGE)
if (diary.levelRewarded.any()) {
//determine reward level that has been claimed
var gotoStage = 0
//want the highest value, so this is checked hardest->easiest
if (AchievementDiary.hasClaimedLevelRewards(player,DiaryType.SEERS_VILLAGE,2)) {
gotoStage = 102
}
else if (AchievementDiary.hasClaimedLevelRewards(player,DiaryType.SEERS_VILLAGE,1)) {
gotoStage = 101
}
else if (AchievementDiary.hasClaimedLevelRewards(player,DiaryType.SEERS_VILLAGE,0)) {
gotoStage = 100
}
//give reward, or proceed to normal dialogue
if (gotoStage != 0) {
player("Hello there. Are you Geoff-erm-Flax? I've been told that", "you'll give me some flax.")
// If 1 day has not passed since last flax reward
if (player.getAttribute("diary:seers:flax-timer", 0) > System.currentTimeMillis()) {
stage = 98
return true
}
// If player cannot receive flax reward
if (!player.inventory.hasSpaceFor(Item(Items.FLAX_1780, 1))) {
stage = 99
return true
}
// Determine flax reward by seers diary reward status
when (diary.reward) {
-1 -> stage = 999
0 -> stage = 100
1 -> stage = 101
2 -> stage = 102
}
} else {
//Already claimed flax else no room else give correct reward
stage = if (getStoreFile().getBoolean(player.username.lowercase())) { 98 }
else if (!player.inventory.hasSpaceFor(Item(Items.FLAX_1780, 1))) { 99 }
else { gotoStage }
}
//If the diary has not been completed
else {
player("Hello there. You look busy.")
stage = 0
}
@ -46,7 +50,7 @@ class GeoffreyDialogue(player: Player? = null) : DialoguePlugin(player) {
when (stage) {
999 -> end()
0 -> npc("Yes, I am very busy. Picking GLORIOUS flax.", "The GLORIOUS flax won't pick itself. So I pick it.", "I pick it all day long.").also { stage++ }
1 -> player("Wow, all that flax must really mount up. What do you do with it all?").also { stage++ }
1 -> player("Wow, all that flax must really mount up.", "What do you do with it all?").also { stage++ }
2 -> npc("I give it away! I love picking the GLORIOUS flax,", "but, if I let it all mount up, I wouldn't have any", "room for more GLORIOUS flax.").also { stage++ }
3 -> player("So, you're just picking the flax for fun? You must", "really like flax.").also { stage++ }
4 -> npc("'Like' the flax? I don't just 'like' flax. The", "GLORIOUS flax is my calling, my reason to live.", "I just love the feeling of it in my hands!").also { stage++ }
@ -55,7 +59,7 @@ class GeoffreyDialogue(player: Player? = null) : DialoguePlugin(player) {
7 -> player("I know this area! It's, erm, Seers' Village. There's", "a pub and, er, a bank.").also { stage++ }
8 -> npc("Pah! You call that local knowledge? Perhaps if you", "were wearing some kind of item from one of the", "seers, I might trust you.").also { stage = 999 }
98 -> npc("I've already given you your GLORIOUS flax", "for the day. Come back tomorrow.").also { stage = 999 } // TODO find accurate dialogue
98 -> npc("Don't be greedy. Other people want GLORIOUS flax too.", "You can have some more tomorrow.").also { stage = 999 } // TODO find accurate dialogue, no source found yet, so I'm using the modern RS3 dialogue from wiki source (https://runescape.wiki/w/Transcript:Geoffrey)
99 -> npc("Yes, but your inventory is full. Come back", "when you have some space for GLORIOUS flax.").also { stage = 999 } // TODO find accurate dialogue
100 -> {rewardFlax(30, "Yes. The seers have instructed me to give you an", "allowance of 30 GLORIOUS flax a day. I'm not going", "to argue with them, so here you go.")} // TODO find accurate dialogue
101 -> {rewardFlax(60, "Yes. Stankers has instructed me to give you an", "allowance of 60 GLORIOUS flax a day. I'm not going", "to argue with a dwarf, so here you go.")} // TODO find accurate dialogue
@ -67,7 +71,7 @@ class GeoffreyDialogue(player: Player? = null) : DialoguePlugin(player) {
fun rewardFlax(n: Int, vararg messages: String): Unit {
npc(*messages)
player.inventory.add(Item(Items.FLAX_1780, n))
player.setAttribute("/save:diary:seers:flax-timer", Util.nextMidnight(System.currentTimeMillis()))
getStoreFile()[player.username.toLowerCase()] = true
stage = 999
}
@ -75,4 +79,8 @@ class GeoffreyDialogue(player: Player? = null) : DialoguePlugin(player) {
return intArrayOf(8590)
}
}
fun getStoreFile(): JSONObject {
return ServerStore.getArchive("daily-seers-flax")
}
}

View file

@ -9,6 +9,7 @@ import core.game.diary.DiaryLevel
import core.game.event.*
import core.game.node.entity.player.Player
import core.game.node.entity.player.link.diary.DiaryType
import core.game.node.entity.player.link.prayer.PrayerType
import core.game.node.item.Item
import core.game.world.map.Location
import core.game.world.map.zone.ZoneBorders
@ -30,6 +31,7 @@ class SeersVillageAchievementDiary : DiaryEventHookBase(DiaryType.SEERS_VILLAGE)
private val SEERS_VILLAGE_AREA = ZoneBorders(2687, 3455, 2742, 3507)
private val SEERS_BANK_AREA = ZoneBorders(2721, 3490, 2730, 3493)
private val SEERS_COAL_TRUCKS_AREA = ZoneBorders(2690, 3502, 2699, 3508)
private val SEERS_COURTHOUSE_AREA = ZoneBorders(2732, 3467, 2739, 3471)
private val RANGING_GUILD_LOCATION = Location(2657, 3439)
@ -352,4 +354,14 @@ class SeersVillageAchievementDiary : DiaryEventHookBase(DiaryType.SEERS_VILLAGE)
}
}
}
override fun onAreaVisited(player: Player) {
if (inBorders(player, SEERS_COURTHOUSE_AREA) && player.prayer.equals(PrayerType.PIETY)) {
finishTask(
player,
DiaryLevel.HARD,
HardTasks.ENTER_SEERS_COURTHOUSE_WITH_PIETY
)
}
}
}

View file

@ -318,6 +318,9 @@ class ServerConstants {
@JvmField
var NEW_PLAYER_ANNOUNCEMENT = true
@JvmField
var INAUTHENTIC_CANDLELIGHT_RANDOM = false
@JvmField
var HOLIDAY_EVENT_RANDOMS = true

View file

@ -1930,7 +1930,7 @@ fun runTask(entity: Entity, delay: Int = 0, repeatTimes: Int = 1, task: () -> Un
entity.pulseManager.run(object : Pulse(delay) {
override fun pulse(): Boolean {
task.invoke()
return --cycles == 0
return --cycles <= 0
}
})
}

View file

@ -1544,27 +1544,6 @@ public class ItemDefinition extends Definition<Item> {
*/
private static final String[] BONUS_NAMES = { "Stab: ", "Slash: ", "Crush: ", "Magic: ", "Ranged: ", "Stab: ", "Slash: ", "Crush: ", "Magic: ", "Ranged: ", "Summoning: ", "Strength: ", "Prayer: " };
/**
* Updates the equipment stats interface.
* @param player The player to update for.
*/
public static void statsUpdate(Player player) {
if (!player.getAttribute("equip_stats_open", false)) {
return;
}
int index = 0;
int[] bonuses = player.getProperties().getBonuses();
for (int i = 36; i < 50; i++) {
if (i == 47) {
continue;
}
int bonus = bonuses[index];
String bonusValue = bonus > -1 ? ("+" + bonus) : Integer.toString(bonus);
player.getPacketDispatch().sendString(BONUS_NAMES[index++] + bonusValue, 667, i);
}
player.getPacketDispatch().sendString("Attack bonus", 667, 34);
}
/**
* Checks if it has a plugin.
* @return {@code True} if so.

View file

@ -16,6 +16,7 @@ import core.plugin.Plugin;
import org.jetbrains.annotations.Nullable;
import core.game.interaction.InteractionListeners;
import core.game.system.config.ItemConfigParser;
import org.rs09.consts.Components;
import java.util.ArrayList;
@ -303,11 +304,11 @@ public final class EquipmentContainer extends Container {
player.removeAttribute("dfs_spec");
player.getProperties().getCombatPulse().setHandler(null);
if (!player.getSettings().isSpecialToggled()) {
setVarp(player, 301, 0);
setVarp(player, 301, 0);
}
}
player.getAppearance().setAnimations();
player.updateAppearance();
player.updateAppearance();
player.getSettings().updateWeight();
updateBonuses(player);
}
@ -349,7 +350,9 @@ public final class EquipmentContainer extends Container {
bonuses[10] += increase;
}
player.getProperties().setBonuses(bonuses);
update(player);
if (player.getInterfaceManager().hasMainComponent(Components.EQUIP_SCREEN2_667)) {
update(player);
}
}
/**
@ -357,9 +360,6 @@ public final class EquipmentContainer extends Container {
* @param player The player to update for.
*/
public static void update(Player player) {
if (!player.getInterfaceManager().hasMainComponent(667)) {
return;
}
int index = 0;
int[] bonuses = player.getProperties().getBonuses();
for (int i = 36; i < 50; i++) {
@ -370,6 +370,7 @@ public final class EquipmentContainer extends Container {
String bonusValue = bonus > -1 ? ("+" + bonus) : Integer.toString(bonus);
player.getPacketDispatch().sendString(BONUS_NAMES[index++] + bonusValue, 667, i);
}
player.getSettings().updateWeight();
player.getPacketDispatch().sendString("Attack bonus", 667, 34);
}
}

View file

@ -1,6 +1,5 @@
package core.game.node.entity.player.info.login;
import core.game.component.CloseEvent;
import core.game.component.Component;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.emote.Emotes;
@ -48,22 +47,17 @@ public final class LoginConfiguration {
*/
private static final Component LOBBY_PANE = new Component(549);
/**
* The lobby interface component.
*/
private static final Component LOBBY_INTERFACE = new Component(378);
/**
* The lobby message of the week models & constant to be set for auto selecting the models
*/
private static final int[] MESSAGE_MODEL = {15, 16, 17, 18, 19, 20, 21, 22, 23, 405, 447, 622, 623, 679, 715, 800};
private static int messModel;
/**
* The lobby interface close event.
*/
private static final Component LOBBY_INTERFACE = new Component(378).setCloseEvent(new CloseEvent() {
@Override
public boolean close(Player player, Component c) {
return player.getLocks().isLocked("login");
}
});
/**
* Constructs a new {@Code LoginConfiguration} {@Code Object}
*/
@ -102,25 +96,25 @@ public final class LoginConfiguration {
}
}
Repository.getLobbyPlayers().add(player);
player.getPacketDispatch().sendString(getLastLogin(player), 378, 116);
player.getPacketDispatch().sendString("Welcome to " + GameWorld.getSettings().getName(), 378, 115);
player.getPacketDispatch().sendString(" ", 378, 37);
player.getPacketDispatch().sendString("Want to stay up to date with the latest news and updates? Join our <br>discord by using the link below!", 378, 38);
player.getPacketDispatch().sendString(" ", 378, 39);
player.getPacketDispatch().sendString("Discord Invite", 378, 14);
player.getPacketDispatch().sendString("Discord Invite", 378, 129);
player.getPacketDispatch().sendString("Credits", 378, 94);
player.getPacketDispatch().sendString(player.getDetails().getCredits() + "", 378, 96);
player.getPacketDispatch().sendString(" ", 378, 229);
player.getPacketDispatch().sendString("Want to contribute to " + ServerConstants.SERVER_NAME + "? <br>Visit the GitLab using the link below!", 378, 230);
player.getPacketDispatch().sendString(" ", 378, 231);
player.getPacketDispatch().sendString("Github", 378, 240);
player.getPacketDispatch().sendString(GameWorld.getSettings().getMessage_string(), messModel, getMessageChild(messModel));
player.getPacketDispatch().sendString("You can gain more credits by voting, reporting bugs and various other methods of contribution.", 378, 93);
setInterfaceText(player, "Welcome to " + ServerConstants.SERVER_NAME, 378, 115);
setInterfaceText(player, getLastLogin(player), 378, 116);
setInterfaceText(player, "", 378, 37);
setInterfaceText(player, "Want to stay up to date with the latest news and updates? Join our discord by using the link on our website!", 378, 38);
setInterfaceText(player, "", 378, 39);
setInterfaceText(player, "Discord Invite", 378, 14);
setInterfaceText(player, "Discord Invite", 378, 129);
setInterfaceText(player, "You can gain more credits by reporting bugs and various other methods of contribution.", 378, 93);
setInterfaceText(player, player.getDetails().getCredits() + "", 378, 96);
setInterfaceText(player, "Credits", 378, 94);
setInterfaceText(player, "", 378, 229);
setInterfaceText(player, "Want to contribute to " + ServerConstants.SERVER_NAME + "? Visit the GitLab using the link on our website!", 378, 230);
setInterfaceText(player, "", 378, 231);
setInterfaceText(player, "Github", 378, 240);
setInterfaceText(player, GameWorld.getSettings().getMessage_string(), messModel, getMessageChild(messModel));
player.getInterfaceManager().openWindowsPane(LOBBY_PANE);
player.getInterfaceManager().setOpened(LOBBY_INTERFACE);
PacketRepository.send(Interface.class, new InterfaceContext(player, 549, 2, 378, true));
PacketRepository.send(Interface.class, new InterfaceContext(player, 549, 3, messModel, true));//UPDATE `configs` SET `value`=FLOOR(RAND()*(25-10)+10) WHERE key_="messageInterface"
PacketRepository.send(Interface.class, new InterfaceContext(player, LOBBY_PANE.getId(), 2, 378, true));
PacketRepository.send(Interface.class, new InterfaceContext(player, LOBBY_PANE.getId(), 3, messModel, true));//UPDATE `configs` SET `value`=FLOOR(RAND()*(25-10)+10) WHERE key_="messageInterface"
player.getDetails().setLastLogin(System.currentTimeMillis());
}
@ -168,12 +162,11 @@ public final class LoginConfiguration {
// 1050 is checked client-side for making piety/chivalry disallowed sfx, likely due to the minigame requirement.
// Set it here unconditionally until the minigame is implemented.
setVarbit(player, 3909, 8, false);
if (hasRequirement(player, Quests.KINGS_RANSOM, false)) {
setVarbit(player, 3909, 8, false);
}
if(ServerConstants.RULES_AND_INFO_ENABLED)
RulesAndInfo.openFor(player);
/*if (GameWorld.getSettings().isPvp()) {
player.getPacketDispatch().sendString("", 226, 1);
}*/
/*if (TutorialSession.getExtension(player).getStage() != 73) {
TutorialStage.load(player, TutorialSession.getExtension(player).getStage(), true);
}*/
@ -206,21 +199,14 @@ public final class LoginConfiguration {
* @param player the player. Fullscreen mode Object id:
*/
public static final void welcome(final Player player) {
if (GameWorld.getSettings().isPvp()) {
player.getPacketDispatch().sendString("", 226, 0);
}
if (player.isArtificial()) {
return;
}
player.getPacketDispatch().sendMessage("Welcome to " + GameWorld.getSettings().getName() + ".");
//player.getPacketDispatch().sendMessage("You are currently playing in beta version 1.2");
player.getPacketDispatch().sendMessage("Welcome to " + ServerConstants.SERVER_NAME + ".");
if (player.getDetails().isMuted()) {
player.getPacketDispatch().sendMessage("You are muted.");
player.getPacketDispatch().sendMessage("To prevent further mutes please read the rules.");
}
// ResourceAIPManager.get().load(player);
// ResourceAIPManager.get().save(player);
}
/**
@ -240,7 +226,8 @@ public final class LoginConfiguration {
player.getPacketDispatch().sendRunEnergy();
player.getFamiliarManager().login();
player.getInterfaceManager().openDefaultTabs();
player.getPacketDispatch().sendString("Friends List - World " + GameWorld.getSettings().getWorldId(), 550, 3);
setInterfaceText(player, "Friends List - " + ServerConstants.SERVER_NAME + " " + GameWorld.getSettings().getWorldId(), 550, 3);
setInterfaceText(player, "When you have finished playing " + ServerConstants.SERVER_NAME + ", always use the button below to logout safely.", 182, 0);
player.getQuestRepository().syncronizeTab(player);
player.getInterfaceManager().close();
player.getEmoteManager().refresh();
@ -260,11 +247,11 @@ public final class LoginConfiguration {
return 8;
} else if (interfaceId == 16) {
return 6;
} else if (interfaceId == 17 || interfaceId == 15 || interfaceId == 18 || interfaceId == 19 || interfaceId == 21 || interfaceId == 22 || interfaceId == 447 || interfaceId == 405) {
return 4;
} else if (interfaceId == 20 || interfaceId == 623) {
return 5;
} else if (interfaceId == 23 || interfaceId == 800) {
} else if (interfaceId == 15 || interfaceId == 18 || interfaceId == 19 || interfaceId == 21 || interfaceId == 22 || interfaceId == 447 || interfaceId == 405) {
return 4;
} else if (interfaceId == 17 || interfaceId == 23 || interfaceId == 800) {
return 3;
} else if (interfaceId == 715) {
return 2;
@ -289,12 +276,8 @@ public final class LoginConfiguration {
* @return the last login.
*/
public static String getLastLogin(Player player) {
String lastIp = player.getDetails().accountInfo.getLastUsedIp();
if (lastIp.equals("")) {
lastIp = player.getDetails().getIpAddress();
}
player.getDetails().accountInfo.setLastUsedIp(player.getDetails().getIpAddress());
String string = "You last logged in @timeAgo from: " + lastIp;
player.getPacketDispatch().sendLastLoginInfo();
String string = "You last logged in @timeAgo from:";
long time = player.getDetails().getLastLogin();
Date lastLogin = new Date(time);
Date current = new Date();

View file

@ -3,7 +3,6 @@ package core.game.node.entity.player.link;
import core.game.node.entity.player.Player;
import core.game.node.scenery.Scenery;
import core.tools.Log;
import core.tools.SystemLogger;
import core.game.system.task.Pulse;
import core.game.world.GameWorld;
import core.game.world.map.Location;
@ -431,8 +430,11 @@ public final class PacketDispatch {
PacketRepository.send(CSConfigPacket.class, new CSConfigContext(player, id, value, type, params));
}
public void resetInterface(int id)
{
public void resetInterface(int id) {
PacketRepository.send(ResetInterface.class, new InterfaceContext(player, 0, 0, id, false));
}
public void sendLastLoginInfo() {
PacketRepository.send(LastLoginInfo.class, new PlayerContext(player));
}
}

View file

@ -4,9 +4,11 @@ import core.game.component.Component;
import core.game.node.entity.combat.spell.MagicSpell;
import core.game.node.entity.player.Player;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import static core.api.ContentAPIKt.setVarbit;
/**
* Represents a managing class of a players spell book.
@ -15,7 +17,7 @@ import java.util.Map;
public final class SpellBookManager {
/**
* Represents the current interface if of the spellbook.
* Represents the current interface if of the spell book.
*/
private int spellBook = SpellBook.MODERN.getInterfaceId();
@ -23,25 +25,26 @@ public final class SpellBookManager {
* Constructs a new {@code SpellBookManager} {@code Object}.
*/
public SpellBookManager() {
/**
/*
* empty.
*/
}
/**
* Sets the spell book.
* @param book
* @param book the spell book.
*/
public void setSpellBook(SpellBook book) {
this.spellBook = book.getInterfaceId();
}
/**
* Updates the
* @param player
* Updates the spell book.
* @param player the player.
*/
public void update(Player player) {
player.getInterfaceManager().openTab(new Component(SpellBook.forInterface(this.spellBook).getInterfaceId()));
player.getInterfaceManager().openTab(new Component(spellBook));
setVarbit(player, 357, Objects.requireNonNull(SpellBook.forInterface(spellBook)).ordinal());
}
/**
@ -53,7 +56,7 @@ public final class SpellBookManager {
}
/**
* Represents a characters spellbook.
* Represents a characters spell book.
* @author 'Vexia
* @author Emperor
*/

View file

@ -206,7 +206,7 @@ public class AchievementDiary {
}
if(complete){
completedLevels.add(level);
} else if(completedLevels.contains(level)) completedLevels.remove(level);
} else if(completedLevels.contains(level)) completedLevels.remove((Object) level);
}
}

View file

@ -298,7 +298,7 @@ public enum Emotes {
}
/**
* Handles the reward button for an emote.
* Handles the button for an emote.
*
* @param player the player.
* @param buttonId the button id.

View file

@ -1,5 +1,6 @@
package core.game.node.entity.player.link.prayer;
import content.data.Quests;
import core.game.node.entity.player.link.diary.DiaryType;
import core.game.node.entity.skill.SkillBonus;
import core.game.node.entity.skill.Skills;
@ -221,11 +222,20 @@ public enum PrayerType {
* @return <code>True</code> if it is permitted.
*/
public boolean permitted(final Player player) {
if (player.getSkills().getStaticLevel(Skills.PRAYER) < getLevel() || player.getSkills().getStaticLevel(Skills.DEFENCE) < defenceReq) {
playAudio(player, Sounds.PRAYER_OFF_2673);
player.getDialogueInterpreter().sendDialogue("You need a <col=08088A>Prayer level of " + getLevel() + (player.getSkills().getStaticLevel(Skills.DEFENCE) < defenceReq ? (" and a Defence level of " + defenceReq) : "") + " to use " + StringUtils.formatDisplayName(name().toLowerCase().replace("_", " ")) + ".");
if (!hasLevelStat(player, Skills.PRAYER, level) || !hasLevelStat(player, Skills.DEFENCE, defenceReq)) {
sendDialogue(player, "You need a <col=08088A>" + (!hasLevelStat(player, Skills.PRAYER, level) ? "Prayer level of " + level + (!hasLevelStat(player, Skills.DEFENCE, defenceReq) ? " and a " : "") : "") + (!hasLevelStat(player, Skills.DEFENCE, defenceReq) ? "Defence level of " + defenceReq : "") + " to use " + StringUtils.formatDisplayName(name().toLowerCase().replace("_", " ")) + ".");
return false;
}
if (defenceReq == 65 || defenceReq == 70) {
if (!hasRequirement(player, Quests.KINGS_RANSOM)) {
return false;
} else {
if (getVarbit(player, 3909) != 8) {
setVarbit(player, 3909, 8, false);
}
}
}
return true;
}
@ -241,17 +251,12 @@ public enum PrayerType {
player.getPrayer().getActive().add(this);
iconify(player, getIcon(player, this));
playAudio(player, sound.id);
if (this == PrayerType.PIETY
&& new ZoneBorders(2732, 3467, 2739, 3471, 0).insideBorder(player)) {
player.getAchievementDiaryManager().finishTask(player, DiaryType.SEERS_VILLAGE, 2, 3);
}
player.dispatch (new PrayerActivatedEvent(this));
player.dispatch (new PrayerActivatedEvent(this));
} else {
player.getPrayer().getActive().remove(this);
playAudio(player, Sounds.CANCEL_PRAYER_2663);
findNextIcon(player);
player.dispatch (new PrayerDeactivatedEvent(this));
player.dispatch (new PrayerDeactivatedEvent(this));
}
return true;
}

View file

@ -217,6 +217,28 @@ class FunCommandSet : CommandSet(Privilege.ADMIN) {
p.graphics(Graphics(369, 0))
}
}
/**
* Toggles pet hunger to off, normal, or dev
* 0 = No hunger/growth mode (hunger/growth does not progress)
* 1 = Normal hunger/growth mode (1x speed)
* 2 = Dev hunger/growth mode (100x speed)
*/
define("petrate", Privilege.ADMIN, "petrate <lt>0-2<gt>", "Sets pet hunger and growth to off, normal, or dev."){ player, args ->
if(args.size < 2) {
notify(player, "Pet mode is currently ${player.getAttribute("petrate", 1)}")
return@define
}
val mode = args[1].toIntOrNull() ?: (-1).also { reject(player, "Please enter a valid number") }
if (mode in 0 .. 2) {
player.setAttribute("petrate", mode)
notify(player, "Setting pet mode to $mode")
}
else {
reject(player, "Only modes 0-2 are valid")
}
}
}
fun bury(player: Player){

View file

@ -160,6 +160,7 @@ object ServerConfigParser {
ServerConstants.GRAFANA_TTL_DAYS = data.getLong("integrations.grafana_log_ttl_days", 7L).toInt()
ServerConstants.BETTER_DFS = data.getBoolean("world.better_dfs", true)
ServerConstants.NEW_PLAYER_ANNOUNCEMENT = data.getBoolean("world.new_player_announcement", true)
ServerConstants.INAUTHENTIC_CANDLELIGHT_RANDOM = data.getBoolean("world.inauthentic_candlelight_random", false)
ServerConstants.HOLIDAY_EVENT_RANDOMS = data.getBoolean("world.holiday_event_randoms", true)
ServerConstants.FORCE_HALLOWEEN_EVENTS = data.getBoolean("world.force_halloween_randoms", false)
ServerConstants.FORCE_CHRISTMAS_EVENTS = data.getBoolean("world.force_christmas_randoms", false)

View file

@ -88,17 +88,16 @@ class GameSettings
/**"Lobby" interface
* The message of the week models to display
* 15 & 22 = keys & lock || 16 = fly swat || 17 = person with question marks || 18 & 447 = wise old man
* 19 = man & woman with mouth closed || 20 = man & lock & key || 21 = closed chests
* 23 = snowmen || 405 = Construction houses || 622 = Two sets of 3 people range, mage, melee
* 623 = Woodcutting || 679 = Summoning || 715 = Easter || 800 = Halloween
* Any value that isn't one listed above = random selection
* 15 & 22 = Lock w/key & keys || 16 = Fly swatters || 17 = Man & woman with question marks
* 18 & 447 = Wise old man & woman || 19 = Man with mouth zipped & woman talking || 20 = Man & lock w/key
* 21 = Chests that open & close || 23 = Christmas || 405 = Construction houses
* 622 = Two sets 3 people range, mage, melee 623 = Woodcutting || 679 = Summoning || 715 = Easter || 800 = Halloween
*/
var message_model: Int,
/**"Lobby" interface
* The message of the week text
* The "child" for writing text to these interfaces is located inside of LoginConfiguration.java
* The "child" for writing text to these interfaces is located inside LoginConfiguration.java
* method: getMessageChild
*/
var message_string: String

View file

@ -75,9 +75,10 @@ public final class PacketRepository {
OUTGOING_PACKETS.put(InstancedLocationUpdate.class, new InstancedLocationUpdate()); //
OUTGOING_PACKETS.put(CSConfigPacket.class, new CSConfigPacket()); //
OUTGOING_PACKETS.put(Varbit.class, new Varbit());
OUTGOING_PACKETS.put(ResetInterface.class, new ResetInterface());
OUTGOING_PACKETS.put(ResetInterface.class, new ResetInterface());
OUTGOING_PACKETS.put(VarcUpdate.class, new VarcUpdate());
OUTGOING_PACKETS.put(InterfaceSetAngle.class, new InterfaceSetAngle());
OUTGOING_PACKETS.put(LastLoginInfo.class, new LastLoginInfo());
}
/**
@ -105,5 +106,4 @@ public final class PacketRepository {
}
}
}
}
}

View file

@ -0,0 +1,15 @@
package core.net.packet.out
import core.net.packet.IoBuffer
import core.net.packet.OutgoingPacket
import core.net.packet.context.PlayerContext
import java.net.Inet4Address
class LastLoginInfo : OutgoingPacket<PlayerContext> {
override fun send(context: PlayerContext) {
val buffer = IoBuffer(164)
buffer.imp4(Inet4Address.getByName(context.player.details.ipAddress).hashCode())
buffer.cypherOpcode(context.player.session.isaacPair.output)
context.player.session.write(buffer)
}
}

View file

@ -99,6 +99,8 @@ better_agility_pyramid_gp = true
better_dfs = true
#new player announcement
new_player_announcement = true
#enables inauthentic candlelight random event (adds an additional normal random event)
inauthentic_candlelight_random = true
#enables holiday random events (no effect on normal random events)
holiday_event_randoms = true
#force holiday randoms (can only force one at a time)