Implemented auto splitting of excessively long dialogue lines

Many new farming-related player messages added, and some existing messages updated
Raking animation updated
Herb picking animation updated
Digging up farming patch animation updated
Plant cure animation updated
A scarecrow can be retrieved from a flower patch by digging it up with a spade
Picking fruit/berries stops when running out of inventory space
The player can no longer dig up a tree they have planted before chopping it down
This commit is contained in:
zsrv
2024-02-14 11:33:13 +00:00
committed by Ryan
parent 38c50c465d
commit 1d12dd741f
23 changed files with 728 additions and 520 deletions
+6 -1
View File
@@ -767,10 +767,15 @@ fun emote(entity: Entity, emote: Emotes) {
/**
* Sends a message to the given player.
*
* The message will be split on word boundaries into multiple lines so
* that none of the lines will overflow the player's message box.
*
* @param player the player to send the message to.
* @param message the message to send.
*/
fun sendMessage(player: Player, message: String) {
player.sendMessage(message)
player.sendMessages(*splitLines(message, 86))
}
/**
+38 -6
View File
@@ -2,12 +2,20 @@ package core.api
import java.util.*
import kotlin.math.ceil
object DialUtils {
val tagRegex = "<([A-Za-z0-9=/]+)>".toRegex()
fun removeMatches(message: String, regex: Regex): String {
return regex.replace(message, "")
}
}
/**
* Automatically split a single continuous string into multiple comma-separated lines.
* Should this not work out for any reason, you should fallback to standard npc and player methods for dialogue.
*/
fun splitLines(message: String, perLineLimit: Int = 54) : Array<String> {
var lines = Array(ceil(message.length / perLineLimit.toFloat()).toInt()) {""}
fun splitLines(message: String, perLineLimit: Int = 54): Array<String> {
var lines = Array(ceil(DialUtils.removeMatches(message, DialUtils.tagRegex).length / perLineLimit.toFloat()).toInt()) { "" }
//short circuit when possible because it's cheaper.
if (lines.size == 1) {
@@ -20,8 +28,28 @@ fun splitLines(message: String, perLineLimit: Int = 54) : Array<String> {
val line = StringBuilder()
var accumulator = 0
val openTags = LinkedList<String>()
fun pushLine() {
if (line.isEmpty()) return
// find all tags that were opened or closed in the line
for (lineTag in DialUtils.tagRegex.findAll(line)) {
if (lineTag.value.get(1) == '/') {
// closing tag encountered; remove it from the list of open tags
for (openTag in openTags.descendingIterator()) {
val lineTagName = lineTag.value.substring(2, lineTag.value.length - 1)
val openTagName = openTag.substring(1, lineTag.value.length - 2)
if (lineTagName == openTagName) {
openTags.remove(openTag)
break
}
}
} else {
openTags.add(lineTag.value)
}
}
//allow array to be resized - there are specific edgecases where it becomes necessary. (Check the unit test for example)
if (lines.size == index)
lines = lines.plus(line.toString())
@@ -30,11 +58,15 @@ fun splitLines(message: String, perLineLimit: Int = 54) : Array<String> {
index++
line.clear()
accumulator = 0
// if any unclosed tags remain, add them to the beginning of the new line
for (tag in openTags) line.append(tag)
openTags.clear()
}
while (!tokenQueue.isEmpty()) {
val shouldSpace = line.isNotEmpty()
accumulator += tokenQueue.peek().length
val shouldSpace = DialUtils.removeMatches(line.toString(), DialUtils.tagRegex).isNotEmpty()
accumulator += DialUtils.removeMatches(tokenQueue.peek(), DialUtils.tagRegex).length
if (shouldSpace) accumulator += 1
if (accumulator > perLineLimit) {
@@ -49,10 +81,10 @@ fun splitLines(message: String, perLineLimit: Int = 54) : Array<String> {
pushLine()
// If there's 5 lines, merge lines 4 and 5 into line 4.
if (lines.size > 4){
if (lines.size > 4) {
lines[3] = lines[3] + "<br>" + lines[4]
lines = lines.sliceArray(0..3)
}
return lines
}
}