Completed very large refactor of Plague City quest and related functionality

This commit is contained in:
GregF
2025-02-16 10:19:20 +00:00
committed by Ryan
parent be76ca143b
commit 4f97dbef8c
66 changed files with 3055 additions and 1696 deletions
+1 -1
View File
@@ -18,7 +18,7 @@ class ServerConstants {
var NOAUTH_DEFAULT_ADMIN: Boolean = true
@JvmField
var CURRENT_SAVEFILE_VERSION = 2
var CURRENT_SAVEFILE_VERSION = 3
@JvmField
var DAILY_ACCOUNT_LIMIT = 3
+19 -4
View File
@@ -195,6 +195,18 @@ fun inEquipment(player: Player, id: Int, amount: Int = 1): Boolean {
return amountInEquipment(player, id) >= amount
}
/**
* Check if any item is in a player's inventory
* @param player the player
* @param ids the set of item ids to check
* @return true if the player has at least one of the items in their inventory, false if none are present
*/
fun anyInInventory(player: Player, vararg ids: Int): Boolean {
return ids.any{ id ->
inInventory(player, id)
}
}
/**
* Check if an item exists in a player's equipment or inventory
* @param player the player whose equipment to check
@@ -1702,9 +1714,10 @@ fun closeAllInterfaces(player: Player) {
* @param player the player to send the dialogue to
* @param msg the message to send.
* @param expr the FacialExpression to use. An enum exists for these called FacialExpression. Defaults to FacialExpression.FRIENDLY
* @param hide should the continue button be hidden?
*/
fun sendPlayerDialogue(player: Player, msg: String, expr: core.game.dialogue.FacialExpression = core.game.dialogue.FacialExpression.FRIENDLY) {
player.dialogueInterpreter.sendDialogues(player, expr, *splitLines(msg))
fun sendPlayerDialogue(player: Player, msg: String, expr: core.game.dialogue.FacialExpression = core.game.dialogue.FacialExpression.FRIENDLY, hide: Boolean = false) {
player.dialogueInterpreter.sendDialogues(player, expr, hide, *splitLines(msg))
}
/**
@@ -1723,9 +1736,11 @@ fun sendPlayerOnInterface(player: Player, iface: Int, child: Int) {
* @param npc the ID of the NPC to use for the chathead
* @param msg the message to send.
* @param expr the FacialExpression to use. An enum exists for these called FacialExpression. Defaults to FacialExpression.FRIENDLY
* @param hide should the continue button be hidden?
*/
fun sendNPCDialogue(player: Player, npc: Int, msg: String, expr: core.game.dialogue.FacialExpression = core.game.dialogue.FacialExpression.FRIENDLY) {
player.dialogueInterpreter.sendDialogues(npc, expr, *splitLines(msg))
fun sendNPCDialogue(player: Player, npc: Int, msg: String, expr: core.game.dialogue.FacialExpression = core.game.dialogue.FacialExpression.FRIENDLY,
hide: Boolean = false) {
player.dialogueInterpreter.sendDialogues(npc, expr, hide, *splitLines(msg))
}
/**
@@ -122,11 +122,12 @@ abstract class Cutscene(val player: Player) {
* @param expression the FacialExpression the NPC should use
* @param message the message to send
* @param onContinue (optional) a method that runs when the dialogue is "continued." Increments the cutscene stage by default.
* @param hide Should the continue button be hidden?
*/
fun dialogueUpdate(npcId: Int, expression: core.game.dialogue.FacialExpression, message: String, onContinue: () -> Unit = {incrementStage()})
fun dialogueUpdate(npcId: Int, expression: core.game.dialogue.FacialExpression, message: String, onContinue: () -> Unit = {incrementStage()}, hide: Boolean = false)
{
logCutscene("Sending NPC dialogue update.")
sendNPCDialogue(player, npcId, message, expression)
sendNPCDialogue(player, npcId, message, expression, hide)
player.dialogueInterpreter.addAction { _,_ -> onContinue.invoke() }
}
@@ -434,7 +434,7 @@ public final class DialogueInterpreter {
* @return The chatbox component.
*/
public Component sendDialogues(Entity entity, int expression, String... messages) {
return sendDialogues(entity instanceof Player ? -1 : ((NPC) entity).getShownNPC(player).getId(), expression, messages);
return sendDialogues(entity instanceof Player ? -1 : ((NPC) entity).getShownNPC(player).getId(), expression, false, messages);
}
/**
@@ -442,12 +442,11 @@ public final class DialogueInterpreter {
* @param npcId The npc id.
* @param expression The entity's facial expression.
* @param messages The messages.
* @param hide the continue.
* @param hide should the continue button be hidden?
* @return The chatbox component.
*/
public Component sendDialogues(int npcId, FacialExpression expression, boolean hide, String... messages) {
sendDialogues(npcId, expression == null ? -1 : expression.getAnimationId(), messages);
return player.getInterfaceManager().getChatbox();
return sendDialogues(npcId, expression == null ? -1 : expression.getAnimationId(), hide, messages);
}
/**
@@ -458,34 +457,18 @@ public final class DialogueInterpreter {
* @return The chatbox component.
*/
public Component sendDialogues(Entity entity, FacialExpression expression, boolean hide, String... messages) {
sendDialogues(entity, expression, messages);
player.getPacketDispatch().sendInterfaceConfig(player.getInterfaceManager().getChatbox().getId(), 3, hide);
return player.getInterfaceManager().getChatbox();
return sendDialogues(entity.getId(), expression == null ? -1 : expression.getAnimationId(), hide, messages);
}
/**
* Send dialogues based on the amount of specified messages.
* @param expression The entity's facial expression.
* @param messages The messages.
* @param hide the continue.
* @param hide should the continue button be hidden?
* @return The chatbox component.
*/
public Component sendDialogues(Entity entity, int expression, boolean hide, String... messages) {
sendDialogues(entity, expression, messages);
player.getPacketDispatch().sendInterfaceConfig(player.getInterfaceManager().getChatbox().getId(), 3, hide);
return player.getInterfaceManager().getChatbox();
}
/**
* Send dialogues based on the amount of specified messages.
* @param expression The entity's facial expression.
* @param messages The messages.
* @return The chatbox component.
*/
public Component sendDialogues(int npcId, int expression, boolean hide, String... messages) {
sendDialogues(npcId, expression, messages);
player.getPacketDispatch().sendInterfaceConfig(player.getInterfaceManager().getChatbox().getId(), 3, hide);
return player.getInterfaceManager().getChatbox();
return sendDialogues(entity.getId(), expression, hide, messages);
}
/**
@@ -496,7 +479,7 @@ public final class DialogueInterpreter {
* @return The chatbox component.
*/
public Component sendDialogues(int npcId, FacialExpression expression, String... messages) {
return sendDialogues(npcId, expression == null ? -1 : expression.getAnimationId(), messages);
return sendDialogues(npcId, expression == null ? -1 : expression.getAnimationId(),false, messages);
}
static Pattern GENDERED_SUBSTITUTION = Pattern.compile("@g\\[([^,]*),([^\\]]*)\\]");
@@ -512,7 +495,6 @@ public final class DialogueInterpreter {
m.appendTail(sb);
return sb.toString();
}
/**
* Send dialogues based on the amount of specified messages.
* @param npcId The npc id.
@@ -521,18 +503,31 @@ public final class DialogueInterpreter {
* @return The chatbox component.
*/
public Component sendDialogues(int npcId, int expression, String... messages) {
return sendDialogues(npcId, expression, false, messages);
}
/**
* Send dialogues based on the amount of specified messages.
* @param npcId The npc id.
* @param expression The entity's facial expression.
* @param messages The messages.
* @param hide should the continue button be hidden?
* @return The chatbox component.
*/
public Component sendDialogues(int npcId, int expression, boolean hide, String... messages) {
if (messages.length < 1 || messages.length > 4) {
System.err.println("Invalid amount of messages: " + messages.length);
return null;
}
boolean npc = npcId > -1;
int interfaceId = (npc ? 240 : 63) + messages.length;
interfaceId += hide ? 4 : 0;
if (expression == -1) {
expression = FacialExpression.HALF_GUILTY.getAnimationId();
}
player.getPacketDispatch().sendAnimationInterface(expression, interfaceId, 2);
player.getPacketDispatch().sendItemOnInterface(-1, 1, interfaceId, 1);
if (npc) {
player.getPacketDispatch().sendItemOnInterface(-1, 1, interfaceId, 1);
player.getPacketDispatch().sendNpcOnInterface(npcId, interfaceId, 2);
player.getPacketDispatch().sendString(NPCDefinition.forId(npcId).getName(), interfaceId, 3);
} else {
@@ -540,7 +535,7 @@ public final class DialogueInterpreter {
player.getPacketDispatch().sendString(player.getUsername(), interfaceId, 3);
}
for (int i = 0; i < messages.length; i++) {
player.getPacketDispatch().sendString(doSubstitutions(player, messages[i].toString()), interfaceId, (i + 4));
player.getPacketDispatch().sendString(doSubstitutions(player, messages[i]), interfaceId, (i + 4));
}
player.getInterfaceManager().openChatbox(interfaceId);
player.getPacketDispatch().sendInterfaceConfig(player.getInterfaceManager().getChatbox().getId(), 3, false);
@@ -33,11 +33,19 @@ class EquipHandler : InteractionListener {
fun handleEquip(player: Player, node: Node) {
val item = node.asItem()
val itemEquipmentSlot = item.definition.getConfiguration<Int>(ItemConfigParser.EQUIP_SLOT, -1)
if (item == null || player.inventory[item.slot] != item || item.name.toLowerCase().contains("goblin mail")) {
val currentEquippedItem = player.equipment[itemEquipmentSlot]
if (item == null || currentEquippedItem == item || item.name.toLowerCase().contains("goblin mail")) {
return
}
if(currentEquippedItem != null){
if(!InteractionListeners.run(currentEquippedItem.id, player, currentEquippedItem, false)){
return
}
}
val equipStateListener = item.definition.getConfiguration<Plugin<Any>>("equipment", null)
if (equipStateListener != null) {
val bool = equipStateListener.fireEvent("equip", player, item)
@@ -45,7 +53,7 @@ class EquipHandler : InteractionListener {
return
}
}
if (!InteractionListeners.run(node.id, player, node, true)) {
if (!InteractionListeners.run(node.id, player, item, true)) {
return
}
@@ -70,7 +78,6 @@ class EquipHandler : InteractionListener {
playAudio(player, item.definition.getConfiguration(ItemConfigParser.EQUIP_AUDIO, 2244))
if (player.properties.autocastSpell != null) {
val itemEquipmentSlot = item.definition.getConfiguration<Int>(ItemConfigParser.EQUIP_SLOT, -1)
if (itemEquipmentSlot == EquipmentContainer.SLOT_WEAPON) {
player.properties.autocastSpell = null
@@ -1,12 +1,15 @@
package core.game.node.entity.player.info.login
import content.data.Quests
import content.global.skill.summoning.pet.Pets
import content.region.kandarin.ardougne.quest.plaguecity.PlagueCity
import core.ServerConstants
import core.api.*
import core.game.node.entity.player.Player
import core.game.node.item.Item
import core.tools.Log
import org.rs09.consts.Items
import content.data.Quests
import org.rs09.consts.Vars
/**
* Runs one-time save-version-related hooks.
@@ -16,6 +19,7 @@ import content.data.Quests
class SaveVersionHooks : LoginListener {
override fun login(player: Player) {
if (player.version < ServerConstants.CURRENT_SAVEFILE_VERSION) {
log(this::class.java, Log.FINE, "Upgrading ${player.name} from ${player.version} to ${ServerConstants.CURRENT_SAVEFILE_VERSION}")
if (player.version < 1) { // GL !1811
// Give out crafting hoods if the player bought any crafting capes when the hoods were not obtainable
@@ -69,6 +73,15 @@ class SaveVersionHooks : LoginListener {
}
}
if (player.version < 3) {
// Damage control on Plague city. There are a few varbits that should have been set for spawning
when (getQuestStage(player, Quests.PLAGUE_CITY)){
in 6..98 -> setVarbit(player, Vars.VARBIT_QUEST_PLAGUE_CITY_EDMOND_TUNNELS, 1) // Edmond is in the tunnel
in 99..100 ->setVarbit(player, Vars.VARBIT_QUEST_PLAGUE_CITY_RESCUE_ELENA, 1) // Elena is free
}
}
// Finish up
player.version = ServerConstants.CURRENT_SAVEFILE_VERSION
}
}
@@ -202,7 +202,12 @@ public final class PacketDispatch {
* @param childId The child id.
*/
public void sendPlayerOnInterface(int interfaceId, int childId) {
PacketRepository.send(DisplayModel.class, new DisplayModelContext(player, interfaceId, childId));
// fixme right now for iface 68-71 the player is massive
// The zoom for the other windows is 2150
// for these 4 individuals it should be 796 but dmc.setZoom doesn't work
DisplayModelContext dmc = new DisplayModelContext(player, interfaceId, childId);
dmc.setZoom(796); // this appears to do nothing
PacketRepository.send(DisplayModel.class, dmc);
}
/**
@@ -73,6 +73,16 @@ class MiscCommandSet : CommandSet(Privilege.ADMIN){
AnmaCutscene(player).start()
}
define("setsaveversion", Privilege.ADMIN) { player, args ->
try{
player.version = args[1].toInt()
notify(player, "Setting save version to ${player.version}")
}
catch (nfe: NumberFormatException){
reject(player, "Save versions can only be an integer")
}
}
/**
* Prints player's current location
*/