2010-11-22

How did they do it? - Al Bhed

I am introducing a new series I call “How did they do that?” Basically what is going to happen here is I am going to tackle some...odd, interesting or complicating aspects from different games. I will explain what it is and I will use examples on where it is used and attempt to mimic it.

Note: This will be based on mechanics, for example, stats, formulas, stuff like that. So don’t expect something outrageous such as importing models or special effects.

Note: A code sample is attached at the bottom of the article. I wouldn’t want people to use all their brain power trying to understand my theory and translating it to code when there is a downloadable available. I will try to put all the stuff in classes. That way, you don’t have to know the code or even know how it works. You just have to know how to use it. However, reading it will be an interesting learning experience.

The first article will be on Al Bhed.

Al What?
Al Bhed, it is a fictional language used in Final Fantasy X (FFX) and FFX-2. What happens is there is another language, obviously which you do not understand. The minigame is that you have the opportunity to find these “letters” throughout the game. The more you find, the more you understand. If you want to know more about this, go here. Each letter is represented by another character.

Simple concept right?

Stuff to note:
This is important if you want to make a new language. The words have to be pronounceable. For example, if you say “Hello” in English it turns out as “Rammu” in Al Bhed. It is pronounceable. There is a simple reason for that. You will notice that the vowels, and Y, is mixed with each other. This ensures that all words that are pronounceable in English is pronounceable in Al Bhed.

So How does it work?
Obviously I can’t tell you how Square Enix did it simply because I do not know. I do however have a method that you can use.

#1. Create an array with space for 26 characters. It will represent the letters a to z. It should be a Boolean so that you can simply check true or false.

Why?
When we come to a later part of the code, you will have to check if the character has received the letter. Otherwise the code will blindly convert to Al Bhed without caring if you know the letter or not.

#2. Make a function to modify the above array to a true/false.

Why?
Same as above, if you do not ever check that they indeed do have the letter, the code will convert without taking the collected letters into consideration.

#3. Make a function to convert each individual letter from English to Al Bhed.

Why?
Obviously to translate the letters.

Why only one way?
You only need it one way. It only has to be translated to one language. If you want to do it both ways by all means. It just makes more sense for the programmer to type in the message in English and have it converted to Al Bhed.

Why each individual letter? Why not just use a replace function?
The problem when converting all the letters using a replace function is that you have less control over it. That’s not the big problem. Consider the string below.

Hello, I am converting text.

Suppose you convert this to Al Bhed using a replace function. You start by converting all the a’s:
Hello, I ym converting text.

Everything is still fine. Now you get to the e’s:
Hallo I ym convarting taxt.

Everything is still fine. Now you continue this until you get to the I’s:
Hallo e ym convarteng taxt.

Perfect. Now you get to the O’s:
Hallo e ym cunvarteng taxt.

Still great. This is where the problem comes in. Now you go down the alphabet converting everything, now you are with the U’s.
Hallo e ym cinvarteng taxt.

Something isn’t right here. The original text does not have U’s, but because the converted text, from O’s, created a U, the text converted the already converted U. So in the end, you have an inaccurate translation. This is even worse with the consonants. That is why you convert the word one letter at a time, from left to right.

#4. Go through the string, checking letters one by one, converting them provided the array in #1 representing the current letter is set to true.

Why?
The idea is that the words should not make sense. Only “obtained” letters should be translated. That way, the more letters they get the more they understand. If the array value returns false, make the PC show Al Bhed, if it return true, make it show the English translation. So if only certain letters are found, only certain pieces of a word would be in English.

Eg. When translating “Hello”, but you only have the “H” and the “L” letters, the word should be displayed like so:
Hallu
Usually the letters you have are displayed in a different color.
So, if the user has the letter, simply don’t convert it.

#5. Return the converted string.

Why?
How else are the people suppose to read the converted string?

Problems you will face
If you just blindly convert everything you will run into problems.
If I want to convert this:

Hey! Zappy77! Watch out for Pinky! My pet mouse!

Problem #1: You will not display the punctuation, so have to make the computer check for it.

Solution:
My method is simple, if the letter is not in the list, simply write the input letter. That way you don’t have to check for a “!”, a “,”, etc.

Problem #2: If you are like me, you probably would code the engine to search for letters from A – Z, all in capital letters. You will not specify the lower case letters. If that is the case, the lower case letters will not be converted.

Solution:
Convert the inputted letter to uppercase before processing.

Problem #3:
Assuming you had Problem #2, the solution will create another problem. When the string is returned, the whole string will be in uppercase, which put a little more strain on the readers eyes. This is not good.

Solution:
Simple really, before you add it to the main string, check from the buffer if it was originally upper or lower case. If it was lower case, simply convert to lower case. If it was upper case, simply add it to the string.

Problem #4:
If you convert the above string, the output would be:
Rao! Wybbo77! Fydlr uid vun Behgo! So bad suica!
That’s bad! Why? Zappy77 and Pinky are proper nouns. Meaning they are names. You cannot convert names, that would be stupid. Nobody will know who they are referring to.

If there is a place called “Death Cage”, would you want the player to know “Death Cage” (Which is a name) or should they read: “Taydr Lyka” and not know what the places names are?

Solution:

I wrote a simple text parser. What I do is if I don’t want a part converted, I simply put [square brackets] around it. The script will then ignore the conversion words between square brackets and simply remove the square brackets.

If you cannot write a function like this yourself, simply refer to my included source code, or study this sample extracted from my source:

a = modifier.find("[");
b = modifier.find("]");

    for (i=0;i <= len ;i++)
    {
        if (i >= a && i <= b)
        {
            if (buffer[i] != '[' && buffer[i] != ']')
            {
                albhed += buffer[i];
                continue;
            }
            else
            {   
                continue;
            }
        }

        if (i>a)
        {
            a = modifier.find("[",i-1);
        }

        if (i>b)
        {
            b = modifier.find("]",i+1);
        }
...

This obviously makes more sense in the code itself.
Anyway, you can find the source as well an example of using the code here.

So that’s it for the first article of the series of “How did they do it?”. If you find any bugs in the code, please notify me. This is a full blown Al Bhed engine, but might have 1 or 2 bugs. I wrote this code in about an hour so don’t expect it to be perfect.

No comments:

Post a Comment