This script implements the same concept as the MUCK version by Verin: spoofed ambient ‘noises’ triggered by chance based on user activity, output after a certain sleep period, and not occurring again 'til after a specified delay. The initial motivation was to import an area I had created on SpinDizzy with such noises; I’m now rolling it out over the Academy as well.
If you use it in your areas, I’d be interested in hearing about it! I’d suggest keeping chance of triggering low (~1/50-250) and delay (180+) and number of noises high, at least in busy rooms. It’s easy for them to get repetitive in a high-traffic area without sufficient variety.
AssemblyScript obviously differs from the stack-based MUF; and Wolfery has no list management library, so I had to implement my own list based around storage primitives.
A few areas of interest:
const FORM_FEED = String.fromCodePoint(0xC)
let noises = noisesString.split(FORM_FEED)
The list is stored as a form-feed-delimited string. I considered other newline-equivalent markers (5.8), including Unicode-specific line and paragraph separators; I wanted noises to be able to extend over multiple lines and paragraphs, so couldn’t use something present in such input. FF also has the advantage of taking a single byte in UTF-8, used for storage.
In use, the string must be split to an array. For listing it’s handed to Array.reduce(), that takes a function to call with each element to produce an indexed, newline-delimited string:
function reduceList(acc: string, cur: string, index: i32, self: Array<string>) : string {
return acc += '\n' + index.toString() + ': ' + cur
}
Normally (in Java/TypeScript), this might be implemented as an anonymous function, and this is what I tried to start with, however it results in a closure which is not yet implemented.
Spoofs are limited to ~2000 characters, insufficient to display some long lists, so we search backwards for a newline from each 2000-character block in the display string and split the preceding data to output as a separate chunk.
let noises = noisesString.split(FORM_FEED)
let list = 'noises: ' + noises.length.toString() + ' in list:' // + noisesString
// Handle lists > ~2000 char describe limit
let toPrint = noises.reduce<string>(reduceList, list)
for (let len = toPrint.length; len > 2000; len = toPrint.length) {
let cutAt = toPrint.lastIndexOf('\n', 2000)
Room.describe(toPrint.slice(0, cutAt))
toPrint = toPrint.slice(cutAt + 1)
}
Room.describe(toPrint)
Conveniently, the maximum length of a single noise is also 2000 characters, due to the input limit. The total list can reach ~20,000 chars before listing runs into the 512kB memory limit.
Obviously, you don’t want anyone changing your configuration. Sometimes, though, it’s convenient to have a puppet do it when your main character is elsewhere. The puppeteer needs to be tested for specifically to permit this, as they cannot edit the room in question:
const ooc = JSON.parse<Event.OOC>(ev)
[…]
const puppeteer = ooc.puppeteer
if (Room.canEdit(ooc.char.id) || (puppeteer && Room.canEdit(puppeteer.id))) {
[…]
} else {
Room.describe('noises: Character [puppeteer] must be room owner')
}
Ideally it’d be possible to install this script area-wide, but as yet there’s no support for this, nor for instance rooms. There are various possible expansions - placeholder support to mention a random character or exit; noises that trigger only at certain times of the day or year; links to entry or exit. Some may require multiple lists, or a more sophisticated data structure. There could even be a central noise repository based on message passing. You’re welcome to use the existing code to try to achieve these, in accordance with the license.