Merge branch 'sir-renitee' into 'master'

Fully Implemented Heraldry

See merge request 2009scape/2009scape!2446
This commit is contained in:
Bishop 2026-08-01 19:12:01 +00:00
commit 8764b099e0
16 changed files with 1236 additions and 757 deletions

File diff suppressed because it is too large Load diff

View file

@ -59,7 +59,7 @@ public enum BuildHotspot {
DINING_BENCH_1(15300, BuildHotspotType.RECURSIVE, BuildingUtils.BUILD_MID_ANIM, Decoration.BENCH_WOODEN, Decoration.BENCH_OAK, Decoration.BENCH_CARVED_OAK, Decoration.BENCH_TEAK, Decoration.BENCH_CARVED_TEAK, Decoration.BENCH_MAHOGANY, Decoration.BENCH_GILDED),
DINING_BENCH_2(15299, BuildHotspotType.RECURSIVE, BuildingUtils.BUILD_MID_ANIM, Decoration.BENCH_WOODEN, Decoration.BENCH_OAK, Decoration.BENCH_CARVED_OAK, Decoration.BENCH_TEAK, Decoration.BENCH_CARVED_TEAK, Decoration.BENCH_MAHOGANY,Decoration.BENCH_GILDED),
ROPE_BELL_PULL(15304, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_HIGH_ANIM, Decoration.ROPE_PULL, Decoration.BELL_PULL, Decoration.FANCY_BELL_PULL),
WALL_DECORATION(15303, BuildHotspotType.RECURSIVE, BuildingUtils.BUILD_HIGH_ANIM, Decoration.OAK_DECORATION, Decoration.TEAK_DECORATION, Decoration.GILDED_DECORATION),
WALL_DECORATION(15303, BuildHotspotType.CREST, BuildingUtils.BUILD_HIGH_ANIM, Decoration.OAK_DECO, Decoration.TEAK_DECO, Decoration.GILDED_DECO),
/**
* Low-level Work shop hotspots.
@ -191,7 +191,7 @@ public enum BuildHotspot {
/**
* Combat room hotspots.
*/
WALL_DECORATION2(15297, BuildHotspotType.RECURSIVE, BuildingUtils.BUILD_HIGH_ANIM, Decoration.OAK_DECORATION, Decoration.TEAK_DECORATION, Decoration.GILDED_DECORATION),
WALL_DECORATION2(15297, BuildHotspotType.CREST, BuildingUtils.BUILD_HIGH_ANIM, Decoration.OAK_DECO, Decoration.TEAK_DECO, Decoration.GILDED_DECO),
STORAGE_SPACE(15296, BuildHotspotType.INDIVIDUAL, BuildingUtils.BUILD_MID_ANIM, Decoration.GLOVE_RACK, Decoration.WEAPONS_RACK, Decoration.EXTRA_WEAPONS_RACK),
CR_RING(15277, BuildHotspotType.LINKED, BuildingUtils.BUILD_MID_ANIM, Decoration.BOXING_RING, Decoration.FENCING_RING, Decoration.COMBAT_RING, Decoration.NOTHING, Decoration.NOTHING2),
CR_CORNER(15278, BuildHotspotType.LINKED, BuildingUtils.BUILD_MID_ANIM, Decoration.BOXING_RING, Decoration.FENCING_RING, Decoration.COMBAT_RING, Decoration.NOTHING, Decoration.NOTHING2),

View file

@ -276,7 +276,7 @@ public final class BuildingUtils {
}
break;
case CREST:
SceneryBuilder.replace(object, object.transform(deco.getObjectId(style) + player.getHouseManager().getCrest().ordinal()));
SceneryBuilder.replace(object, object.transform(deco.getCrestAdjustedId(style, player.getHouseManager().getCrest())));
hotspot.setDecorationIndex(decIndex);
break;
case INDIVIDUAL:
@ -341,14 +341,18 @@ public final class BuildingUtils {
HousingStyle style = player.getHouseManager().getStyle();
for (int i = 0; i < room.getHotspots().length; i++) {
Hotspot hotspot = room.getHotspots()[i];
int objectId = hotspot.getDecorationIndex() < 0 ? -1 : hotspot.getHotspot().getDecorations()[hotspot.getDecorationIndex()].getObjectId(style);
if (hotspot.getHotspot().getType() == BuildHotspotType.CREST) {
objectId += player.getHouseManager().getCrest().ordinal();
int objectId;
if (hotspot.getDecorationIndex() < 0) {
objectId = -1;
} else if (hotspot.getHotspot().getType() == BuildHotspotType.CREST) {
objectId = hotspot.getHotspot().getDecorations()[hotspot.getDecorationIndex()].getCrestAdjustedId(style, player.getHouseManager().getCrest());
} else {
objectId = hotspot.getHotspot().getDecorations()[hotspot.getDecorationIndex()].getObjectId(style);
}
if (objectId == object.getId() && hotspot.getCurrentX() == l.getChunkOffsetX() && hotspot.getCurrentY() == l.getChunkOffsetY()) {
Decoration decoration = hotspot.getHotspot().getDecorations()[hotspot.getDecorationIndex()];
player.animate(REMOVE_ANIMATION);
removeDecoration(player, region, room, hotspot, object, style);
Decoration decoration = Decoration.forObjectId(object.getId());
for (Item item : decoration.getRefundItems()) {
addItemOrDrop(player, item.getId(), item.getAmount());
}
@ -472,6 +476,14 @@ public final class BuildingUtils {
return false;
}
return true;
case ROUND_SHIELD:
case SQUARE_SHIELD:
case KITE_SHIELD:
if (player.getHouseManager().getCrest() == CrestType.NULL) {
sendDialogue(player, "You need a crest to build heraldic shields."); // Placeholder
return false;
}
return true;
default:
return true;
}

View file

@ -1,117 +0,0 @@
package content.global.skill.construction;
import core.game.node.entity.player.Player;
import org.rs09.consts.Items;
import core.game.node.entity.skill.Skills;
import content.data.Quests;
/**
* Family crest types.
*
* @author Emperor
* >ORDINAL BOUND<
*/
public enum CrestType implements CrestRequirement {
ARRAV("the Shield of Arrav symbol") { // requires Shield of Arrav
@Override
public boolean eligible(Player player) {
return player.getQuestRepository().isComplete(Quests.SHIELD_OF_ARRAV);
}
},
ASGARNIA("the symbol of Asgarnia"), // no requirements
DORGESHUUN("the Dorgeshuun brooch") { // requires The Lost Tribe
@Override
public boolean eligible(Player player) {
return player.getQuestRepository().isComplete(Quests.THE_LOST_TRIBE);
}
},
DRAGON("a dragon") { // requires Dragon Slayer
@Override
public boolean eligible(Player player) {
return player.getQuestRepository().isComplete(Quests.DRAGON_SLAYER);
}
},
FAIRY("a fairy") { // requries Lost City
@Override
public boolean eligible(Player player) {
return player.getQuestRepository().isComplete(Quests.LOST_CITY);
}
},
GUTHIX("the symbol of Guthix") { // Requires 70+ Prayer
@Override
public boolean eligible(Player player) {
return player.getSkills().hasLevel(Skills.PRAYER, 70);
}
},
HAM("the symbol of the HAM cult."), // no requirements
HORSE("a horse") { // requires Toy Horsey in inventory
@Override
public boolean eligible(Player player) {
return player.getInventory().containsAtLeastOneItem(new int[]{
Items.TOY_HORSEY_2524,
Items.TOY_HORSEY_2520,
Items.TOY_HORSEY_2526,
Items.TOY_HORSEY_2522
});
}
},
JOGRE("Jiggig"), // no requirements
KANDARIN("the symbol of Kandarin"), // no requirements
MISTHALIN("the symbol of Misthalin"), // no requirements
MONEY("a bag of money", 500000), // Costs 500k
SARADOMIN("the symbol of Saradomin") { // Requires 70+ Prayer
@Override
public boolean eligible(Player player) {
return player.getSkills().hasLevel(Skills.PRAYER, 70);
}
},
SKULL("a skull") { // requires Skulled while talking to Herald
@Override
public boolean eligible(Player player) {
return player.getSkullManager().isSkulled();
}
},
VARROCK("the symbol of Varrock"), // no requirements
ZAMORAK("the symbol of Zamorak") { // Requires 70+ Prayer
@Override
public boolean eligible(Player player) {
return player.getSkills().hasLevel(Skills.PRAYER, 70);
}
};
private String name;
private int cost;
CrestType(String name, int cost) {
this.name = name;
this.cost = cost;
}
CrestType(String name) {
this(name, 5000);
}
public String getName() {
return this.name;
}
public int getCost() {
return this.cost;
}
}
interface CrestRequirement {
default boolean eligible(Player player) {
return true;
}
}

View file

@ -0,0 +1,48 @@
package content.global.skill.construction
import content.data.Quests
import core.api.*
import core.game.node.entity.player.Player
import core.game.node.entity.skill.Skills
import org.rs09.consts.Items
/**
* Enumerates the various crests the player can purchase for the Construction skill, as well as their requirements.
* The NULL CrestType represents players who have yet to receive a crest from Sir Renitee.
* ORDINAL BOUND
* @author Bishop
*/
enum class CrestType(val crestName: String, val cost: Int = 5000, private val requirement: (Player) -> Boolean = { true }) {
ARRAV("the Shield of Arrav symbol",
requirement = { isQuestComplete(it, Quests.SHIELD_OF_ARRAV) }),
ASGARNIA("the symbol of Asgarnia"),
DORGESHUUN("the Dorgeshuun brooch",
requirement = { isQuestComplete(it, Quests.THE_LOST_TRIBE) }),
DRAGON("a dragon",
requirement = { isQuestComplete(it, Quests.DRAGON_SLAYER) }),
FAIRY("a fairy",
requirement = { isQuestComplete(it, Quests.LOST_CITY) }),
GUTHIX("the symbol of Guthix",
requirement = { hasLevelStat(it, Skills.PRAYER, 70) }),
HAM("the symbol of the HAM cult."),
HORSE("a horse",
requirement = { anyInInventory(it,Items.TOY_HORSEY_2524, Items.TOY_HORSEY_2520, Items.TOY_HORSEY_2526, Items.TOY_HORSEY_2522) }),
JOGRE("Jiggig"),
KANDARIN("the symbol of Kandarin"),
MISTHALIN("the symbol of Misthalin"),
MONEY("a bag of money",
cost = 500000),
SARADOMIN("the symbol of Saradomin",
requirement = { hasLevelStat(it, Skills.PRAYER, 70) }),
SKULL("a skull",
requirement = { it.skullManager.isSkulled }),
VARROCK("the symbol of Varrock"),
ZAMORAK("the symbol of Zamorak",
requirement = { hasLevelStat(it, Skills.PRAYER, 70) }),
NULL("no crest",
cost = 0, requirement = { false });
fun eligible(player: Player): Boolean = requirement(player)
}

View file

@ -255,7 +255,7 @@ public enum Decoration {
* Wall-mounted decorations
*/
OAK_DECORATION (13606, 8102, 16, 120, new Item[] { new Item(Items.OAK_PLANK_8778, 2) }),
TEAK_DECORATION (13606, 8103, 36, 180, new Item[] { new Item(Items.TEAK_PLANK_8780, 2) }),
TEAK_DECORATION (13608, 8103, 36, 180, new Item[] { new Item(Items.TEAK_PLANK_8780, 2) }),
GILDED_DECORATION(13607, 8104, 56, 1020, new Item[] { new Item(Items.MAHOGANY_PLANK_8782, 3), new Item(Items.GOLD_LEAF_8784, 2) }),
/**
@ -899,7 +899,13 @@ public enum Decoration {
if (h.getCurrentX() == l.getChunkOffsetX() && h.getCurrentY() == l.getChunkOffsetY()) {
if (h.getDecorationIndex() != -1) {
Decoration deco = h.getHotspot().getDecorations()[h.getDecorationIndex()];
if (deco.getObjectId(player.getHouseManager().getStyle()) == object.getId()) {
int id;
if (h.getHotspot().getType() == BuildHotspotType.CREST) {
id = deco.getCrestAdjustedId(player.getHouseManager().getStyle(), player.getHouseManager().getCrest());
} else {
id = deco.getObjectId(player.getHouseManager().getStyle());
}
if (id == object.getId()) {
return deco;
}
}
@ -964,6 +970,23 @@ public enum Decoration {
return objectId;
}
/**
* Returns the object ID adjusted for the player's crest.
* For CrestType.NULL, maps _DECO decorations to their blank _DECORATION counterparts.
* Returns -1 for shield decorations with NULL crest (no blank variant exists).
*/
public int getCrestAdjustedId(HousingStyle style, CrestType crest) {
if (crest == CrestType.NULL) {
switch (this) {
case OAK_DECO: return OAK_DECORATION.getObjectId(style);
case TEAK_DECO: return TEAK_DECORATION.getObjectId(style);
case GILDED_DECO: return GILDED_DECORATION.getObjectId(style);
default: return -1;
}
}
return getObjectId(style) + crest.ordinal();
}
/**
* Gets the level.
* @return The level.

View file

@ -86,7 +86,7 @@ public final class HouseManager {
/**
* The player's crest.
*/
private CrestType crest = CrestType.ASGARNIA;
private CrestType crest = CrestType.NULL;
/**
* Constructs a new {@code HouseManager} {@code Object}.
@ -101,6 +101,12 @@ public final class HouseManager {
public void parse(JSONObject data){
location = HouseLocation.values()[Integer.parseInt( data.get("location").toString())];
style = HousingStyle.values()[Integer.parseInt( data.get("style").toString())];
Object crestRaw = data.get("crest");
if (crestRaw != null) {
crest = CrestType.values()[Integer.parseInt(crestRaw.toString())];
} else {
crest = CrestType.ASGARNIA;
}
Object servRaw = data.get("servant");
if(servRaw != null){
servant = Servant.parse((JSONObject) servRaw);

View file

@ -0,0 +1,50 @@
package content.global.skill.construction
import content.data.Quests
import core.api.*
import core.game.node.entity.player.Player
import org.rs09.consts.Items
/**
* Enumerates the various paintings the player can purchase for the Construction skill, as well as their requirements.
* @author Bishop
*/
enum class PaintingType(val paintingId: Int, val cost: Int = 1000, private val requirement: (Player) -> Boolean = { true }) {
ARTHUR(Items.ARTHUR_PORTRAIT_7995,
requirement = { isQuestComplete(it, Quests.HOLY_GRAIL) }),
ELENA(Items.ELENA_PORTRAIT_7996,
requirement = { isQuestComplete(it, Quests.PLAGUE_CITY) }),
ALVIS(Items.KELDAGRIM_PORTRAIT_7997,
requirement = { isQuestComplete(it, Quests.THE_GIANT_DWARF) }),
MISC(Items.MISC_PORTRAIT_7998,
requirement = { isQuestComplete(it, Quests.THRONE_OF_MISCELLANIA) }),
DESERT(Items.DESERT_PAINTING_7999,
cost = 2000,
requirement = { isQuestComplete(it, Quests.THE_FEUD) && isQuestComplete(it, Quests.THE_GOLEM) &&
isQuestComplete(it, Quests.THE_TOURIST_TRAP)}),
ISAFDAR(Items.ISAFDAR_PAINTING_8000,
cost = 2000,
requirement = { isQuestComplete(it, Quests.ROVING_ELVES) }),
KARAMJA(Items.KARAMJA_PAINTING_8001,
cost = 2000,
requirement = { isQuestComplete(it, Quests.PIRATES_TREASURE) && isQuestComplete(it, Quests.SHILO_VILLAGE) &&
isQuestComplete(it, Quests.TAI_BWO_WANNAI_TRIO) }),
LUMBRIDGE(Items.LUMBRIDGE_PAINTING_8002,
cost = 2000,
requirement = { isQuestComplete(it, Quests.COOKS_ASSISTANT) && isQuestComplete(it, Quests.RUNE_MYSTERIES) &&
isQuestComplete(it, Quests.THE_RESTLESS_GHOST) }),
MORYTANIA(Items.MORYTANIA_PAINTING_8003,
cost = 2000,
requirement = { isQuestComplete(it, Quests.CREATURE_OF_FENKENSTRAIN) && isQuestComplete(it, Quests.GHOSTS_AHOY) &&
isQuestComplete(it, Quests.HAUNTED_MINE) && isQuestComplete(it, Quests.SHADES_OF_MORTTON) }),
MAP_SMALL(Items.SMALL_MAP_8004,
requirement = { getQuestPoints(it) > 50 }),
MAP_MEDIUM(Items.MEDIUM_MAP_8005,
requirement = { getQuestPoints(it) > 100 }),
MAP_LARGE(Items.LARGE_MAP_8006,
requirement = { getQuestPoints(it) > 150 });
fun eligible(player: Player): Boolean = requirement(player)
}

View file

@ -140,9 +140,15 @@ public final class Room {
Scenery object = objects[x][y];
if (object != null && object.getId() == spot.getHotspot().getObjectId(house.getStyle())) {
if (spot.getDecorationIndex() > -1 && spot.getDecorationIndex() < spot.getHotspot().getDecorations().length) {
int id = spot.getHotspot().getDecorations()[spot.getDecorationIndex()].getObjectId(house.getStyle());
int id;
if (spot.getHotspot().getType() == BuildHotspotType.CREST) {
id += house.getCrest().ordinal();
id = spot.getHotspot().getDecorations()[spot.getDecorationIndex()].getCrestAdjustedId(house.getStyle(), house.getCrest());
if (id == -1) {
spot.setDecorationIndex(-1);
continue;
}
} else {
id = spot.getHotspot().getDecorations()[spot.getDecorationIndex()].getObjectId(house.getStyle());
}
SceneryBuilder.replace(object, object.transform(id, object.getRotation(), chunk.getCurrentBase().transform(x, y, 0)));
}

View file

@ -0,0 +1,111 @@
package content.global.skill.construction.decoration.workshop
import content.global.skill.construction.CrestType
import content.global.skill.crafting.HeraldicProduct
import content.region.asgarnia.falador.dialogue.SirReniteeDialogueFile
import core.api.*
import core.game.interaction.InteractionListener
import core.game.node.entity.player.Player
import core.game.node.entity.skill.Skills
import org.rs09.consts.Animations
import org.rs09.consts.Items
import org.rs09.consts.Scenery
/**
* Handles easel type furniture in a POH, with which players may make heraldic items.
* @author Bishop
*/
class EaselListener : InteractionListener {
private val easels = intArrayOf(
Scenery.HELMET_PLUMING_STAND_13716,
Scenery.PAINTING_STAND_13717,
Scenery.BANNER_MAKING_STAND_13718
)
private fun checkRequirements(player: Player, product: HeraldicProduct) : Boolean {
when {
(!getAttribute(player, SirReniteeDialogueFile.ATTRIBUTE_CREST, false) || player.houseManager.crest == CrestType.NULL) -> {
sendDialogueLines(player, "You must speak to the chief herald of Falador before you can make", "heraldic items.") // OSRS
return false
}
(!inInventory(player, product.primaryMaterialId)) -> {
sendDialogue(player, "You need a ${product.primaryMaterialId.asItem().name.lowercase()} to make this.")
return false
}
(product.secondaryMaterialId != null && !inInventory(player, product.secondaryMaterialId)) -> {
sendDialogue(player, "You need a ${product.secondaryMaterialId.asItem().name.lowercase()} to make this.")
return false
}
(!hasLevelDyn(player, Skills.CONSTRUCTION, product.constructionReq)) -> {
sendDialogue(player, "You need a Construction level of ${product.constructionReq} to make this.")
return false
}
(!hasLevelDyn(player, Skills.CRAFTING, product.craftingReq)) -> {
sendDialogue(player, "You need a Crafting level of ${product.craftingReq} to make this.")
return false
}
else -> {
return true
}
}
}
private fun giveProduct(player: Player, product: HeraldicProduct) {
val crest = player.houseManager.crest
if (removeItem(player, product.primaryMaterialId)) {
if (product.secondaryMaterialId == null || removeItem(player, product.secondaryMaterialId)) {
addItemOrDrop(player, product.productForCrest(crest))
rewardXP(player, Skills.CRAFTING, product.craftingXp)
animate(player, Animations.HUMAN_CRAFT_POH_CREST_3654)
when (product) {
HeraldicProduct.STEEL_HELM, HeraldicProduct.RUNE_HELM ->
sendMessage(player, "You make a helmet in your colours.")
HeraldicProduct.STEEL_SHIELD, HeraldicProduct.RUNE_SHIELD ->
sendMessage(player, "You make a shield with your symbol on.")
HeraldicProduct.BANNER ->
sendMessage(player, "You make a banner with your symbol on.")
}
}
}
}
override fun defineListeners() {
on(easels, SCENERY, "use", "make-helmet") { player, node ->
val options = when (node.id) {
Scenery.HELMET_PLUMING_STAND_13716 ->
arrayOf("Plumed steel helmet", "Plumed rune helmet")
Scenery.PAINTING_STAND_13717 ->
arrayOf("Plumed steel helmet", "Plumed rune helmet", "Steel heraldic shield", "Runite heraldic shield")
Scenery.BANNER_MAKING_STAND_13718 ->
arrayOf("Plumed steel helmet", "Plumed rune helmet", "Steel heraldic shield", "Runite heraldic shield", "Heraldic banner")
else ->
return@on false
}
val buttonsToProducts = mapOf(
2 to HeraldicProduct.STEEL_HELM,
3 to HeraldicProduct.RUNE_HELM,
4 to HeraldicProduct.STEEL_SHIELD,
5 to HeraldicProduct.RUNE_SHIELD,
6 to HeraldicProduct.BANNER
)
sendDialogueOptions(player, "What do you want to make?", *options)
addDialogueAction(player) { player, button ->
if (checkRequirements(player, buttonsToProducts[button] ?: return@addDialogueAction)) {
giveProduct(player, buttonsToProducts[button] ?: return@addDialogueAction)
}
return@addDialogueAction
}
return@on true
}
onUseWith(SCENERY, Items.BOLT_OF_CLOTH_8790, Scenery.BANNER_MAKING_STAND_13718) { player, _, _ ->
if (checkRequirements(player, HeraldicProduct.BANNER)) {
giveProduct(player, HeraldicProduct.BANNER)
}
return@onUseWith true
}
}
}

View file

@ -0,0 +1,31 @@
package content.global.skill.crafting
import content.global.skill.construction.CrestType
import org.rs09.consts.Items
/**
* Enumerates the heraldic items players can craft with easels in their POHs.
* @author Bishop
*/
enum class HeraldicProduct(
val primaryMaterialId: Int,
val secondaryMaterialId: Int?,
val baseProductId: Int,
val craftingReq: Int,
val craftingXp: Double,
val constructionReq: Int = 16) {
STEEL_HELM(Items.STEEL_FULL_HELM_1157, null,
Items.STEEL_HERALDIC_HELM_8682, 38, 37.0),
RUNE_HELM(Items.RUNE_FULL_HELM_1163, null,
Items.RUNE_HERALDIC_HELM_8464, STEEL_HELM.craftingReq, STEEL_HELM.craftingXp),
STEEL_SHIELD(Items.STEEL_KITESHIELD_1193, null,
Items.STEEL_KITESHIELD_8746, 43, 40.0),
RUNE_SHIELD(Items.RUNE_KITESHIELD_1201, null,
Items.RUNE_KITESHIELD_8714, STEEL_SHIELD.craftingReq, STEEL_SHIELD.craftingXp),
BANNER(Items.BOLT_OF_CLOTH_8790, Items.PLANK_960,
Items.BANNER_8650, 48, 42.5);
fun productForCrest(crest: CrestType): Int = baseProductId + (crest.ordinal * 2)
}

View file

@ -1,469 +0,0 @@
package content.region.asgarnia.falador.dialogue;
import core.ServerConstants;
import core.Util;
import core.game.dialogue.DialoguePlugin;
import core.game.dialogue.FacialExpression;
import core.plugin.Initializable;
import org.rs09.consts.Items;
import core.game.node.entity.npc.NPC;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.diary.DiaryType;
import core.game.node.item.Item;
import core.tools.RandomFunction;
import core.game.node.entity.skill.Skills;
import content.global.skill.construction.CrestType;
/**
* Represents the dialogue to handle Sir Renitee
*
* @author afaroutdude
*/
@Initializable
public class SirReniteeDialogue extends DialoguePlugin {
/**
* Constructs a new {@code SirReniteeDialogue} {@code Object}.
*/
public SirReniteeDialogue() {
}
public SirReniteeDialogue(Player player) {
super(player);
}
@Override
public boolean open(Object... args) {
npc = (NPC) args[0];
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Hmm? What's that, young " + (player.getAppearance().isMale() ? "man" : "woman") + "? What can I do for", "you?");
stage = 0;
return true;
}
@Override
public boolean handle(int interfaceId, int buttonId) {
switch (stage) {
case 0:
interpreter.sendOptions("Select an Option", "I don't know, what can you do for me?", "Nothing, thanks");
stage = 10;
break;
case 10:
switch (buttonId) {
case 1:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "I don't know, what can you do for me?");
stage = 100;
break;
case 2:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "Nothing, thanks.");
stage = 30;
break;
}
break;
case 30:
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Mmm, well, see you some other time maybe.");
stage = 40;
break;
case 40:
end();
break;
case 100:
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Hmm, well, mmm, do you have a family crest? I keep", "track of every " + ServerConstants.SERVER_NAME + " family, you know, so I might", "be able to find yours.");
stage = 110;
break;
case 110:
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "I'm also something of an, mmm, a painter. If you've", "met any important persons or visited any nice places I", "could paint them for you.");
stage = 120;
break;
case 120:
interpreter.sendOptions("Select an Option", "Can you see if I have a family crest?", "Can I buy a painting?");
stage = 130;
break;
case 130:
switch (buttonId) {
case 1:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "Can you see if I have a family crest?");
stage = 200;
break;
case 2:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "Can I buy a painting?");
stage = 500;
break;
}
break;
case 200:
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "What is your name?");
stage = 210;
break;
case 210:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, player.getUsername() + ".");
stage = 220;
break;
case 220:
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Mmm, " + player.getUsername() + ", let me see...");
stage = 230;
break;
case 230:
if (player.getSkills().hasLevel(Skills.CONSTRUCTION, 16)) {
if (player.getAttribute("sir-renitee-assigned-crest", false)) {
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "According to my records, your crest is ", player.getHouseManager().getCrest().getName() + ".");
} else {
final int c = RandomFunction.random(4);
final CrestType[] crests = {CrestType.VARROCK, CrestType.ASGARNIA, CrestType.KANDARIN, CrestType.MISTHALIN};
final CrestType crest = crests[c];
player.getHouseManager().setCrest(crest);
player.setAttribute("/save:sir-renitee-assigned-crest", true);
String message = "that can be your";
if (crest == CrestType.VARROCK) {
message = "you can use that city's";
}
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Well, I don't think you have any noble blood,",
"but I see that your ancestors came from " + Util.enumToString(player.getHouseManager().getCrest().name()) + ",", " so " + message + " crest.");
}
if (!player.getAchievementDiaryManager().getDiary(DiaryType.FALADOR).isComplete(0,4)) {
player.getAchievementDiaryManager().getDiary(DiaryType.FALADOR).updateTask(player,0,4,true);
}
stage = 240;
} else {
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY,
"First thing's first, young " + (player.getAppearance().isMale() ? "man" : "woman") + "! There is not much point",
"in having a family crest if you cannot display it.");
stage = 235;
}
break;
case 235:
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "You should train construction until you can build a wall", "decoration in your dining room.");
stage = 40;
break;
case 240:
interpreter.sendOptions("Select an Option", "I don't like that crest. Can I have a different one?", "Thanks!");
stage = 250;
break;
case 250:
switch (buttonId) {
case 1:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "I don't like that crest. Can I have a different one?");
stage = 300;
break;
case 2:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "Thanks!");
stage = 260;
break;
}
break;
case 260:
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "You're welcome, my " + (player.getAppearance().isMale() ? "boy." : "girl."));
stage = 40;
break;
case 300:
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Mmm, very well. Changing your crest will cost", "5,000 coins.");
if (player.getInventory().getAmount(Items.COINS_995) < 5000) {
stage = 302;
} else {
stage = 305;
}
break;
case 302:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "I'll have to go and get some money then.");
stage = 40;
break;
case 305:
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "There are sixteen different symbols;", "which one would you like?");
stage = 310;
break;
case 310:
interpreter.sendOptions("Select an Option", "Shield of Arrav", "Asgarnia", "Dorgeshuun Symbol", "Dragon", "More...");
stage = 320;
break;
case 320:
switch (buttonId) {
case 1: {
CrestType c = CrestType.ARRAV;
if (c.eligible(player) && player.getInventory().getAmount(Items.COINS_995) > c.getCost()
&& player.getInventory().remove(new Item(Items.COINS_995, c.getCost()))) {
player.getHouseManager().setCrest(c);
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Ah yes, the shield that you helped to retrieve. You have", "certainly earned the right to wear its symbol.");
stage = 40;
} else {
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "[MISSING DIALOGUE - NOT ELIGIBLE]");
stage = 310;
}
break;
}
case 2: {
CrestType c = CrestType.ASGARNIA;
if (c.eligible(player) && player.getInventory().getAmount(Items.COINS_995) > c.getCost()
&& player.getInventory().remove(new Item(Items.COINS_995, c.getCost()))) {
player.getHouseManager().setCrest(c);
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Ah, splendid, splendid. There is no better symbol", "than that of our fair land!");
stage = 40;
} else {
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "[MISSING DIALOGUE - NOT ELIGIBLE]");
stage = 310;
}
break;
}
case 3: {
CrestType c = CrestType.DORGESHUUN;
if (c.eligible(player) && player.getInventory().getAmount(Items.COINS_995) > c.getCost()
&& player.getInventory().remove(new Item(Items.COINS_995, c.getCost()))) {
player.getHouseManager().setCrest(c);
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Ah yes, our new neighbours under Lumbridge. I hear", "you were the one who made contact with them, jolly good.");
stage = 40;
} else {
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Hmm, have you ever even met the Dorgeshuun? I don't", "think you should wear their symbol until you have", "made contact with that lost tribe.");
stage = 310;
}
break;
}
case 4: {
CrestType c = CrestType.DRAGON;
if (c.eligible(player) && player.getInventory().getAmount(Items.COINS_995) > c.getCost()
&& player.getInventory().remove(new Item(Items.COINS_995, c.getCost()))) {
player.getHouseManager().setCrest(c);
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "I see you are a mighty dragon-slayer! You have", "certainly earned the right to wear a dragon symbol.");
stage = 40;
} else {
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "[MISSING DIALOGUE - NOT ELIGIBLE]");
stage = 310;
}
break;
}
case 5:
interpreter.sendOptions("Select an option", "Fairy", "Guthix", "HAM", "Horse", "More...");
stage = 330;
break;
}
break;
case 330:
switch (buttonId) {
case 1: {
CrestType c = CrestType.FAIRY;
if (c.eligible(player) && player.getInventory().getAmount(Items.COINS_995) > c.getCost()
&& player.getInventory().remove(new Item(Items.COINS_995, c.getCost()))) {
player.getHouseManager().setCrest(c);
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Hmm, mmm, yes, everyone likes pretty fairies.");
stage = 40;
} else {
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "[MISSING DIALOGUE - NOT ELIGIBLE]");
stage = 310;
}
break;
}
case 2: {
CrestType c = CrestType.GUTHIX;
if (c.eligible(player) && player.getInventory().getAmount(Items.COINS_995) > c.getCost()
&& player.getInventory().remove(new Item(Items.COINS_995, c.getCost()))) {
player.getHouseManager().setCrest(c);
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Guthix, god of balance! I'm a Saradominist myself,", "you know, but we all find meaning in our own way, what?");
stage = 40;
} else {
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "You do not seem to be very devoted to any god.", "I will not let you have a divine symbol", "unless you have level 70 prayer.");
stage = 310;
}
break;
}
case 3: {
CrestType c = CrestType.HAM;
if (c.eligible(player) && player.getInventory().getAmount(Items.COINS_995) > c.getCost()
&& player.getInventory().remove(new Item(Items.COINS_995, c.getCost()))) {
player.getHouseManager().setCrest(c);
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Hmm, I'm not sure I like that HAM group, their", "beliefs are a little extreme for me.", "But if that's what you want.");
stage = 40;
} else {
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "[MISSING DIALOGUE - NOT ELIGIBLE]");
stage = 310;
}
break;
}
case 4: {
CrestType c = CrestType.HORSE;
if (c.eligible(player) && player.getInventory().getAmount(Items.COINS_995) > c.getCost()
&& player.getInventory().remove(new Item(Items.COINS_995, c.getCost()))) {
player.getHouseManager().setCrest(c);
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Ah, I see you've brought a toy horse for me to see. An",
"interesting beast. Certainly you can use that as your",
"crest if you like, although it seems a bit strange to me.");
stage = 40;
} else {
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "A horse? I know people talk about them, but I'm not at all sure",
"they ever existed. I don't think I could let you use as",
"your symbol unless you can fetch me some kind of model of one.");
stage = 310;
}
break;
}
case 5:
interpreter.sendOptions("Select an option", "Jogre", "Kandarin", "Misthalin", "Money", "More...");
stage = 340;
break;
}
break;
case 340:
switch (buttonId) {
case 1: {
CrestType c = CrestType.JOGRE;
if (c.eligible(player) && player.getInventory().getAmount(Items.COINS_995) > c.getCost()
&& player.getInventory().remove(new Item(Items.COINS_995, c.getCost()))) {
player.getHouseManager().setCrest(c);
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "A Jungle Ogre, eh? Odd beast, very odd.");
stage = 40;
} else {
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "[MISSING DIALOGUE - NOT ELIGIBLE]");
stage = 310;
}
break;
}
case 2: {
CrestType c = CrestType.KANDARIN;
if (c.eligible(player) && player.getInventory().getAmount(Items.COINS_995) > c.getCost()
&& player.getInventory().remove(new Item(Items.COINS_995, c.getCost()))) {
player.getHouseManager().setCrest(c);
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Our neighbours in the west? Very good, very good.");
stage = 40;
} else {
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "[MISSING DIALOGUE - NOT ELIGIBLE]");
stage = 310;
}
break;
}
case 3: {
CrestType c = CrestType.MISTHALIN;
if (c.eligible(player) && player.getInventory().getAmount(Items.COINS_995) > c.getCost()
&& player.getInventory().remove(new Item(Items.COINS_995, c.getCost()))) {
player.getHouseManager().setCrest(c);
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Ah, the fair land of Lumbridge and Varrock.");
stage = 40;
} else {
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "[MISSING DIALOGUE - NOT ELIGIBLE]");
stage = 310;
}
break;
}
case 4:
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "You wish to represent yourself by a moneybag?", "I think to make that meaningful I should increase", "the price to 500,000 coins. Do you agree?");
stage = 342;
break;
case 5:
interpreter.sendOptions("Select an option", "Saradomin", "Skull", "Varrock", "Zamorak", "More...");
stage = 350;
break;
}
break;
case 341:
interpreter.sendOptions("Select an option", "All right.", "No way!");
stage = 342;
break;
case 342:
switch (buttonId) {
case 1:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "All right.");
CrestType c = CrestType.MONEY;
if (c.eligible(player) && player.getInventory().getAmount(Items.COINS_995) > c.getCost()) {
stage = 343;
} else {
stage = 302;
}
break;
case 2:
interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "No way!");
stage = 344;
break;
}
break;
case 343: {
CrestType c = CrestType.MONEY;
if (c.eligible(player) && player.getInventory().getAmount(Items.COINS_995) > c.getCost()
&& player.getInventory().remove(new Item(Items.COINS_995, c.getCost()))) {
player.getHouseManager().setCrest(c);
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Thank you very much! You may now use a money-bag", "as your symbol.");
stage = 40;
} else {
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "[MISSING DIALOGUE - NOT ELIGIBLE]");
stage = 310;
}
break;
}
case 344:
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Well we can't have just any pauper using a money-bag", "as a symbol, can we? You'll have to choose a", "different symbol.");
stage = 310;
break;
case 350:
switch (buttonId) {
case 1: {
CrestType c = CrestType.SARADOMIN;
if (c.eligible(player) && player.getInventory().getAmount(Items.COINS_995) > c.getCost()
&& player.getInventory().remove(new Item(Items.COINS_995, c.getCost()))) {
player.getHouseManager().setCrest(c);
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Ah, the great god Saradomin! May he smile on your house", "as you adorn it with his symbol!");
if (!player.getAchievementDiaryManager().getDiary(DiaryType.FALADOR).isComplete(2,1)) {
player.getAchievementDiaryManager().getDiary(DiaryType.FALADOR).updateTask(player,2,1,true);
}
stage = 40;
} else {
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "You do not seem to be very devoted to any god.", "I will not let you have a divine symbol", "unless you have level 70 prayer.");
stage = 310;
}
break;
}
case 2: {
CrestType c = CrestType.SKULL;
if (c.eligible(player) && player.getInventory().getAmount(Items.COINS_995) > c.getCost()
&& player.getInventory().remove(new Item(Items.COINS_995, c.getCost()))) {
player.getHouseManager().setCrest(c);
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Of, of course you can have a skull symbol, " + (player.getAppearance().isMale() ? "sir!" : "madam!"));
stage = 40;
} else {
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "A symbol of death? You do not seem like a killer to me;", "perhaps some other symbol would suit you better.");
stage = 310;
}
break;
}
case 3: {
CrestType c = CrestType.VARROCK;
if (c.eligible(player) && player.getInventory().getAmount(Items.COINS_995) > c.getCost()
&& player.getInventory().remove(new Item(Items.COINS_995, c.getCost()))) {
player.getHouseManager().setCrest(c);
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "Ah, Varrock, a fine city!");
stage = 40;
} else {
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "[MISSING DIALOGUE - NOT ELIGIBLE]");
stage = 310;
}
break;
}
case 4: {
CrestType c = CrestType.ZAMORAK;
if (c.eligible(player) && player.getInventory().getAmount(Items.COINS_995) > c.getCost()
&& player.getInventory().remove(new Item(Items.COINS_995, c.getCost()))) {
player.getHouseManager().setCrest(c);
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "The god of Chaos? It is a terrible thing to worship", "that evil being. But if that is what you wish...");
stage = 40;
} else {
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "You do not seem to be very devoted to any god.", "I will not let you have a divine symbol", "unless you have level 70 prayer.");
stage = 310;
}
break;
}
case 5:
interpreter.sendOptions("Select an Option", "Shield of Arrav", "Asgarnia", "Dorgeshuun Symbol", "Dragon", "More...");
stage = 320;
break;
}
break;
case 500:
interpreter.sendDialogues(npc, FacialExpression.HALF_GUILTY, "[MISSING DIALOGUE - UNIMPLIMENTED]");
stage = 40;
}
return true;
}
@Override
public DialoguePlugin newInstance(Player player) {
return new SirReniteeDialogue(player);
}
@Override
public int[] getIds() {
return new int[]{4249};
}
}

View file

@ -0,0 +1,550 @@
package content.region.asgarnia.falador.dialogue
import content.global.skill.construction.CrestType
import content.global.skill.construction.PaintingType
import content.global.skill.crafting.HeraldicProduct
import core.ServerConstants
import core.Util
import core.api.*
import core.game.dialogue.ChatAnim
import core.game.dialogue.DialogueLabeller
import core.game.dialogue.DialogueOption
import core.game.diary.DiaryLevel
import core.game.interaction.IntType
import core.game.interaction.InteractionListener
import core.game.node.entity.npc.NPC
import core.game.node.entity.player.link.diary.DiaryType
import core.game.node.entity.skill.Skills
import core.game.node.item.Item
import core.tools.RandomFunction
import org.rs09.consts.Items
import org.rs09.consts.NPCs
/**
* Dialogue for Sir Renitee, who manages the player's personal crest for the Construction skill, and sells paintings.
* @author Bishop
*/
class SirReniteeDialogue : InteractionListener {
override fun defineListeners() {
on(NPCs.SIR_RENITEE_4249, IntType.NPC, "talk-to") { player, node ->
DialogueLabeller.open(player, SirReniteeDialogueFile(), node as NPC)
return@on true
}
}
}
class SirReniteeDialogueFile : DialogueLabeller() {
companion object {
const val ATTRIBUTE_CREST = "/save:sir-renitee-assigned-crest"
private const val ATTRIBUTE_CREST_TEMP = "sir-renitee-temp-crest"
private const val ATTRIBUTE_PAINTING_TEMP = "sir-renitee-temp-painting"
}
private fun selectCrest(crestType: CrestType, labelName: String) {
label(labelName)
exec { player, _ ->
setAttribute(player, ATTRIBUTE_CREST_TEMP, crestType)
loadLabel(player, "crest_buy")
}
}
private fun selectPainting(painting: PaintingType, labelName: String) {
label(labelName)
exec { player, _ ->
setAttribute(player, ATTRIBUTE_PAINTING_TEMP, painting)
loadLabel(player, "painting_buy")
}
}
override fun addConversation() {
/**
* GENERIC DIALOGUE
*/
npc(ChatAnim.NEUTRAL, "Hmm? What's that, young ${if (player!!.isMale) "man" else "woman"}? What can I do for", "you?")
options(
DialogueOption("intro", "I don't know, what can you do for me?", expression = ChatAnim.ASKING),
DialogueOption("nothing", "Nothing, thanks", spokenText = "Nothing, thanks.", expression = ChatAnim.NEUTRAL),
)
label("nothing")
npc(ChatAnim.NEUTRAL, "Mmm, well, see you some other time maybe.")
/**
* CREST DIALOGUE
*/
label("intro")
npc(ChatAnim.NEUTRAL, "Hmm, well, mmm, do you have a family crest? I keep",
"track of every ${ServerConstants.SERVER_NAME} family, you know, so I might", "be able to find yours.")
npc(ChatAnim.NEUTRAL, "I'm also something of an, mmm, a painter. If you've",
"met any important persons or visited any nice places I", "could paint them for you.")
options(
DialogueOption("family_crest", "Can you see if I have a family crest?", expression = ChatAnim.ASKING),
DialogueOption("painting", "Can I buy a painting?", expression = ChatAnim.NEUTRAL),
)
label("family_crest")
npc(ChatAnim.NEUTRAL_FAST, "What is your name?")
player(ChatAnim.NEUTRAL, "${player!!.username}.")
npc(ChatAnim.NEUTRAL_FAST, "Mmm, ${player!!.username}, let me see...")
exec { player, _ ->
if (hasLevelStat(player, Skills.CONSTRUCTION, HeraldicProduct.STEEL_HELM.constructionReq)) {
loadLabel(player, "has_construction_level")
} else {
loadLabel(player, "no_construction_level")
}
}
label("no_construction_level")
npc(ChatAnim.NEUTRAL, "First thing's first, young ${if (player!!.isMale) "man" else "woman"}! There is not much point",
"in having a family crest if you cannot display it.")
npc(ChatAnim.NEUTRAL, "You should train construction until you can build a wall",
"decoration in your dining room.")
label("has_construction_level")
exec { player, _ ->
if (getAttribute(player, ATTRIBUTE_CREST, false)) {
loadLabel(player, "show_existing_crest")
} else {
val crests = arrayOf(CrestType.VARROCK, CrestType.ASGARNIA, CrestType.KANDARIN, CrestType.MISTHALIN)
player.houseManager.crest = crests[RandomFunction.random(4)]
setAttribute(player, ATTRIBUTE_CREST, true)
loadLabel(player, "show_new_crest")
}
if (!player.achievementDiaryManager.getDiary(DiaryType.FALADOR).isComplete(0, 4)) {
finishTask(player, DiaryType.FALADOR, DiaryLevel.EASY, 4)
}
}
label("show_existing_crest")
npc(ChatAnim.NEUTRAL, "According to my records, your crest is ${player!!.houseManager.crest.crestName}.")
goto("crest_options")
label("show_new_crest")
npc(ChatAnim.NEUTRAL, "Well, I don't think you have any noble blood,",
"but I see that your ancestors came from ${Util.enumToString(player!!.houseManager.crest.name)},",
"so ${if (player!!.houseManager.crest == CrestType.VARROCK) "you can use that city's" else "that can be your"} crest.")
goto("crest_options")
label("crest_options")
options(
DialogueOption("change_crest", "I don't like that crest. Can I have a different one?", expression = ChatAnim.ASKING),
DialogueOption("thanks", "Thanks!", expression = ChatAnim.NEUTRAL),
)
label("thanks")
npc(ChatAnim.NEUTRAL, "You're welcome, my ${if (player!!.isMale) "boy" else "girl"}.")
label("change_crest")
npc(ChatAnim.NEUTRAL, "Mmm, very well. Changing your crest will cost 5,000", "coins.")
exec { player, _ ->
if (amountInInventory(player, Items.COINS_995) < CrestType.ASGARNIA.cost) {
loadLabel(player, "no_money")
} else {
loadLabel(player, "choose_symbol")
}
}
label("no_money")
player(ChatAnim.NEUTRAL, "I'll have to go and get some money then.")
label("choose_symbol")
npc(ChatAnim.NEUTRAL, "There are sixteen different symbols; which one would", "you like?")
goto("crest_page1")
label("crest_page1")
options(
DialogueOption("crest_arrav", "Shield of Arrav", skipPlayer = true),
DialogueOption("crest_asgarnia", "Asgarnia", skipPlayer = true),
DialogueOption("crest_dorgeshuun", "Dorgeshuun Symbol", skipPlayer = true),
DialogueOption("crest_dragon", "Dragon", skipPlayer = true),
DialogueOption("crest_page2", "More...", skipPlayer = true),
)
label("crest_page2")
options(
DialogueOption("crest_fairy", "Fairy", skipPlayer = true),
DialogueOption("crest_guthix", "Guthix", skipPlayer = true),
DialogueOption("crest_ham", "HAM", skipPlayer = true),
DialogueOption("crest_horse", "Horse", skipPlayer = true),
DialogueOption("crest_page3", "More...", skipPlayer = true),
)
label("crest_page3")
options(
DialogueOption("crest_jogre", "Jogre", skipPlayer = true),
DialogueOption("crest_kandarin", "Kandarin", skipPlayer = true),
DialogueOption("crest_misthalin", "Misthalin", skipPlayer = true),
DialogueOption("crest_money", "Money", skipPlayer = true),
DialogueOption("crest_page4", "More...", skipPlayer = true),
)
label("crest_page4")
options(
DialogueOption("crest_saradomin", "Saradomin", skipPlayer = true),
DialogueOption("crest_skull", "Skull", skipPlayer = true),
DialogueOption("crest_varrock", "Varrock", skipPlayer = true),
DialogueOption("crest_zamorak", "Zamorak", skipPlayer = true),
DialogueOption("crest_page1", "More...", skipPlayer = true),
)
/**
* CREST CHECKOUT
*/
selectCrest(CrestType.ARRAV, "crest_arrav")
selectCrest(CrestType.ASGARNIA, "crest_asgarnia")
selectCrest(CrestType.DORGESHUUN, "crest_dorgeshuun")
selectCrest(CrestType.DRAGON, "crest_dragon")
selectCrest(CrestType.FAIRY, "crest_fairy")
selectCrest(CrestType.GUTHIX, "crest_guthix")
selectCrest(CrestType.HAM, "crest_ham")
selectCrest(CrestType.HORSE, "crest_horse")
selectCrest(CrestType.JOGRE, "crest_jogre")
selectCrest(CrestType.KANDARIN, "crest_kandarin")
selectCrest(CrestType.MISTHALIN, "crest_misthalin")
selectCrest(CrestType.SARADOMIN, "crest_saradomin")
selectCrest(CrestType.SKULL, "crest_skull")
selectCrest(CrestType.VARROCK, "crest_varrock")
selectCrest(CrestType.ZAMORAK, "crest_zamorak")
label("crest_buy")
exec { player, _ ->
val crest = getAttribute(player, ATTRIBUTE_CREST_TEMP, CrestType.ASGARNIA)
if (crest.eligible(player) && removeItem(player, Item(Items.COINS_995, crest.cost))) {
player.houseManager.crest = crest
if (crest == CrestType.SARADOMIN && !player.achievementDiaryManager.getDiary(DiaryType.FALADOR).isComplete(2, 1)) {
player.achievementDiaryManager.getDiary(DiaryType.FALADOR).updateTask(player, 2, 1, true)
}
loadLabel(player, "crest_buy_ok")
} else {
loadLabel(player, "crest_buy_fail")
}
}
label("crest_buy_ok")
manual { player, _ ->
val crest = getAttribute(player, ATTRIBUTE_CREST_TEMP, CrestType.ASGARNIA)
val expression = if (crest == CrestType.SKULL) {
ChatAnim.AFRAID
} else {
ChatAnim.HAPPY
}
val messages = when (crest) {
CrestType.ARRAV ->
arrayOf("Ah yes, the shield that you helped to retrieve. You have",
"certainly earned the right to wear its symbol.")
CrestType.ASGARNIA ->
arrayOf("Ah, splendid, splendid. There is no better symbol",
"than that of our fair land!")
CrestType.DORGESHUUN ->
arrayOf("Ah yes, our new neighbours under Lumbridge. I hear",
"you were the one who made contact with them, jolly good.")
CrestType.DRAGON ->
arrayOf("I see you are a mighty dragon-slayer! You have",
"certainly earned the right to wear a dragon symbol.")
CrestType.FAIRY ->
arrayOf("Hmm, mmm, yes, everyone likes pretty fairies.")
CrestType.GUTHIX ->
arrayOf("Guthix, god of balance! I'm a Saradominist myself,",
"you know, but we all find meaning in our own way, what?")
CrestType.HAM ->
arrayOf("Hmm, I'm not sure I like that HAM group, their",
"beliefs are a little extreme for me.", "But if that's what you want.")
CrestType.HORSE ->
arrayOf("Ah, I see you've brought a toy horse for me to see. An",
"interesting beast. Certainly you can use that as your",
"crest if you like, although it seems a bit strange to me.")
CrestType.JOGRE ->
arrayOf("A Jungle Ogre, eh? Odd beast, very odd.")
CrestType.KANDARIN ->
arrayOf("Our neighbours in the west? Very good, very good.")
CrestType.MISTHALIN ->
arrayOf("Ah, the fair land of Lumbridge and Varrock.")
CrestType.SARADOMIN ->
arrayOf("Ah, the great god Saradomin! May he smile on your house",
"as you adorn it with his symbol!")
CrestType.SKULL ->
arrayOf("Of, of course you can have a skull symbol, ${if (player.isMale) "sir" else "madam"}!")
CrestType.VARROCK ->
arrayOf("Ah, Varrock, a fine city!")
CrestType.ZAMORAK ->
arrayOf("The god of Chaos? It is a terrible thing to worship",
"that evil being. But if that is what you wish...")
else ->
arrayOf("This shouldn't be happening. Please report this.")
}
interpreter!!.sendDialogues(npc, expression, *messages)
}
label("crest_buy_fail")
manual { player, _ ->
val crest = getAttribute(player, ATTRIBUTE_CREST_TEMP, CrestType.ASGARNIA)
val messages = when (crest) {
CrestType.ARRAV ->
arrayOf("But that legendary shield is still lost! I don't think",
"it would be proper for you to wear its symbol.")
CrestType.DORGESHUUN ->
arrayOf("Hmm, have you ever even met the Dorgeshuun? I don't",
"think you should wear their symbol until you have",
"made contact with that lost tribe.")
CrestType.DRAGON ->
arrayOf("When the dragon on Crandor Isle remains undefeated? I",
"think you should prove yourself a dragon-slayer before",
"you can wear a dragon symbol!")
CrestType.FAIRY ->
arrayOf("A fairy? Fairies are rumoured to exist in a lost city",
"somewhere. I don't think I should let you use them as",
"a symbol until you have met them in person.")
CrestType.GUTHIX, CrestType.SARADOMIN, CrestType.ZAMORAK ->
arrayOf("You do not seem to be very devoted to any god.",
"I will not let you have a divine symbol",
"unless you have level 70 prayer.")
CrestType.HORSE ->
arrayOf("A horse? I know people talk about them, but I'm not at all sure",
"they ever existed. I don't think I could let you use as",
"your symbol unless you can fetch me some kind of model of one.")
CrestType.SKULL ->
arrayOf("A symbol of death? You do not seem like a killer to me;",
"perhaps some other symbol would suit you better.")
else ->
arrayOf("This shouldn't be happening. Please report this.")
}
interpreter!!.sendDialogues(npc, ChatAnim.NEUTRAL, *messages)
}
goto("crest_page1")
// Money crest has a unique flow since Sir Renitee needs to check the player's cash stack a second time
label("crest_money")
npc(ChatAnim.NEUTRAL, "You wish to represent yourself by a moneybag?",
"I think to make that meaningful I should increase", "the price to 500,000 coins. Do you agree?")
options(
DialogueOption("money_accept", "All right.", expression = ChatAnim.NEUTRAL),
DialogueOption("money_refuse", "No way!", expression = ChatAnim.NEUTRAL),
)
label("money_accept")
exec { player, _ ->
if (CrestType.MONEY.eligible(player) && removeItem(player, Item(Items.COINS_995, CrestType.MONEY.cost))) {
player.houseManager.crest = CrestType.MONEY
loadLabel(player, "money_ok")
} else {
loadLabel(player, "no_money")
}
}
label("money_ok")
npc(ChatAnim.NEUTRAL, "Thank you very much! You may now use a money-bag", "as your symbol.")
label("money_refuse")
npc(ChatAnim.NEUTRAL, "Well we can't have just any pauper using a money-bag",
"as a symbol, can we? You'll have to choose a", "different symbol.")
goto("crest_page1")
/**
* PAINTING DIALOGUE
*/
label("painting")
npc(ChatAnim.NEUTRAL, "Would you like a portrait or an, mmm, a landscape? Or", "a map, maybe?")
goto("painting_options")
label("painting_options")
options(
DialogueOption("portrait", "A portrait", "A portrait please.", expression = ChatAnim.NEUTRAL),
DialogueOption("landscape", "A landscape", "A landscape please.", expression = ChatAnim.NEUTRAL),
DialogueOption("map", "A map", "A map please.", expression = ChatAnim.NEUTRAL),
)
/**
* PAINTING MENUS
*/
label("portrait")
npc(ChatAnim.NEUTRAL, "Mmm, well, there are a few portraits I can paint. I can",
"only let you have one if you've got some connection with", "that person though. Who would you like?")
options(
DialogueOption("portrait_arthur", "King Arthur", skipPlayer = true),
DialogueOption("portrait_elena", "Elena of Ardougne", skipPlayer = true),
DialogueOption("portrait_alvis", "King Alvis of Keldagrim", skipPlayer = true),
DialogueOption("portrait_misc", "The Prince and Princess of Miscellania", skipPlayer = true),
)
label("landscape")
npc(ChatAnim.NEUTRAL, "Mmm, well, I can paint a few places. Where have you had", "your adventures?")
options(
DialogueOption("landscape_lumbridge", "The River Lum", skipPlayer = true),
DialogueOption("landscape_desert", "The Kharid desert", skipPlayer = true),
DialogueOption("landscape_morytania", "Morytania", skipPlayer = true),
DialogueOption("landscape_karamja", "Karamja", skipPlayer = true),
DialogueOption("landscape_isafdar", "Isafdar", skipPlayer = true),
)
label("map")
npc(ChatAnim.NEUTRAL, "Mmm, yes, ah, I have painted maps of the known world on",
"several different sizes of parchment. Which size would", "you like?")
options(
DialogueOption("map_small", "Small", skipPlayer = true),
DialogueOption("map_medium", "Medium", skipPlayer = true),
DialogueOption("map_large", "Large", skipPlayer = true),
)
/**
* PAINTING CHECKOUT
*/
selectPainting(PaintingType.ARTHUR, "portrait_arthur")
selectPainting(PaintingType.ELENA, "portrait_elena")
selectPainting(PaintingType.ALVIS, "portrait_alvis")
selectPainting(PaintingType.MISC, "portrait_misc")
selectPainting(PaintingType.DESERT, "landscape_desert")
selectPainting(PaintingType.ISAFDAR, "landscape_isafdar")
selectPainting(PaintingType.KARAMJA, "landscape_karamja")
selectPainting(PaintingType.LUMBRIDGE, "landscape_lumbridge")
selectPainting(PaintingType.MORYTANIA, "landscape_morytania")
selectPainting(PaintingType.MAP_SMALL, "map_small")
selectPainting(PaintingType.MAP_MEDIUM, "map_medium")
selectPainting(PaintingType.MAP_LARGE, "map_large")
label("painting_buy")
exec { player, _ ->
val painting = getAttribute(player, ATTRIBUTE_PAINTING_TEMP, PaintingType.MAP_SMALL)
if (painting.eligible(player)) {
loadLabel(player, "painting_show_cost")
} else {
loadLabel(player, "painting_buy_fail")
}
}
label("painting_show_cost")
manual { player, _ ->
val painting = getAttribute(player, ATTRIBUTE_PAINTING_TEMP, PaintingType.MAP_SMALL)
interpreter!!.sendDialogues(npc, ChatAnim.NEUTRAL, "That will be, mmm, ${painting.cost} coins please.")
}
exec { player, _ ->
val painting = getAttribute(player, ATTRIBUTE_PAINTING_TEMP, PaintingType.MAP_SMALL)
if (inInventory(player, Items.COINS_995, painting.cost)) {
loadLabel(player, "painting_buy_confirm")
} else {
loadLabel(player, "no_money")
}
}
label("painting_buy_confirm")
options(
DialogueOption("painting_accept", "All right", skipPlayer = true),
DialogueOption("painting_refuse", "No thanks", skipPlayer = true),
)
label("painting_buy_fail")
manual { player, _ ->
val painting = getAttribute(player, ATTRIBUTE_PAINTING_TEMP, PaintingType.MAP_SMALL)
val messages = when (painting) {
PaintingType.ARTHUR ->
arrayOf("Do you have, mmm, a connection with King Arthur? He",
"wouldn't like me to just give his picture to anyone.")
PaintingType.ELENA ->
arrayOf("The last I heard, Elena was, mmm, trapped in West",
"Ardougne. I wouldn't feel right selling her portrait",
"while she was in danger.")
PaintingType.ALVIS ->
arrayOf("Have you ever been to Keldagrim? I think I'd need you",
"to jog my memory...")
PaintingType.MISC ->
arrayOf("Do you have some connection with the prince and",
"princess? I wouldn't want to give out their picture to",
"just anyone?")
PaintingType.DESERT ->
arrayOf("Mmm, I'm not sure you've had enough adventures in the",
"desert to deserve a painting of it.")
PaintingType.ISAFDAR ->
arrayOf("Mmm, I'm not sure you've had enough adventures in",
"Isafdar to deserve a painting of it.")
PaintingType.KARAMJA ->
arrayOf("Mmm, I'm not sure you've had enough adventures in",
"Karamja to deserve a painting of it.")
PaintingType.LUMBRIDGE ->
arrayOf("Mmm, I'm not sure you've had enough adventures in",
"Lumbridge to deserve a painting of it.")
PaintingType.MORYTANIA ->
arrayOf("Mmm, I'm not sure you've had enough adventures in",
"Morytania to deserve a painting of it.")
PaintingType.MAP_SMALL, PaintingType.MAP_MEDIUM, PaintingType.MAP_LARGE ->
arrayOf("Mmm, I'm not sure you've had enough adventures in the",
"world to deserve that map.")
}
interpreter!!.sendDialogues(npc, ChatAnim.NEUTRAL, *messages)
}
manual { player, _ ->
val painting = getAttribute(player, ATTRIBUTE_PAINTING_TEMP, PaintingType.MAP_SMALL)
val messages = when (painting) {
PaintingType.ARTHUR ->
arrayOf("To buy the portrait of King Arthur you must have",
"completed The Holy Grail.")
PaintingType.ELENA ->
arrayOf("To buy the portrait of Elena you must have completed",
"the Plague City quest.")
PaintingType.ALVIS ->
arrayOf("To buy the portrait of the Giant Dwarf"/*sic*/+" you must have",
"completed The Giant Dwarf.")
PaintingType.MISC ->
arrayOf("To buy the portrait of the Prince and Princess of",
"Miscellania you must have completed The Throne of",
"Miscellania.")
PaintingType.DESERT ->
arrayOf("To buy the painting of the desert you must have",
"completed Tourist Trap, The Feud, and The Golem.")
PaintingType.ISAFDAR ->
arrayOf("To buy the painting of Isafdar you must have completed",
"Roving Elves.")
PaintingType.KARAMJA ->
arrayOf("To buy the painting of Karamja you must have completed",
"Pirate's Treasure, Tai Bwo Wannai Trio, and Shilo Village.")
PaintingType.LUMBRIDGE ->
arrayOf("To buy the painting of the Lum you must have completed",
"Cook's Assistant, Rune Mysteries, and The Restless Ghost.")
PaintingType.MORYTANIA ->
arrayOf("To buy the painting of Morytania you must have completed",
"Shades of Mort'ton, The Creature of Fenkenstrain,",
"Ghosts Ahoy, and The Haunted Mine.")
PaintingType.MAP_SMALL ->
arrayOf("To buy a small map you must have 51 Quest Points.")
PaintingType.MAP_MEDIUM ->
arrayOf("To buy a medium map you must have 101 Quest Points.")
PaintingType.MAP_LARGE ->
arrayOf("To buy a large map you must have 151 Quest Points.")
}
interpreter!!.sendDialogue(*messages)
}
goto("painting_reset")
label("painting_accept")
exec { player, _ ->
val painting = getAttribute(player, ATTRIBUTE_PAINTING_TEMP, PaintingType.MAP_SMALL)
if (removeItem(player, Item(Items.COINS_995, painting.cost))) {
addItemOrDrop(player, painting.paintingId)
}
}
npc(ChatAnim.NEUTRAL, "There you go. Would you like another painting?")
goto("painting_options")
label("painting_refuse")
npc(ChatAnim.NEUTRAL, "Well, mmm, maybe a different painting, mmm?")
goto("painting_options")
label("painting_reset")
npc(ChatAnim.NEUTRAL, "Would you like a different painting?")
options(
DialogueOption("portrait", "Yes - a portrait", "A portrait please.", expression = ChatAnim.NEUTRAL),
DialogueOption("landscape", "Yes - a landscape", "A landscape please.", expression = ChatAnim.NEUTRAL),
DialogueOption("map", "Yes - a map", "A map please.", expression = ChatAnim.NEUTRAL),
DialogueOption("nothing", "No, thanks.", expression = ChatAnim.NEUTRAL),
)
}
}

View file

@ -1,5 +1,6 @@
package core.api.utils
import content.global.skill.construction.CrestType
import content.global.skill.construction.HouseLocation
import content.minigame.blastfurnace.BFPlayerState
import content.minigame.blastfurnace.BlastFurnace
@ -81,6 +82,7 @@ fun permadeath(target: Player) {
// House data
target.houseManager.createNewHouseAt(HouseLocation.NOWHERE)
target.houseManager.crest = CrestType.NULL
target.getPOHStorageState().clear()
// Achievements

View file

@ -70,6 +70,7 @@ public enum FacialExpression {
SLEEPING(9802),
SILENT(9804),
NEUTRAL(9808),
NEUTRAL_FAST(9810), // Like neutral but mouth starts moving immediately
THINKING(9812),
HALF_THINKING(9814),
DISGUSTED(9816),

View file

@ -197,6 +197,7 @@ class PlayerSaver (val player: Player){
val houseData = JSONObject()
houseData.put("location",manager.location.ordinal.toString())
houseData.put("style",manager.style.ordinal.toString())
houseData.put("crest",manager.crest.ordinal.toString())
if(manager.hasServant()){
val servant = JSONObject()
servant.put("type",manager.servant.type.ordinal.toString())