Merge branch 2009scape:master into master

This commit is contained in:
Tooze 2026-06-20 16:36:06 +00:00
commit d1c29870bc
20 changed files with 289 additions and 192 deletions

View file

@ -18342,7 +18342,7 @@
{
"minAmount": "1",
"weight": "5.0",
"id": "5733",
"id": "12070",
"maxAmount": "1"
},
{

View file

@ -145,7 +145,7 @@
},
{
"item_id": "444",
"loc_data": "{1,3231,3739,0,250}-{1,3236,3741,0,250}-{1,3195,9821,0,150}-"
"loc_data": "{1,3231,3739,0,250}-{1,3236,3741,0,250}-{1,3195,9821,0,150}-{1,2732,3224,0,250}-"
},
{
"item_id": "480",

View file

@ -85880,6 +85880,12 @@
"id": "8065",
"name": "Pumpkin"
},
{
"id": "8077",
"name": "Pumpkin",
"examine": "What's black and white and smells of pumpkin?",
"end_height": ""
},
{
"id": "8078",
"name": "Maggie"
@ -85982,11 +85988,13 @@
},
{
"id": "8104",
"name": "Barrel"
"name": "Barrel",
"examine": "What's black and white and smells like beer?"
},
{
"id": "8105",
"name": "Bush"
"name": "Bush",
"examine": "What's black and white and down to earth?"
},
{
"id": "8106",
@ -85994,19 +86002,23 @@
},
{
"id": "8107",
"name": "Cactus"
"name": "Cactus",
"examine": "What's black and white and covered in spines?"
},
{
"id": "8108",
"name": "Crate"
"name": "Crate",
"examine": "What's black and white and on a sneaking mission?"
},
{
"id": "8109",
"name": "Rock"
"name": "Rock",
"examine": "What's black and white and looks like a rock hopper?"
},
{
"id": "8110",
"name": "Toadstool"
"name": "Toadstool",
"examine": "What's black and white and covered in mushroom?"
},
{
"id": "8111",
@ -87755,43 +87767,53 @@
},
{
"id": "8502",
"name": "Cactus"
"name": "Cactus",
"examine": "Are those spines or feathers? Either way, it looks delicious."
},
{
"id": "8503",
"name": "Cactus"
"name": "Cactus",
"examine": "Prickly, but strangely tasty-looking..."
},
{
"id": "8504",
"name": "Bush"
"name": "Bush",
"examine": "It rustles deliciously."
},
{
"id": "8505",
"name": "Toadstool"
"name": "Toadstool",
"examine": "A horrible fungus, but there is something strangely tasty about it."
},
{
"id": "8506",
"name": "Barrel"
"name": "Barrel",
"examine": "The most delicious barrel you have ever seen."
},
{
"id": "8507",
"name": "Bush"
"name": "Bush",
"examine": "Who would have thought that leaves could smell so edible?"
},
{
"id": "8508",
"name": "Crate"
"name": "Crate",
"examine": "A crate. But delicious."
},
{
"id": "8509",
"name": "Bush"
"name": "Bush",
"examine": "You feel a strange urge to pour gravy on that bush."
},
{
"id": "8510",
"name": "Rock"
"name": "Rock",
"examine": "Now that's a rock I'd try to make into soup!"
},
{
"id": "8511",
"name": "Bush"
"name": "Bush",
"examine": "Did that bush just pour sauce on itself?"
},
{
"id": "8512",

View file

@ -76,6 +76,20 @@ class MazeInterface : InteractionListener, EventHook<TickEvent>, MapArea {
WeightedItem(Items.DEFENCE_POTION2_135,1,1,1.0),
)
private val ONE_WAY_WALL = mapOf(
Location.create(2904, 4573, 0) to setOf( // Diagonal entries
Location.create(2904, 4573, 0),
Location.create(2904, 4572, 0),
Location.create(2904, 4574, 0),
),
Location.create(2906, 4586, 0) to setOf( // Diagonal entries
Location.create(2906, 4586, 0),
Location.create(2907, 4586, 0),
),
Location.create(2902, 4575, 0) to setOf(Location.create(2903, 4575, 0)),
Location.create(2924, 4583, 0) to setOf(Location.create(2923, 4583, 0)),
)
fun initMaze(player: Player) {
setAttribute(player, MAZE_ATTRIBUTE_TICKS_LEFT, 300)
setVarp(player, MAZE_TIMER_VARP, (getAttribute<Int>(player, MAZE_ATTRIBUTE_TICKS_LEFT, 0) / 3),false)
@ -190,10 +204,25 @@ class MazeInterface : InteractionListener, EventHook<TickEvent>, MapArea {
return@on true
}
on(Scenery.WALL_3628, IntType.SCENERY, "open") { player, node ->
// Door opening workaround
// Ignore 3629(WALL_3629) and 3630(WALL_3630) in handleAutowalkDoor ignoreSecondDoor
DoorActionHandler.handleAutowalkDoor(player, node as core.game.node.scenery.Scenery)
on(
intArrayOf(
Scenery.WALL_3628,
Scenery.WALL_3629,
Scenery.WALL_3630,
Scenery.WALL_3631,
Scenery.WALL_3632,
),
IntType.SCENERY,
"open"
) { player, node ->
val scenery = node as core.game.node.scenery.Scenery
if (ONE_WAY_WALL[scenery.location]?.contains(player.location) == true) {
sendDialogue(player, "I don't think that's the right way.")
} else {
DoorActionHandler.handleAutowalkDoor(player, scenery)
}
return@on true
}

View file

@ -2,6 +2,7 @@ package content.global.dialogue;
import content.global.handlers.item.book.GeneralRuleBook;
import core.game.dialogue.DialoguePlugin;
import core.game.diary.DiaryLevel;
import core.game.node.entity.npc.NPC;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.diary.DiaryType;
@ -10,6 +11,10 @@ import core.game.world.GameWorld;
import core.game.world.update.flag.context.Animation;
import core.plugin.Initializable;
import core.tools.RandomFunction;
import org.rs09.consts.NPCs;
import static content.region.misthalin.lumbridge.diary.LumbridgeAchivementDiary.Companion.BeginnerTasks.DRAYNOR_TALK_TO_TOWNCRIER_ABOUT_RULES;
import static core.api.ContentAPIKt.finishTask;
/**
* Represents the town crier dialogue plugin.
@ -127,9 +132,8 @@ public final class TownCrierDialogue extends DialoguePlugin {
return true;
}
});
// Find out about the Rules of Conduct from the Draynor<br><br>Town Crier
if (npc.getId() == 6136) {
player.getAchievementDiaryManager().finishTask(player, DiaryType.LUMBRIDGE, 0, 10);
if (npc.getId() == NPCs.TOWN_CRIER_6136) {
finishTask(player, DiaryType.LUMBRIDGE, DiaryLevel.BEGINNER, DRAYNOR_TALK_TO_TOWNCRIER_ABOUT_RULES);
}
stage = 71;
break;

View file

@ -1,90 +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 content.global.skill.crafting.TanningProduct;
import core.game.node.entity.player.Player;
import core.game.node.item.Item;
import core.plugin.Initializable;
import core.plugin.Plugin;
import kotlin.Unit;
/**
* @author Vexia
* @version 1.2
*/
@Initializable
public class TanningInterface extends ComponentPlugin {
/**
* Method used to create a new instance.
* @param arg
* @return
* @throws Throwable
*/
@Override
public Plugin<Object> newInstance(Object arg) throws Throwable {
ComponentDefinition.put(324, this);
return this;
}
@Override
public boolean handle(Player player, Component component, int opcode, int button, int slot, int itemId) {
TanningProduct def = null;
switch (button) {
case 1:
def = TanningProduct.SOFT_LEATHER;
break;
case 2:
def = TanningProduct.HARD_LEATHER;
break;
case 3:
def = TanningProduct.SNAKESKIN;
break;
case 4:
def = TanningProduct.SNAKESKIN2;
break;
case 5:
def = TanningProduct.GREEN_DHIDE;
break;
case 6:
def = TanningProduct.BLUEDHIDE;
break;
case 7:
def = TanningProduct.REDDHIDE;
break;
case 8:
def = TanningProduct.BLACKDHIDE;
break;
}
if (def == null) {
return true;
}
int amount = 0;
final TanningProduct deff = def;
switch (opcode){
case 155:
amount = 1;
break;
case 196:
amount = 5;
break;
case 124:
amount = 10;
case 199:
sendInputDialogue(player, true, "Enter the amount:", (value) -> {
TanningProduct.tan(player, (int) value, deff);
return Unit.INSTANCE;
});
break;
case 234:
amount = player.getInventory().getAmount(new Item(def.getItem(), 1));
break;
}
TanningProduct.tan(player, amount, def);
return true;
}
}

View file

@ -0,0 +1,25 @@
package content.global.handlers.iface
import content.global.skill.crafting.TanningProduct
import core.api.amountInInventory
import core.api.sendInputDialogue
import core.game.interaction.InterfaceListener
class TanningInterface : InterfaceListener {
override fun defineInterfaceListeners() {
on(324) { player, _, opcode, buttonID, _, _ ->
val product = TanningProduct.forId(buttonID)
when (opcode) {
155 -> TanningProduct.tan(player, 1, product)
196 -> TanningProduct.tan(player, 5, product)
124 -> TanningProduct.tan(player, 10, product)
199 -> sendInputDialogue(player, true, "Enter the amount:") { value ->
TanningProduct.tan(player, value as Int, product)
}
234 -> TanningProduct.tan(player, amountInInventory(player, product.item), product)
}
return@on true
}
}
}

View file

@ -127,7 +127,7 @@ private const val F_FLARES = 72
private const val F_PLAIN_TROUSERS = 70
private const val F_SHORTS = 77
private val femaleLegIDs = intArrayOf(F_FINE_SKIRT, F_FRILLED_SKIRT, F_LAYERED_SKIRT, F_LONG_NARROW_SKIRT, F_RAGGED_SKIRT, F_TATTERED_SKIRT, F_SHORT_SKIRT, F_SASHED_SKIRT, F_FITTED_SKIRT, F_TORN_TROUSERS, F_LONG_SKIRT, F_TURN_UPS, F_FLARES, F_FLARES, F_PLAIN_TROUSERS, F_SHORTS)
private val femaleLegIDs = intArrayOf(F_FINE_SKIRT, F_FRILLED_SKIRT, F_LAYERED_SKIRT, F_LONG_NARROW_SKIRT, F_RAGGED_SKIRT, F_TATTERED_SKIRT, F_SHORT_SKIRT, F_SASHED_SKIRT, F_FITTED_SKIRT, F_TORN_TROUSERS, F_LONG_SKIRT, F_TURN_UPS, F_FLARES, F_PLAIN_TROUSERS, F_SHORTS)
private val COINS = Item(995,1000)

View file

@ -155,7 +155,7 @@ public final class ThuroDialogue extends DialoguePlugin {
stage = 14;
return true;
}
player.getInventory().add(player.getSkills().getMasteredSkills() >= 1 ? ITEMS[1] : ITEMS[0]);
player.getInventory().add(player.getSkills().getMasteredSkills() > 1 ? ITEMS[1] : ITEMS[0]);
player.getInventory().add(ITEMS[2]);
interpreter.sendDialogues(npc, FacialExpression.OLD_NORMAL, "There you go! You're truley a master of Smithing.");
stage = 16;
@ -488,7 +488,7 @@ public final class ThuroDialogue extends DialoguePlugin {
stage = 14;
return true;
}
player.getInventory().add(player.getSkills().getMasteredSkills() >= 1 ? ITEMS[1] : ITEMS[0]);
player.getInventory().add(player.getSkills().getMasteredSkills() > 1 ? ITEMS[1] : ITEMS[0]);
player.getInventory().add(ITEMS[2]);
interpreter.sendDialogues(npc, FacialExpression.OLD_NORMAL, "There you go! You're truley a master of Smithing.");
stage = 16;

View file

@ -148,7 +148,11 @@ public final class PikkupstixDialogue extends DialoguePlugin {
}
break;
case 100:
npc("Welcome to my humble abode. How can I help", "you?");
if (player.getSkills().getStaticLevel(Skills.SUMMONING) == 99) {
npc(FacialExpression.AMAZED, "Why, I've never seen such raw Summoning power", "before! If anyone has the right to own a Skillcape of", "Summoning, then it is you!");
} else {
npc("Welcome to my humble abode. How can I help", "you?");
}
break;
}
return true;
@ -631,7 +635,7 @@ public final class PikkupstixDialogue extends DialoguePlugin {
switch (stage) {
case 0:
if (player.getSkills().getStaticLevel(Skills.SUMMONING) == 99) {
options("So, what's Summoning all about, then?", "Can I buy some Summoning supplies?", "Can I buy a Summoning skillcape?");
options("Yes, please sell me a Skillcape of Summoning.", "So, what's Summoning all about then?", "Can I buy some Summoning supplies?", "Please tell me about skillcapes.");
stage = 600;
} else {
options("So, what's Summoning all about, then?", "Can I buy some Summoning supplies?", "Please tell me about skillcapes.");
@ -756,35 +760,40 @@ public final class PikkupstixDialogue extends DialoguePlugin {
case 600:
switch (buttonId) {
case 1:
player(FacialExpression.ASKING, "May I buy a Skillcape of Summoning, please?");
stage = 599;
break;
case 2:
player("So, what's summoning all about, then?");
stage = 10;
break;
case 2:
case 3:
player("Can I buy some summoning supplies, please?");
stage = 34;
break;
case 3:
player("Can I buy a Skillcape of Summoning?");
stage = 599;
case 4:
player("Please tell me about skillcapes.");
stage = 400;
break;
}
break;
case 599:
npc("Why yes you can! I must warn you that they cost", "a total of 99000 coins. Do you wish to still", "buy a skillcape of Summoning?");
npc(FacialExpression.NEUTRAL, "That is a pretty tall order, even for someone with your", "skills, " + player.getUsername() + ". You'll have to pay a fee of 99000 coins", "to get the cape.");
stage = 601;
break;
case 601:
options("Yes.", "No.");
options("99000 coins? I think not!", "I'll take one!");
stage = 602;
break;
case 602:
switch (buttonId) {
case 1:
player("Yes, please.");
stage = 603;
player(FacialExpression.AMAZED, "99000 coins? I think not!");
stage = 605;
break;
case 2:
end();
player(FacialExpression.HAPPY, "I'll take one!");
stage = 603;
break;
}
break;
@ -804,13 +813,17 @@ public final class PikkupstixDialogue extends DialoguePlugin {
return true;
}
if (player.getInventory().add(ITEMS[player.getSkills().getMasteredSkills() > 1 ? 1 : 0], ITEMS[2])) {
player("There you go, enjoy!");
npc(FacialExpression.HAPPY, "Excellent! Wear that cape with pride my friend.");
stage = 604;
}
break;
case 604:
end();
break;
case 605:
npc(FacialExpression.NEUTRAL, "Well, keep that in mind the next time you ask. These", "things are not cheap to make you know!");
stage = 604;
break;
}
break;
}

View file

@ -47,11 +47,11 @@ public final class ShantayDialogue extends DialoguePlugin {
}
if (args.length == 2) {
player.getPacketDispatch().sendMessage("Shantay saunters over to talk with you.");
interpreter.sendDialogues(836, FacialExpression.HALF_GUILTY, "If you want to be let out, you have to pay a fine of", "five gold. Do you want to pay now?");
interpreter.sendDialogues(836, FacialExpression.NEUTRAL, "If you want to be let out, you have to pay a fine of", "five gold. Do you want to pay now?");
stage = 703;
return true;
}
interpreter.sendDialogues(836, FacialExpression.HALF_GUILTY, "Hello effendi, I am Shantay.");
interpreter.sendDialogues(836, FacialExpression.NEUTRAL, "Hello effendi, I am Shantay.");
stage = 0;
return true;
}
@ -60,11 +60,11 @@ public final class ShantayDialogue extends DialoguePlugin {
public boolean handle(int interfaceId, int buttonId) {
switch (stage) {
case 0:
interpreter.sendDialogues(836, FacialExpression.HALF_GUILTY, "I see you're new. Please read the billboard poster", "before going into the desert. It'll give yer details on the", "dangers you can face.");
interpreter.sendDialogues(836, FacialExpression.NEUTRAL, "I see you're new. Please read the billboard poster", "before going into the desert. It'll give yer details on the", "dangers you can face.");
stage = 1;
break;
case 1:
interpreter.sendDialogues(836, FacialExpression.HALF_GUILTY, "There is a heartbroken mother just past the gates and", "in the desert. Her name is Irena and she mourns her", "lost daughter. Such a shame.");
interpreter.sendDialogues(836, FacialExpression.NEUTRAL, "There is a heartbroken mother just past the gates and", "in the desert. Her name is Irena and she mourns her", "lost daughter. Such a shame.");
stage = 2;
break;
case 2:
@ -74,19 +74,19 @@ public final class ShantayDialogue extends DialoguePlugin {
case 3:
switch (buttonId) {
case 1:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "What is this place?");
interpreter.sendDialogues(player, FacialExpression.NEUTRAL, "What is this place?");
stage = 10;
break;
case 2:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "Can I see what you have to sell please?");
interpreter.sendDialogues(player, FacialExpression.NEUTRAL, "Can I see what you have to sell please?");
stage = 20;
break;
case 3:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "I must be going.");
interpreter.sendDialogues(player, FacialExpression.NEUTRAL, "I must be going.");
stage = 30;
break;
case 4:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "I want to buy a Shantay pass for 5 gold coins.");
interpreter.sendDialogues(player, FacialExpression.NEUTRAL, "I want to buy a Shantay pass for 5 gold coins.");
stage = 40;
break;
@ -101,7 +101,7 @@ public final class ShantayDialogue extends DialoguePlugin {
player.getInventory().add(new Item(1854));
interpreter.sendItemMessage(1854, "You purchase a Shantay Pass.");
} else {
interpreter.sendDialogues(player, null, "Sorry, I don't seem to have enough money.");
interpreter.sendDialogues(player, FacialExpression.NEUTRAL, "Sorry, I don't seem to have enough money.");
}
stage = 41;
break;
@ -109,18 +109,18 @@ public final class ShantayDialogue extends DialoguePlugin {
end();
break;
case 30:
interpreter.sendDialogues(836, FacialExpression.HALF_GUILTY, "So long...");
interpreter.sendDialogues(836, FacialExpression.NEUTRAL, "So long...");
stage = 31;
break;
case 31:
end();
break;
case 10:
interpreter.sendDialogues(836, FacialExpression.HALF_GUILTY, "This is the pass of Shantay. I guard this area with my", "men. I am responsible for keeping this pass open and", "repaired.");
interpreter.sendDialogues(836, FacialExpression.NEUTRAL, "This is the pass of Shantay. I guard this area with my", "men. I am responsible for keeping this pass open and", "repaired.");
stage = 11;
break;
case 11:
interpreter.sendDialogues(836, FacialExpression.HALF_GUILTY, "My men and I prevent outlaws from getting out of the", "desert. And we stop the inexeperienced from a dry death", "in the sands. Which would you say you were?");
interpreter.sendDialogues(836, FacialExpression.NEUTRAL, "My men and I prevent outlaws from getting out of the", "desert. And we stop the inexeperienced from a dry death", "in the sands. Which would you say you were?");
stage = 12;
break;
case 12:
@ -130,21 +130,21 @@ public final class ShantayDialogue extends DialoguePlugin {
case 13:
switch (buttonId) {
case 1:
interpreter.sendDialogues(player, null, "I am definitely an outlaw, prepare to die.");
interpreter.sendDialogues(player, FacialExpression.NEUTRAL, "I am definitely an outlaw, prepare to die.");
stage = 700;
break;
case 2:
interpreter.sendDialogues(player, null, "I am a little inexperienced.");
interpreter.sendDialogues(player, FacialExpression.NEUTRAL, "I am a little inexperienced.");
stage = 710;
break;
case 3:
interpreter.sendDialogues(player, null, "Er, neither, I'm an adventurer.");
interpreter.sendDialogues(player, FacialExpression.NEUTRAL, "Er, neither, I'm an adventurer.");
stage = 720;
break;
}
break;
case 20:
interpreter.sendDialogues(836, FacialExpression.HALF_GUILTY, "Absolutely Effendi!");
interpreter.sendDialogues(836, FacialExpression.NEUTRAL, "Absolutely Effendi!");
stage = 21;
break;
case 21:
@ -152,11 +152,11 @@ public final class ShantayDialogue extends DialoguePlugin {
npc.openShop(player);
break;
case 700:
interpreter.sendDialogues(836, null, "Ha, very funny.....");
interpreter.sendDialogues(836, FacialExpression.NEUTRAL, "Ha, very funny.....");
stage = 701;
break;
case 701:
interpreter.sendDialogues(836, null, "Guards arrest him!");
interpreter.sendDialogues(836, FacialExpression.NEUTRAL, "Guards arrest him!");
stage = 702;
break;
case 702:
@ -168,7 +168,7 @@ public final class ShantayDialogue extends DialoguePlugin {
public boolean pulse() {
player.setAttribute("/save:shantay-jail", true);
player.getProperties().setTeleportLocation(Location.create(3298, 3123, 0));
interpreter.sendDialogues(836, null, "You'll have to stay in there until you pay the fine of", "five gold pieces. Do you want to pay now?");
interpreter.sendDialogues(836, FacialExpression.NEUTRAL, "You'll have to stay in there until you pay the fine of", "five gold pieces. Do you want to pay now?");
stage = 703;
return true;
}
@ -181,11 +181,11 @@ public final class ShantayDialogue extends DialoguePlugin {
case 704:
switch (buttonId) {
case 1:
interpreter.sendDialogues(player, null, "Yes, okay.");
interpreter.sendDialogues(player, FacialExpression.NEUTRAL, "Yes, okay.");
stage = 705;
break;
case 2:
interpreter.sendDialogues(player, null, "No thanks, you're not having my money.");
interpreter.sendDialogues(player, FacialExpression.NEUTRAL, "No thanks, you're not having my money.");
stage = 800;
break;
}
@ -194,20 +194,20 @@ public final class ShantayDialogue extends DialoguePlugin {
if (player.getInventory().remove(new Item(995, 5))) {
player.getPacketDispatch().sendMessage("You hand over the five gold pieces to Shantay.");
player.getPacketDispatch().sendMessage("Shantay unlocks the door to the cell.");
interpreter.sendDialogues(836, null, "Great, Effendi, now please try to keep the peace.");
interpreter.sendDialogues(836, FacialExpression.NEUTRAL, "Great, Effendi, now please try to keep the peace.");
player.removeAttribute("shantay-jail");
stage = 822;
} else {
interpreter.sendDialogues(player, null, "Sorry, I don't seem to have enough money.");
interpreter.sendDialogues(player, FacialExpression.NEUTRAL, "Sorry, I don't seem to have enough money.");
stage = 825;
}
break;
case 800:
interpreter.sendDialogues(836, null, "You have a choice. You can either pay five gold pieces", "or... You can be transported to a maximum security", "prision in Port Sarim");
interpreter.sendDialogues(836, FacialExpression.NEUTRAL, "You have a choice. You can either pay five gold pieces", "or... You can be transported to a maximum security", "prison in Port Sarim");
stage = 801;
break;
case 801:
interpreter.sendDialogues(836, null, "Will you pay the five gold pieces?");
interpreter.sendDialogues(836, FacialExpression.NEUTRAL, "Will you pay the five gold pieces?");
stage = 802;
break;
case 802:
@ -217,17 +217,17 @@ public final class ShantayDialogue extends DialoguePlugin {
case 803:
switch (buttonId) {
case 1:
interpreter.sendDialogues(player, null, "Yes, okay.");
interpreter.sendDialogues(player, FacialExpression.NEUTRAL, "Yes, okay.");
stage = 820;
break;
case 2:
interpreter.sendDialogues(player, null, "No, do your worst!");
interpreter.sendDialogues(player, FacialExpression.NEUTRAL, "No, do your worst!");
stage = 804;
break;
}
break;
case 804:
interpreter.sendDialogues(836, null, "You are to be transported to a maximum security", "prision in Port Sarim. I hope you've learn an important", "lesson from this.");
interpreter.sendDialogues(836, FacialExpression.NEUTRAL, "You are to be transported to a maximum security", "prison in Port Sarim. I hope you've learnt an important", "lesson from this.");
stage = 805;
break;
case 805:
@ -237,17 +237,17 @@ public final class ShantayDialogue extends DialoguePlugin {
end();
break;
case 820:
interpreter.sendDialogues(836, null, "Good, I see that you have come to your senses.");
interpreter.sendDialogues(836, FacialExpression.NEUTRAL, "Good, I see that you have come to your senses.");
stage = 821;
break;
case 821:
if (player.getInventory().remove(new Item(995, 5))) {
player.getPacketDispatch().sendMessage("You hand over the five gold pieces to Shantay.");
player.getPacketDispatch().sendMessage("Shantay unlocks the door to the cell.");
interpreter.sendDialogues(836, null, "Great, Effendi, now please try to keep the peace.");
interpreter.sendDialogues(836, FacialExpression.NEUTRAL, "Great, Effendi, now please try to keep the peace.");
stage = 822;
} else {
interpreter.sendDialogues(player, null, "Sorry, I don't seem to have enough money.");
interpreter.sendDialogues(player, FacialExpression.NEUTRAL, "Sorry, I don't seem to have enough money.");
stage = 825;
}
break;
@ -258,26 +258,26 @@ public final class ShantayDialogue extends DialoguePlugin {
end();
break;
case 710:
interpreter.sendDialogues(836, null, "Can I recommend that you purchase a full waterskin", "and a knife! These items will no doubt save your life. A", "waterskin will keep water from evaporating in the desert.");
interpreter.sendDialogues(836, FacialExpression.NEUTRAL, "Can I recommend that you purchase a full waterskin", "and a knife! These items will no doubt save your life. A", "waterskin will keep water from evaporating in the desert.");
stage = 711;
break;
case 711:
interpreter.sendDialogues(836, null, "And a keen woodsman with a knife can extract juice", "from a cactus. Before you go into the desert, it's", "advisable to wear desert clothes. It's very hot in the", "desert and you'll surely cook if you wear amour.");
interpreter.sendDialogues(836, FacialExpression.NEUTRAL, "And a keen woodsman with a knife can extract juice", "from a cactus. Before you go into the desert, it's", "advisable to wear desert clothes. It's very hot in the", "desert and you'll surely cook if you wear amour.");
stage = 712;
break;
case 712:
end();
break;
case 720:
interpreter.sendDialogues(836, null, "Great, I have just the thing for you the desert adventurer.", "I sell desert clothes which will keep you cool in the heat", "of the desert. I also sell waterskins so that you won't", "die in the desert.");
interpreter.sendDialogues(836, FacialExpression.NEUTRAL, "Great, I have just the thing for you the desert adventurer.", "I sell desert clothes which will keep you cool in the heat", "of the desert. I also sell waterskins so that you won't", "die in the desert.");
stage = 721;
break;
case 721:
interpreter.sendDialogues(836, null, "A waterskin and a knife help you survive from the juice", "of a cactus. Use the chest to store your items, we'll take", "them to the bank. It's hot in the desert, you'll bake in", "all that armour.");
interpreter.sendDialogues(836, FacialExpression.NEUTRAL, "A waterskin and a knife help you survive from the juice", "of a cactus. Use the chest to store your items, we'll take", "them to the bank. It's hot in the desert, you'll bake in", "all that armour.");
stage = 722;
break;
case 722:
interpreter.sendDialogues(836, null, "To keep the pass open we ask for 5 gold pieces. And", "we give you a Shantay Pass, just ask to see what I sell", "to buy one.");
interpreter.sendDialogues(836, FacialExpression.NEUTRAL, "To keep the pass open we ask for 5 gold pieces. And", "we give you a Shantay Pass, just ask to see what I sell", "to buy one.");
stage = 723;
break;
case 723:

View file

@ -336,6 +336,12 @@ class ServerConstants {
@JvmField
var FORCE_EASTER_EVENTS = false
@JvmField
var APRIL_FOOLS_EVENT = false
@JvmField
var FORCE_APRIL_FOOLS = false
@JvmField
var RUNECRAFTING_FORMULA_REVISION = 530

View file

@ -25,6 +25,7 @@ import core.game.consumable.*
import core.game.container.impl.EquipmentContainer
import core.game.dialogue.DialogueFile
import core.game.dialogue.SkillDialogueHandler
import core.game.diary.DiaryLevel
import core.game.ge.GrandExchangeRecords
import core.game.interaction.*
import core.game.node.Node
@ -42,6 +43,7 @@ import core.game.node.entity.player.link.HintIconManager
import core.game.node.entity.player.link.IronmanMode
import core.game.node.entity.player.link.TeleportManager
import core.game.node.entity.player.link.audio.Audio
import core.game.node.entity.player.link.diary.DiaryType
import core.game.node.entity.player.link.emote.Emotes
import core.game.node.entity.player.link.prayer.PrayerType
import core.game.node.entity.player.link.quest.Quest
@ -3354,4 +3356,33 @@ fun openSingleTab(player: Player, component: Int) {
player.interfaceManager.openSingleTab(Component(component))
}
/**
* Finish an achievement diary task for the player.
* @param player the player who just finished the task.
* @param diary the diary the task belongs to.
* @param level the level of the task.
* @param task The task that was just finished.
*/
fun finishTask(player: Player, diary: DiaryType, level: DiaryLevel, task: Int) {
player.achievementDiaryManager.finishTask(player, diary, getDiaryLevelIndex(diary, level), task)
}
/**
* Resolves a [DiaryLevel] to an index for a specific diary.
* @param diary The diary the task belongs to.
* @param level The task level in the diary.
* @throws IllegalArgumentException if the level is not present in the diary.
* @return the index of the level that can be used with [core.game.node.entity.player.link.diary.AchievementDiaryManager.finishTask].
*/
fun getDiaryLevelIndex(diary: DiaryType, level: DiaryLevel): Int {
val levelName = level.name.lowercase().replaceFirstChar { c -> c.uppercase() }
val levelIndex = diary.levelNames.indexOf(levelName)
if (levelIndex < 0) {
throw IllegalArgumentException("'$levelName' was not found in diary '$diary'.")
}
return levelIndex
}
private class ContentAPI

View file

@ -180,16 +180,7 @@ abstract class DiaryEventHookBase(private val diaryType: DiaryType) : MapArea, L
)
}
private fun findIndexFor(level: DiaryLevel): Int {
val levelName = level.name.lowercase().replaceFirstChar { c -> c.uppercase() }
val levelIndex = diaryType.levelNames.indexOf(levelName)
if (levelIndex < 0) {
throw IllegalArgumentException("'$levelName' was not found in diary '$diaryType'.")
}
return levelIndex
}
private fun findIndexFor(level: DiaryLevel): Int = getDiaryLevelIndex(diaryType, level)
protected open fun onAreaVisited(player: Player) {
areaTasks.forEach {

View file

@ -1,34 +1,32 @@
package core.game.node.entity.skill;
import content.global.handlers.item.equipment.brawling_gloves.BrawlingGloves;
import content.global.handlers.item.equipment.brawling_gloves.BrawlingGlovesManager;
import content.global.skill.skillcapeperks.SkillcapePerks;
import core.ServerConstants;
import core.game.event.DynamicSkillLevelChangeEvent;
import core.game.event.XPGainEvent;
import content.global.handlers.item.equipment.brawling_gloves.BrawlingGloves;
import content.global.handlers.item.equipment.brawling_gloves.BrawlingGlovesManager;
import core.game.node.entity.Entity;
import core.game.node.entity.combat.ImpactHandler;
import core.game.node.entity.npc.NPC;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.info.PlayerMonitor;
import core.game.node.entity.player.link.request.assist.AssistSession;
import core.game.node.item.Item;
import core.game.world.GameWorld;
import core.game.world.repository.Repository;
import core.net.packet.PacketRepository;
import core.net.packet.context.SkillContext;
import core.net.packet.out.SkillLevel;
import core.plugin.CorePluginTypes.XPGainPlugins;
import kotlin.Pair;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import core.game.node.entity.player.info.PlayerMonitor;
import core.game.world.GameWorld;
import core.game.world.repository.Repository;
import core.plugin.CorePluginTypes.XPGainPlugins;
import org.rs09.consts.Items;
import org.rs09.consts.Sounds;
import java.util.ArrayList;
import static core.api.ContentAPIKt.getWorldTicks;
import static core.api.ContentAPIKt.playAudio;
import static java.lang.Math.floor;
import static java.lang.Math.max;
@ -828,7 +826,7 @@ public final class Skills {
*/
public int getMasteredSkills() {
int count = 0;
for (int i = 0; i < 23; i++) {
for (int i = 0; i < staticLevels.length; i++) {
if (getStaticLevel(i) >= 99) {
count++;
}

View file

@ -232,18 +232,35 @@ class DevelopmentCommandSet : CommandSet(Privilege.ADMIN) {
writer.close()
}
define("rolldrops", Privilege.ADMIN, "::rolldrops <lt>NPC ID<gt> <lt>AMOUNT<gt>", "Rolls the given NPC drop table AMOUNT times.") { player: Player, args: Array<String> ->
if(args.size < 2){
reject(player,"Usage: ::rolldrops npcid amount")
define(
"rolldrops",
Privilege.ADMIN,
"::rolldrops <lt>NPC ID<gt> <lt>AMOUNT<gt> [true|false]",
"Rolls the given NPC drop table AMOUNT times. Add true to persist the items in your bank."
) { player: Player, args: Array<String> ->
if (args.size < 3) {
reject(player, "Usage: ::rolldrops npcid amount [true|false]")
}
val container = player.dropLog
val npcId = args[1].toInt()
val amount = args[2].toInt()
val container = when (args.getOrNull(3)) {
"true" -> player.bank
"false", null -> {
player.dropLog.clear()
player.dropLog
}
else -> {
reject(player, "Usage: ::rolldrops npcid amount [true|false]")
return@define
}
}
container.clear()
val drops = NPCDefinition.forId(npcId).dropTables.table.roll(player, amount)
for(drop in drops) container.add(drop, false)
for (drop in drops) container.add(drop, false)
container.open(player)
}

View file

@ -164,6 +164,8 @@ object ServerConfigParser {
ServerConstants.FORCE_HALLOWEEN_EVENTS = data.getBoolean("world.force_halloween_randoms", false)
ServerConstants.FORCE_CHRISTMAS_EVENTS = data.getBoolean("world.force_christmas_randoms", false)
ServerConstants.FORCE_EASTER_EVENTS = data.getBoolean("world.force_easter_randoms", false)
ServerConstants.APRIL_FOOLS_EVENT = data.getBoolean("world.april_fools_event", false)
ServerConstants.FORCE_APRIL_FOOLS = data.getBoolean("world.force_april_fools", false)
ServerConstants.RUNECRAFTING_FORMULA_REVISION = data.getLong("world.runecrafting_formula_revision", 530).toInt()
ServerConstants.ENHANCED_DEEP_WILDERNESS = data.getBoolean("world.enhanced_deep_wilderness", false)
ServerConstants.WILDERNESS_EXCLUSIVE_LOOT = data.getBoolean("world.wilderness_exclusive_loot", false)

View file

@ -155,7 +155,7 @@ class HolidayRandoms() : PersistTimer(0, "holiday", isAuto = true), Commands {
define("forcehrevents", Privilege.ADMIN, "::forcehrevents [eventname]", "Force enable holiday random events.") { player, args ->
if (args.size == 1) {
notify(player, "Holidays: halloween, christmas")
notify(player, "Holidays: halloween, christmas, aprilfools")
return@define
}
val event = args[1]
@ -183,6 +183,12 @@ class HolidayRandoms() : PersistTimer(0, "holiday", isAuto = true), Commands {
registerTimer(p, HolidayRandoms())
}
}
"aprilfools" -> {
ServerConstants.FORCE_APRIL_FOOLS = true
for (p in Repository.players) {
notify(p, colorize("%GApril Fools is now active!"))
}
}
else -> reject(player, "Invalid event!")
}
}

View file

@ -0,0 +1,40 @@
package core.game.worldevents.holiday.aprilfools
import core.ServerConstants
import core.api.*
import core.game.node.entity.player.Player
import core.game.node.entity.player.link.emote.Emotes
import core.game.system.command.Privilege
import core.tools.colorize
import java.util.Calendar
class AprilFoolsEvent : Commands, LoginListener {
private fun isActive(): Boolean {
if (ServerConstants.FORCE_APRIL_FOOLS) return true
if (!ServerConstants.APRIL_FOOLS_EVENT) return false
val cal = Calendar.getInstance()
return cal.get(Calendar.MONTH) == Calendar.APRIL && cal.get(Calendar.DAY_OF_MONTH) == 1
}
override fun login(player: Player) {
if (!isActive()) return
sendMessage(player, colorize("Use command ::wheel to spin the new prize wheel!", "00ffff"))
}
override fun defineCommands() {
define("wheel", Privilege.STANDARD) { player, args ->
if (!isActive()) {
sendMessage(player, colorize("-->%R${args[0]}: command not found"))
return@define
}
if (getAttribute(player, "aprilfools:wheelspun", false)) {
sendMessage(player, "I'm not falling for that again.")
return@define
}
sendNews("${player.username} just tried to spin the wheel!")
sendChat(player, "I'm spinning!")
emote(player, Emotes.SPIN)
setAttribute(player, "aprilfools:wheelspun", true)
}
}
}

View file

@ -105,6 +105,9 @@ holiday_event_randoms = false
#force holiday randoms (can only force one at a time)
force_halloween_randoms = false
force_christmas_randoms = false
#enables inauthentic april fools event
april_fools_event = false
force_april_fools = false
#runecrafting formula revision (573 introduced probabilistic multiple runes, 581 extrapolated probabilistic runes past 99)
runecrafting_formula_revision = 530
#enables the enhanced deep wilderness, where the area past the members' fence applies a red skull that boosts brawler/pvp drop rates