Implemented Creature of Fenkenstrain quest

This commit is contained in:
Oven Bread
2023-11-02 08:33:02 +00:00
committed by Ryan
parent 8316a492c9
commit 0eecab4057
23 changed files with 1857 additions and 240 deletions
+17 -17
View File
@@ -61,12 +61,12 @@ public class ItemDefinition extends Definition<Item> {
/**
* The model rotation.
*/
private int modelRotationY;
private int modelRotationX;
/**
* The model rotation.
*/
private int modelRotationX;
private int modelRotationY;
/**
* The model offset.
@@ -320,9 +320,9 @@ public class ItemDefinition extends Definition<Item> {
} else if (opcode == 4) {
def.modelZoom = buffer.getShort() & 0xFFFF;
} else if (opcode == 5) {
def.modelRotationY = buffer.getShort() & 0xFFFF;
} else if (opcode == 6) {
def.modelRotationX = buffer.getShort() & 0xFFFF;
} else if (opcode == 6) {
def.modelRotationY = buffer.getShort() & 0xFFFF;
} else if (opcode == 7) {
def.modelOffsetX = buffer.getShort() & 0xFFFF;
if (def.modelOffsetX > 32767)
@@ -495,11 +495,11 @@ public class ItemDefinition extends Definition<Item> {
modelOffsetY = templateReference.modelOffsetY;
textureColour1 = templateReference.textureColour1;
value = reference.value;
modelRotationX = templateReference.modelRotationX;
modelRotationY = templateReference.modelRotationY;
stackable = true;
unnoted = false;
modifiedModelColors = templateReference.modifiedModelColors;
modelRotationY = templateReference.modelRotationY;
modelRotationX = templateReference.modelRotationX;
modelZoom = templateReference.modelZoom;
textureColour1 = templateReference.textureColour1;
handlers.put(ItemConfigParser.TRADEABLE, true);
@@ -518,8 +518,8 @@ public class ItemDefinition extends Definition<Item> {
textureColour2 = reference.textureColour2;
groundActions = reference.groundActions;
unknownArray1 = reference.unknownArray1;
modelRotationY = templateReference.modelRotationY;
modelRotationX = templateReference.modelRotationX;
modelRotationY = templateReference.modelRotationY;
originalModelColors = reference.originalModelColors;
name = reference.name;
maleWornModelId1 = reference.maleWornModelId1;
@@ -548,7 +548,7 @@ public class ItemDefinition extends Definition<Item> {
public void transferRecolourDefinition(ItemDefinition reference, ItemDefinition templateReference) {
femaleWornModelId2 = reference.femaleWornModelId2;
options = new String[5];
modelRotationX = templateReference.modelRotationX;
modelRotationY = templateReference.modelRotationY;
name = reference.name;
maleWornModelId1 = reference.maleWornModelId1;
modelOffsetY = templateReference.modelOffsetY;
@@ -557,7 +557,7 @@ public class ItemDefinition extends Definition<Item> {
modelOffsetX = templateReference.modelOffsetX;
unknownArray1 = reference.unknownArray1;
stackable = reference.stackable;
modelRotationY = templateReference.modelRotationY;
modelRotationX = templateReference.modelRotationX;
textureColour1 = reference.textureColour1;
colourEquip1 = reference.colourEquip1;
textureColour2 = reference.textureColour2;
@@ -803,32 +803,32 @@ public class ItemDefinition extends Definition<Item> {
* Gets the modelRotation1.
* @return The modelRotation1.
*/
public int getModelRotation1() {
return modelRotationY;
public int getModelRotationX() {
return modelRotationX;
}
/**
* Sets the modelRotation1.
* @param modelRotation1 The modelRotation1 to set.
*/
public void setModelRotation1(int modelRotation1) {
this.modelRotationY = modelRotation1;
public void setModelRotationX(int modelRotation1) {
this.modelRotationX = modelRotation1;
}
/**
* Gets the modelRotation2.
* @return The modelRotation2.
*/
public int getModelRotation2() {
return modelRotationX;
public int getModelRotationY() {
return modelRotationY;
}
/**
* Sets the modelRotation2.
* @param modelRotation2 The modelRotation2 to set.
*/
public void setModelRotation2(int modelRotation2) {
this.modelRotationX = modelRotation2;
public void setModelRotationY(int modelRotation2) {
this.modelRotationY = modelRotation2;
}
/**
@@ -1,6 +1,13 @@
package core.game.dialogue
import core.api.splitLines
import core.game.node.entity.player.Player
import core.tools.END_DIALOGUE
import java.util.regex.Pattern
val DEBUG_DIALOGUE = true
val NUMBER_PATTERN1 = Pattern.compile("^(\\d+) \\[label", Pattern.MULTILINE)
val NUMBER_PATTERN2 = Pattern.compile("(\\d+) -> (\\d+)")
abstract class DialogueBuilderFile : DialogueFile() {
var data: ArrayList<DialogueClause> = ArrayList()
@@ -8,6 +15,37 @@ abstract class DialogueBuilderFile : DialogueFile() {
abstract fun create(b: DialogueBuilder)
init {
create(DialogueBuilder(this))
if(DEBUG_DIALOGUE) {
var graphSb = StringBuilder("digraph {\n")
var nodeIndex = 0
for((i, clause) in data.iterator().withIndex()) {
var clauseSb = StringBuilder()
for(j in 0 until clause.nodes.size) {
if(!(clause.nodes[j] is OptionsDispatchNode)) {
clauseSb.append("${j} ${clause.nodes[j].toString().replace("@indexPlus", "${j+1}").replace("@index", "${j}")}\n")
}
}
graphSb.append("subgraph cluster_${i} {\n")
var tmpSb = StringBuilder()
var m = NUMBER_PATTERN1.matcher(clauseSb)
while(m.find()) {
var x = Integer.valueOf(m.group(1))
m.appendReplacement(tmpSb, "${x+nodeIndex} [label")
}
m.appendTail(tmpSb)
m = NUMBER_PATTERN2.matcher(tmpSb)
while(m.find()) {
var x = Integer.valueOf(m.group(1))
var y = Integer.valueOf(m.group(2))
m.appendReplacement(graphSb, "${x+nodeIndex} -> ${y+nodeIndex}")
}
m.appendTail(graphSb)
graphSb.append("}\n")
nodeIndex += clause.nodes.size
}
graphSb.append("}\n")
System.out.println(graphSb.toString())
}
}
override fun handle(componentID: Int, buttonID: Int) {
for((i, clause) in data.iterator().withIndex()) {
@@ -26,43 +64,137 @@ interface DialogueNode {
fun handle(df: DialogueFile, componentID: Int, buttonID: Int, stage: Int): Int
}
class NpcLNode(val value: String): DialogueNode {
class NpcLNode(val expression: FacialExpression, val value: String): DialogueNode {
override fun toString(): String {
return "[label=\"npcl(FacialExpression.${expression.name}, \\\"${value}\\\")\"]; @index -> @indexPlus;"
}
override fun handle(df: DialogueFile, componentID: Int, buttonID: Int, stage: Int): Int {
df.npcl(value)
df.npcl(expression, value)
return stage + 1
}
}
class NpcNode(val values: Array<String>): DialogueNode {
class NpcNode(val expression: FacialExpression, val values: Array<String>): DialogueNode {
override fun toString(): String {
return "[label=\"npc(FacialExpression.${expression.name}, \\\"${values.contentDeepToString()}\\\")\"]; @index -> @indexPlus;"
}
override fun handle(df: DialogueFile, componentID: Int, buttonID: Int, stage: Int): Int {
df.npc(*values)
df.npc(expression, *values)
return stage + 1
}
}
class PlayerLNode(val value: String): DialogueNode {
class ItemNode(val item: Int, val values: Array<String>): DialogueNode {
override fun toString(): String {
return "[label=\"item(${item}, \\\"${values.contentDeepToString()}\\\")\"]; @index -> @indexPlus;"
}
override fun handle(df: DialogueFile, componentID: Int, buttonID: Int, stage: Int): Int {
df.playerl(value)
df.interpreter!!.sendItemMessage(item, *values)
return stage + 1
}
}
class ClosureNode(val f: (Player) -> Int): DialogueNode {
class PlayerLNode(val expression: FacialExpression, val value: String): DialogueNode {
override fun toString(): String {
return "[label=\"playerl(FacialExpression.${expression.name}, \\\"${value}\\\")\"]; @index -> @indexPlus;"
}
override fun handle(df: DialogueFile, componentID: Int, buttonID: Int, stage: Int): Int {
return f(df.player!!)
df.playerl(expression, value)
return stage + 1
}
}
class PlayerNode(val expression: FacialExpression, val values: Array<String>): DialogueNode {
override fun toString(): String {
return "[label=\"player(FacialExpression.${expression.name}, \\\"${values.contentDeepToString()}\\\")\"]; @index -> @indexPlus;"
}
override fun handle(df: DialogueFile, componentID: Int, buttonID: Int, stage: Int): Int {
df.player(expression, *values)
return stage + 1
}
}
class BetweenStageNode(val f: (DialogueFile, Player, Int, Int) -> Unit): DialogueNode {
override fun toString(): String {
return "[label=\"betweenstage(${(f as java.lang.Object).getClass().getName()})\"]; @index -> @indexPlus"
}
override fun handle(df: DialogueFile, componentID: Int, buttonID: Int, stage: Int): Int {
df.stage = stage + 1 // Simulates moving to this stage.
f(df, df.player!!, componentID, buttonID) // Calls callback function.
df.handle(componentID, buttonID) // Handles the current stage
return stage + 2 // Skips over the current stage.
}
}
class ManualStageNode(val f: (DialogueFile, Player, Int, Int) -> Unit): DialogueNode {
override fun toString(): String {
return "[label=\"manualstage(${(f as java.lang.Object).getClass().getName()})\"]; @index -> @indexPlus"
}
override fun handle(df: DialogueFile, componentID: Int, buttonID: Int, stage: Int): Int {
f(df, df.player!!, componentID, buttonID)
return stage + 1
}
}
class ManualStageWithGotoNode(val f: (DialogueFile, Player, Int, Int, Int) -> Int, g: (Int) -> Int): DialogueNode {
override fun toString(): String {
return "[label=\"manualstagewithgoto(${(f as java.lang.Object).getClass().getName()})\"]; @index -> @indexPlus"
}
override fun handle(df: DialogueFile, componentID: Int, buttonID: Int, stage: Int): Int {
return f(df, df.player!!, componentID, buttonID, stage)
}
}
class PlaceholderNode(val dbf: DialogueBuilderFile, val clauseIndex: Int, var targetStage: Int): DialogueNode {
override fun toString(): String {
return "[label=\"placeholder(${targetStage})\"]; @index -> ${targetStage}"
}
override fun handle(df: DialogueFile, componentID: Int, buttonID: Int, stage: Int): Int {
df.stage = targetStage
df.handle(componentID, buttonID)
return df.stage
}
fun builder(): DialogueBuilder {
targetStage = dbf.data[clauseIndex].nodes.size
return DialogueBuilder(dbf, clauseIndex)
}
}
class GotoNode(val node: PlaceholderNode): DialogueNode {
override fun toString(): String {
return "[label=\"goto(${node.targetStage})\"]; @index -> ${node.targetStage}"
}
override fun handle(df: DialogueFile, componentID: Int, buttonID: Int, stage: Int): Int {
df.stage = node.targetStage
df.handle(componentID, buttonID)
return df.stage
}
}
class OptionEntry(val text: String, val nextStage: Int, val predicate: (Player) -> Boolean = { _ -> true }) {}
class OptionsData(val header: String, val entries: ArrayList<OptionEntry>, var attr: String? = null) {}
class OptionsNode(var options: ArrayList<OptionEntry>): DialogueNode {
class OptionsNode(var options: OptionsData): DialogueNode {
override fun toString(): String {
var ret = "[label=\"options(\\\"${options.header}\\\")\"]; "
for(entry in options.entries) {
ret += "@index -> ${entry.nextStage} [label=\"\\\"${entry.text}\\\"\"]; "
}
return ret
}
fun optionNames(player: Player): Array<String?> {
return options.asSequence().filter({ it.predicate(player) }).map({ it.text }).toList().toTypedArray()
return options.entries.asSequence().filter({ it.predicate(player) }).map({ it.text }).toList().toTypedArray()
}
override fun handle(df: DialogueFile, componentID: Int, buttonID: Int, stage: Int): Int {
val tmp: Array<String?> = optionNames(df.player!!)
if(tmp.size > 1) {
df.options(*tmp)
if(DEBUG_DIALOGUE) {
System.out.println("OptionsNode: ${tmp.size}")
for(i in 0 until tmp.size) {
System.out.println("tmp[${i}]: ${tmp[i]}")
}
}
if(tmp.size > 5) {
System.out.printf("Only a maximum of 5 options are supported by the interface")
return END_DIALOGUE
} else if(tmp.size > 1) {
df.interpreter!!.sendOptions(options.header, *tmp)
return stage + 1
} else if(tmp.size == 1) {
val tmp: List<OptionEntry> = options.asSequence().filter({ it.predicate(df.player!!) }).toList()
val tmp: List<OptionEntry> = options.entries.asSequence().filter({ it.predicate(df.player!!) }).toList()
df.stage = tmp[0].nextStage
df.handle(componentID, 0)
return df.stage
@@ -71,9 +203,18 @@ class OptionsNode(var options: ArrayList<OptionEntry>): DialogueNode {
}
}
}
class OptionsDispatchNode(var options: ArrayList<OptionEntry>): DialogueNode {
class OptionsDispatchNode(var options: OptionsData): DialogueNode {
override fun toString(): String {
return "[label=\"OptionsDispatchNode\"]"
}
override fun handle(df: DialogueFile, componentID: Int, buttonID: Int, stage: Int): Int {
val tmp: List<OptionEntry> = options.asSequence().filter({ it.predicate(df.player!!) }).toList()
val tmp: List<OptionEntry> = options.entries.asSequence().filter({ it.predicate(df.player!!) }).toList()
if(DEBUG_DIALOGUE) {
System.out.println("OptionsDispatchNode: ${tmp.size}")
}
if(options.attr != null) {
df.player!!.setAttribute(options.attr, buttonID-1)
}
df.stage = tmp[buttonID-1].nextStage
df.handle(componentID, 0)
return df.stage
@@ -90,19 +231,70 @@ class DialogueClause(val predicate: (player: Player) -> Boolean, val nodes: Arra
}
}
class DialogueOptionsBuilder(var target: DialogueBuilderFile, val clauseIndex: Int, var options: ArrayList<OptionEntry>) {
class DialogueOptionsBuilder(var target: DialogueBuilderFile, val clauseIndex: Int, var options: OptionsData) {
fun option(value: String): DialogueBuilder {
options.add(OptionEntry(value, target.data[clauseIndex].nodes.size))
options.entries.add(OptionEntry(value, target.data[clauseIndex].nodes.size))
return DialogueBuilder(target, clauseIndex)
}
fun optionIf(value: String, predicate: (Player) -> Boolean): DialogueBuilder {
options.add(OptionEntry(value, target.data[clauseIndex].nodes.size, predicate))
options.entries.add(OptionEntry(value, target.data[clauseIndex].nodes.size, predicate))
return DialogueBuilder(target, clauseIndex)
}
fun option_playerl(value: String): DialogueBuilder {
return option(value).playerl(value)
}
fun recordAttribute(name: String): DialogueOptionsBuilder {
options.attr = name
return this
}
}
class BranchesData(val branches: HashMap<Int, Int>, val f: (Player) -> Int) {}
class BranchNode(val branches: BranchesData): DialogueNode {
override fun toString(): String {
var ret = "[label=\"branch(\\\"${(branches.f as Object).getClass().getName()}\\\")\"]; "
for(entry in branches.branches) {
ret += "@index -> ${entry.value} [label=\"\\\"${entry.key}\\\"\"]; "
}
return ret
}
override fun handle(df: DialogueFile, componentID: Int, buttonID: Int, stage: Int): Int {
df.stage = branches.branches[branches.f(df.player!!)] ?: END_DIALOGUE
df.handle(componentID, buttonID)
return df.stage
}
}
class DialogueBranchBuilder(var target: DialogueBuilderFile, val clauseIndex: Int, var branches: BranchesData) {
fun onValue(value: Boolean): DialogueBuilder {
return onValue(if(value) { 1 } else { 0 })
}
fun onValue(value: Int): DialogueBuilder {
val index = target.data[clauseIndex].nodes.size
branches.branches.put(value, index)
return DialogueBuilder(target, clauseIndex)
}
}
class EndWithNode(val f: (DialogueFile, Player) -> Unit): DialogueNode {
override fun toString(): String {
return "[label=\"endWith(${(f as java.lang.Object).getClass().getName()})\"]";
}
override fun handle(df: DialogueFile, componentID: Int, buttonID: Int, stage: Int): Int {
f(df, df.player!!)
return END_DIALOGUE
}
}
class DialogueBuilder(var target: DialogueBuilderFile, var clauseIndex: Int = -1) {
companion object DialogueBuilderStatic {
@JvmStatic
fun endWithNoop(df: DialogueFile, player: Player) {
}
}
fun onPredicate(predicate: (player: Player) -> Boolean): DialogueBuilder {
target.data.add(DialogueClause(predicate, ArrayList()))
clauseIndex = target.data.size - 1
@@ -115,34 +307,104 @@ class DialogueBuilder(var target: DialogueBuilderFile, var clauseIndex: Int = -1
}
}
fun playerl(value: String): DialogueBuilder {
target.data[clauseIndex].nodes.add(PlayerLNode(value))
target.data[clauseIndex].nodes.add(PlayerLNode(FacialExpression.NEUTRAL, value))
return this
}
fun playerl(expression: FacialExpression, value: String): DialogueBuilder {
target.data[clauseIndex].nodes.add(PlayerLNode(expression, value))
return this
}
fun player(vararg values: String): DialogueBuilder {
target.data[clauseIndex].nodes.add(PlayerNode(FacialExpression.NEUTRAL, values as Array<String>))
return this
}
fun player(expression: FacialExpression, vararg values: String): DialogueBuilder {
target.data[clauseIndex].nodes.add(PlayerNode(expression, values as Array<String>))
return this
}
fun npcl(value: String): DialogueBuilder {
target.data[clauseIndex].nodes.add(NpcLNode(value))
target.data[clauseIndex].nodes.add(NpcLNode(FacialExpression.NEUTRAL, value))
return this
}
fun npcl(expression: FacialExpression, value: String): DialogueBuilder {
target.data[clauseIndex].nodes.add(NpcLNode(expression, value))
return this
}
fun npc(vararg values: String): DialogueBuilder {
target.data[clauseIndex].nodes.add(NpcNode(values as Array<String>))
target.data[clauseIndex].nodes.add(NpcNode(FacialExpression.NEUTRAL, values as Array<String>))
return this
}
fun endWith(f: (Player) -> Unit) {
target.data[clauseIndex].nodes.add(ClosureNode({ player ->
f(player)
return@ClosureNode END_DIALOGUE
}))
fun npc(expression: FacialExpression, vararg values: String): DialogueBuilder {
target.data[clauseIndex].nodes.add(NpcNode(expression, values as Array<String>))
return this
}
fun item(item: Int, vararg values: String): DialogueBuilder {
target.data[clauseIndex].nodes.add(ItemNode(item, values as Array<String>))
return this
}
fun iteml(item: Int, value: String): DialogueBuilder {
return item(item, *splitLines(value))
}
fun line(vararg values: String): DialogueBuilder {
return manualStage() { df, player, _, _ ->
df.interpreter!!.sendDialogue(*(values as Array<String>))
}
}
fun linel(value: String): DialogueBuilder {
return manualStage() { df, player, _, _ ->
df.interpreter!!.sendDialogue(*splitLines(value))
}
}
fun endWith(f: (DialogueFile, Player) -> Unit) {
target.data[clauseIndex].nodes.add(EndWithNode(f))
}
fun end() {
target.data[clauseIndex].nodes.add(ClosureNode({ _ ->
return@ClosureNode END_DIALOGUE
}))
target.data[clauseIndex].nodes.add(EndWithNode(::endWithNoop))
}
/** Runs block without the need for a DialogueFile df.something call. */
fun betweenStage(f: (DialogueFile, Player, Int, Int) -> Unit): DialogueBuilder {
target.data[clauseIndex].nodes.add(BetweenStageNode(f))
return this
}
fun manualStage(f: (DialogueFile, Player, Int, Int) -> Unit): DialogueBuilder {
target.data[clauseIndex].nodes.add(ManualStageNode(f))
return this
}
fun manualStageWithGoto(f: (DialogueFile, Player, Int, Int, Int) -> Int, g: (Int) -> Int): DialogueBuilder {
target.data[clauseIndex].nodes.add(ManualStageWithGotoNode(f, g))
return this
}
fun options(): DialogueOptionsBuilder {
var options: ArrayList<OptionEntry> = ArrayList()
val node = OptionsNode(options)
val dispatchNode = OptionsDispatchNode(options)
return options("Select an Option")
}
fun options(header: String): DialogueOptionsBuilder {
val options: ArrayList<OptionEntry> = ArrayList()
val optionsData = OptionsData(header, options)
val node = OptionsNode(optionsData)
val dispatchNode = OptionsDispatchNode(optionsData)
target.data[clauseIndex].nodes.add(node)
target.data[clauseIndex].nodes.add(dispatchNode)
return DialogueOptionsBuilder(target, clauseIndex, options)
return DialogueOptionsBuilder(target, clauseIndex, optionsData)
}
fun placeholder(): PlaceholderNode {
val node = PlaceholderNode(target, clauseIndex, END_DIALOGUE)
target.data[clauseIndex].nodes.add(node)
return node
}
fun goto(node: PlaceholderNode): DialogueBuilder {
target.data[clauseIndex].nodes.add(GotoNode(node))
return this
}
fun branch(f: (Player) -> Int): DialogueBranchBuilder {
var branches = BranchesData(HashMap(), f)
target.data[clauseIndex].nodes.add(BranchNode(branches))
return DialogueBranchBuilder(target, clauseIndex, branches)
}
fun branchBoolAttribute(attrName: String, defaultVal: Boolean): DialogueBranchBuilder {
return branch({ player -> return@branch if(player.getAttribute(attrName, defaultVal)) { 1 } else { 0 } })
}
}
@@ -21,6 +21,8 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static core.tools.DialogueConstKt.END_DIALOGUE;
@@ -323,13 +325,61 @@ public final class DialogueInterpreter {
* @param itemId The item id.
*/
public Component sendItemMessage(int itemId, String... messages) {
player.getInterfaceManager().openChatbox(131);
String message = messages[0];
for (int i = 1; i < messages.length; i++) {
message += "<br>" + messages[i];
if(1 <= messages.length && messages.length < 4) {
ArrayList<String> packedMessages = new ArrayList();
for(int i = 0; i < messages.length/2; i++) {
packedMessages.add(messages[i] + "<br>" + messages[i+1]);
}
if(messages.length % 2 == 1) {
packedMessages.add(messages[messages.length-1]);
}
int interfaceId = 241 + (packedMessages.size() - 1);
player.getInterfaceManager().openChatbox(interfaceId);
player.getPacketDispatch().sendItemOnInterface(itemId, 1, interfaceId, 1);
ItemDefinition itemDef = ItemDefinition.forId(itemId);
player.getPacketDispatch().sendAngleOnInterface(interfaceId, 1, itemDef.getModelZoom() / 2, itemDef.getModelRotationX(), itemDef.getModelRotationY());
player.getPacketDispatch().sendString("", interfaceId, 3);
for(int i = 0; i < packedMessages.size(); i++) {
//System.out.printf("sendItemMessage[%d]: %s\n", i, packedMessages[i]);
player.getPacketDispatch().sendString(packedMessages.get(i), interfaceId, 4+i);
}
} else {
int interfaceId = 131;
//int interfaceId = 173;
//int interfaceId = 519;
//int interfaceId = 757;
//int interfaceId = 760;
player.getInterfaceManager().openChatbox(interfaceId);
String message = messages[0];
for (int i = 1; i < messages.length; i++) {
message += "<br>" + messages[i];
}
switch(interfaceId) {
case 131:
player.getPacketDispatch().sendString(message, 131, 1);
player.getPacketDispatch().sendItemOnInterface(itemId, 1, 131, 2);
break;
case 173:
player.getPacketDispatch().sendString(message, 173, 4);
player.getPacketDispatch().sendString("", 173, 3);
player.getPacketDispatch().sendItemOnInterface(itemId, 1, 173, 1);
break;
case 519:
player.getPacketDispatch().sendString(message, 519, 1);
player.getPacketDispatch().sendItemOnInterface(itemId, 1, 519, 0);
break;
case 757:
player.getPacketDispatch().sendString(message, 757, 2);
player.getPacketDispatch().sendString("", 757, 1);
player.getPacketDispatch().sendItemOnInterface(itemId, 1, 757, 0);
break;
case 760:
player.getPacketDispatch().sendString(message, 760, 0);
player.getPacketDispatch().sendItemOnInterface(itemId, 1, 760, 1);
break;
}
}
player.getPacketDispatch().sendString(message, 131, 1);
player.getPacketDispatch().sendItemOnInterface(itemId, 1, 131, 2);
return player.getInterfaceManager().getChatbox();
}
@@ -337,14 +387,7 @@ public final class DialogueInterpreter {
* Send a message with an item next to it.
*/
public Component sendItemMessage(final Item item, String... messages) {
player.getInterfaceManager().openChatbox(131);
String message = messages[0];
for (int i = 1; i < messages.length; i++) {
message += "<br>" + messages[i];
}
player.getPacketDispatch().sendString(message, 131, 1);
player.getPacketDispatch().sendItemOnInterface(item.getId(), item.getAmount(), 131, 2);
return player.getInterfaceManager().getChatbox();
return sendItemMessage(item.getId(), messages);
}
/**
@@ -455,6 +498,19 @@ public final class DialogueInterpreter {
return sendDialogues(npcId, expression == null ? -1 : expression.getAnimationId(), messages);
}
static Pattern GENDERED_SUBSTITUTION = Pattern.compile("@g\\[([^,]*),([^\\]]*)\\]");
public static String doSubstitutions(Player player, String msg) {
msg = msg.replace("@name", player.getUsername());
StringBuilder sb = new StringBuilder();
Matcher m = GENDERED_SUBSTITUTION.matcher(msg);
int index = player.isMale() ? 1 : 2;
while(m.find()) {
m.appendReplacement(sb, m.group(index));
}
m.appendTail(sb);
return sb.toString();
}
/**
* Send dialogues based on the amount of specified messages.
* @param npcId The npc id.
@@ -474,6 +530,7 @@ public final class DialogueInterpreter {
}
player.getPacketDispatch().sendAnimationInterface(expression, interfaceId, 2);
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 {
@@ -481,7 +538,7 @@ public final class DialogueInterpreter {
player.getPacketDispatch().sendString(player.getUsername(), interfaceId, 3);
}
for (int i = 0; i < messages.length; i++) {
player.getPacketDispatch().sendString(messages[i].toString().replace("@name", player.getUsername()), interfaceId, (i + 4));
player.getPacketDispatch().sendString(doSubstitutions(player, messages[i].toString()), interfaceId, (i + 4));
}
player.getInterfaceManager().openChatbox(interfaceId);
player.getPacketDispatch().sendInterfaceConfig(player.getInterfaceManager().getChatbox().getId(), 3, false);
@@ -4,9 +4,11 @@ package core.game.dialogue
* Topic/IfTopic system backported from my personal project
* @author Ceikry
*/
open class Topic<T>(val expr: FacialExpression, val text: String, val toStage: T, val skipPlayer: Boolean = false) {
open class Topic<T> @JvmOverloads constructor(val expr: FacialExpression, val text: String, val toStage: T, val skipPlayer: Boolean = false) {
@JvmOverloads
constructor(text: String, toStage: T, skipPlayer: Boolean = false) : this(FacialExpression.ASKING, text, toStage, skipPlayer)
}
class IfTopic<T>(expr: FacialExpression, text: String, toStage: T, val showCondition: Boolean, skipPlayer: Boolean = false) : Topic<T>(expr, text, toStage, skipPlayer) {
constructor(text: String, toStage: T, showCondition: Boolean, skipPlayer: Boolean = false) : this(FacialExpression.ASKING, text, toStage, showCondition, skipPlayer)
}
class IfTopic<T> @JvmOverloads constructor(expr: FacialExpression, text: String, toStage: T, val showCondition: Boolean, skipPlayer: Boolean = false) : Topic<T>(expr, text, toStage, skipPlayer) {
@JvmOverloads
constructor(text: String, toStage: T, showCondition: Boolean, skipPlayer: Boolean = false) : this(core.game.dialogue.FacialExpression.ASKING, text, toStage, showCondition, skipPlayer)
}
@@ -145,6 +145,12 @@ public abstract class Quest implements Plugin<Object> {
playJingle(player, questJingles[new Random().nextInt(3)]);
}
/**
* Resets the quest. This is called when ::setQuestStage is set to 0.
* Useful to override and reset quest player attributes.
*/
public void reset(Player player) {}
/**
* Draws a line on the journal component.
* @param player The player.
@@ -35,8 +35,13 @@ class QuestCommandSet : CommandSet(Privilege.ADMIN){
}
val quest = args[1].toIntOrNull() ?: reject(player,"INVALID QUEST")
val stage = args[2].toIntOrNull() ?: reject(player,"INVALID STAGE")
player.questRepository.setStageNonmonotonic(player.questRepository.forIndex(quest as Int), stage as Int)
notify(player, "<col=209dff>Setting " + player.questRepository.forIndex(quest).name + " to stage $stage</col>")
val questObject = player.questRepository.forIndex(quest as Int)
player.questRepository.setStageNonmonotonic(questObject, stage as Int)
if (stage == 0){
questObject.reset(player)
}
questObject.updateVarps(player)
notify(player, "<col=209dff>Setting " + questObject.name + " to stage $stage</col>")
}
/**
@@ -77,7 +77,7 @@ public final class PacketRepository {
OUTGOING_PACKETS.put(Varbit.class, new Varbit());
OUTGOING_PACKETS.put(ResetInterface.class, new ResetInterface());
OUTGOING_PACKETS.put(VarcUpdate.class, new VarcUpdate());
OUTGOING_PACKETS.put(InterfaceSetAngle.class, new InterfaceSetAngle());
OUTGOING_PACKETS.put(InterfaceSetAngle.class, new InterfaceSetAngle());
}
/**