Roll20 uses cookies to improve your experience on our site. Cookies enable you to enjoy certain features, social sharing functionality, and tailor message and display ads to your interests on our site and others. They also help us understand how our site is being used. By continuing to use our site, you consent to our use of cookies. Update your cookie preferences .
×
Create a free account

[script] Al Bhed style language cipher script

January 20 (3 years ago)

Edited January 20 (3 years ago)
Quinn
Pro
Sheet Author

This is an idea I had for games where the party encounters a culture that speaks an unfamiliar language. In Final Fantasy X, the Al Bhed language is a cipher of English, and there's 26 translation tomes, each of which reveals the cipher for one letter of Al Bhed - so if you get the translation tomes for O and U, then the Al Bhed word 'Oui' now displays as 'Yoi', and the player realizes that 'Oui' probably means 'You'. It's a cool system, so I was like, why not make a script to do this in Roll20?

Usage:

  • !generate Elvish = Generate a new language cipher for Elvish.
  • !say Elvish "Hello, strangers!" = Says "Hello, strangers!", but shuffled into the Elvish cipher.
  • !say Elvish "Hello, !Legolas, my old friend!" = The "!" before Legolas marks it as a proper noun, so it won't be encoded.
  • !learn Elvish = Increases Elvish knowledge for the party by 1. Knowledge goes from 0 to 26; each point of knowledge for a language reveals one letter, which will appear in orange in in Elvish dialogue. 
  • !learn Elvish 10 = sets Elvish knowledge directly to 10.

Configurable points:

  • Enable/disable script completely
  • Change the color of translated letters
  • Allow multiple languages, or simplify commands by just having one language
  • Toggle shuffling vowels exclusively with other vowels, which makes a more pronounceable cipher
  • Redefining the alphabet of characters, theoretically allowing for this to be used in other alphabetic languages

Whenever a language cipher message is sent, a translated copy is whispered to the GM.

Script here - it's still a work in progress. I haven't tested it too thoroughly, and I want to add a feature that lets specific players know a language natively, which would make all messages in that language be whispered to that player in English. Open to thoughts for other feature ideas.

January 20 (3 years ago)
timmaugh
Forum Champion
API Scripter

First, that's an awesome idea for a script.

Some people use tokens (or is it characters?) to represent languages, so that if a player is granted control over that token (representing a language), they will receive the whispers to that token (ie, what is said in that language)... but this gives a bit of nuance to the conveyed message.

Given that you have that kind of nuance, I would almost want to see a per-character attribute to track that character's knowledge. Or, if characters were working together you could have a neat effect if ciphers 1-26 were gained in a non-consistent order. One player with a 4 in Elvish could have the letters a-d, while another character with a 2 could have b & e. All together, if those characters were working together, you'd have a-e, and understand more of the message.

You'd have to probably build a string of characters that each character can translate (generated randomly from the characters they still have to learn when it comes time to level up the skill) and house that in an attribute, then when it comes time to translate choose all of the characters that are working on it and pool their lists.

January 20 (3 years ago)

Edited January 20 (3 years ago)
Quinn
Pro
Sheet Author

I can see a couple different ways that would work... things could get complicated fast.

Option 1: The fully-ciphered message is sent to main chat, and versions translated to different extends are whispered to each player with language knowledge. Downside: It gives players few tools for pooling their knowledge to understand the language better, since each one only sees their own version.

Option 2: The message is sent to main chat, with all letters known to any players present translated. Downside: How does roll20 know what players are present for a scene? Do you have to list them all out every time?

Either way, it adds an extra layer of complexity to the interface, but I can see the advantages.


January 20 (3 years ago)
timmaugh
Forum Champion
API Scripter

I can totally see the concern over it getting overly complicated, so really this is just talking out ideas that may or may not work. You already have a cool script; you don't want to bog that down with an inelegant implementation.

One solution I could see is to share the message to each party member with their character's personal ability taken into account (so a partially translated message), letting them opt into a shared translation, and then having the GM re-issue the translated statement.

When the GM issues the original statement, generate a UUID for the message and track it in the state:

dispatchedCiphers: {
    UUID: { //generated when the object is added
        text: 'Original message text here.',
        contributors: {             -M1234567890abcdef: {active: true, ciphers: ['a', 'c']},             -Mabcdef1234567890: {active: true, ciphers: ['c', 'f', 'g']}
    }, ...

Then issue a message to the players that has a "contribute to the shared translation of this statement" button:

Then encode each button sent to the characters to use the generated UUID for that message and write the cipher abilities to that specific cipher message in the state. That's something like...

state[scriptHandle].dispatchedCiphers[UUID].contributors[characterID] = {active: true, ciphers: (elvishSkill || [])};
ciphers = [...new Set([...ciphers,...charCiphers])];

Meanwhile, the GM's message has 2 buttons -- one to "re-issue" the translated statement, and one to bring up a menu of characters contributing to the translation effort. After all of the characters have opted in (if they're going to contribute), the GM clicks one of those buttons. The menu of contributing characters would show a button for each contributing character, allowing the GM to "deactivate" the contribution from that character (maybe the player clicked the button inadvertently, or maybe their character got knocked unconscious in the meantime).

At some point, everyone has contributed to the message translation who is going to contribute, the GM has ruled out anyone ineligible, and you have a set of contributors in the UUID who are active. Filter than on "active: true", map or reduce it to be the ciphers property, and get a unique set from those:

let contributors = state[scriptHandle].dispatchedCiphers[UUID].contributors.filter(c => c.active);
let ciphers = contributors.reduce((m,c) => [...new Set([...m, ...c.ciphers])],[]);

That's air-coded, but I think that's right.

Anyway, up to you whether the juice is worth the squeeze... that might be more complexity than you want to add. Either way, cool idea!

January 20 (3 years ago)
Quinn
Pro
Sheet Author

Definitely a lot of interesting ideas! But I think that for me, the juice, as you say, doesn't quite hold up to the squeeze, especially in terms of how fiddly it becomes for the users. When I've got all the features I want done, I'll put it on github and people can go hog wild with it.