tango.zh Version 1.0.0 ================ Overview ================ This is just a quick overview of all the stuff below - a simple, high-level explanation of how Tango works. If you want to try it out without learning all the details, you can use tangoQuickStart.zh. It provides a minimal global script and a couple of simple functions. There are a few constants to set for colors, combos, and sounds; the defaults are okay for the classic tileset. To display strings, there are two concepts you need to deal with: text slots and styles. If you're familiar with other programming languages, these are comparable to structs or classes. There are a fixed (but customizable) number of them, and they're identified by integers. A text slot consists of text, a style reference, and some internal data. You can create different types to control drawing order and how much space is alloted, but they're fundamentally all the same. A style is just a collection of settings - the size and color of the text, the sound to play as it's printing, and so forth. These are mostly cosmetic settings, but there are also a few behavioral flags. These control whether the text can be sped up by holding a button, whether the screen is frozen while it's displayed, and some other things. Tango also provides a simple scripting language that can be embedded in strings. This allows you to control what text is displayed and how, create menus, or even make messages run arbitrary ZScript functions. ================ Basic usage ================ There are three functions that need to be added to the active global script. Tango_Start() should be called before the main loop, Tango_Update1() in the main loop before Waitdraw(), and Tango_Update2() in the main loop after Waitdraw(). It is recommended that Tango_Update1() be called before any other funcions so that buttons can be unpressed as soon as possible. Tango_Update2() should generally come after everything else that does any drawing, since one normally wants message windows drawn on top of everything else. At least one style must be set up. This can be done once per quest or on demand. Setting up a style simply involves repeated calls to Tango_SetStyleAttribute(). Displaying text on the screen requires six steps: 1: Find a free text slot (Tango_GetFreeSlot()) 2: Clear any data already in the slot (Tango_ClearSlot()) 3: Load text into the slot (Tango_LoadString() or Tango_LoadMessage()) 4: Set a style (Tango_SetSlotStyle()) 5: Set the position (Tango_SetSlotPosition()) 6: Activate the text slot (Tango_ActivateSlot()) Displaying a menu from a script takes four or five steps: 1: Initialize menu data (Tango_InitializeMenu()) 2: Add choices (Tango_AddChoice()) 3: Set the cursor's appearance (Tango_SetMenuCursor()) 4: (optional) Set the menu sound effects (Tango_SetMenuSFX()) 5: Activate the menu (Tango_ActivateMenu()) ================ Text slots ================ Tango has a number of "text slots" where text and associated data are stored. Before any text can be displayed on the screen, it must be loaded into a slot, and the slot must have a style set. Slots are numbered 0 to __TANGO_NUM_SLOTS-1. Text slots are defined in __Tango_SlotDefs[]. The slot definition defines where in the buffer text is stored and where it's rendered on the offscreen bitmap. It is permissible for slots to overlap in both the buffer and the bitmap, but be careful about this; using overlapping slots simultaneously is likely to cause problems. There are three reasons you might use different slot types. 1: Ordering Text slots are drawn to the screen in the order they're defined in __Tango_SlotDefs[]. That means later slots will appear on top of earlier ones. If there's a string that should always appear on top of any others, you can define a slot type that's only used by the last slot. 2: Reservation There are a limited number of text slots available. If you display several strings at once, you could run into a situation where you want to display another but have no free slots for it. If there's something you always want to be able to show, create a slot type just for that, and you can be sure it will be available when you need it. 3: Efficiency Using different slot types lets you divide up __Tango_Buffer[] efficiently. It may be that you want to display one or two long strings at a time along with a lot of small strings. Creating separate slot types for long and short strings lets you do this without wasting a lot of space in the buffer. The intention is that all slots of a given type will use the same amount of space in the buffer and the bitmap, but this is not enforced. There's no obvious reason to make slots of the same type different, but you can if you like. There are two slots and one slot type defined by default. This should be plenty for most quests, but you can add as many slots and types as you like. Slot type IDs should be 0 or greater. To control the number of slots, set __TANGO_NUM_SLOTS, set the size of __Tango_SlotData[], and add definitions to __Tango_SlotDefs[]. You may also want to set the size of __Tango_Buffer[] to control the amount of space available for text. ================ Fonts ================ Tango can't use ZC's built-in fonts directly; it needs additional data about spacing to position everything correctly. Tango font definitions are arrays that provide the necessary information. Definitions for most built-in fonts are included, but they're not imported by default. The files are in the tango/font directory. Although they aren't constants (since ZScript doesn't allow constant arrays), the names are written in all caps to indicate that they should be used as though they were. You can create your own fonts, too. Using characters made from tiles, you can extend built-in fonts with additional characters or create completely original ones. The drawback of tile-based characters is that they have fewer color options; they only have a CSet, not a CSet and a color. On the other hand, tile-based characters can use multiple colors, and they can even be 8-bit. If you want to create a font, see the font format section of tango.txt for details. ================ Styles ================ Before any text can be displayed, the slot must have a style set. The style defines how the text will be displayed - the font, the backdrop, the sound effects, and so forth. Style IDs are integers 0 and up. Use Tango_SetStyleAttribute() to set each style attribute. You must at least set the font and color; every other setting has a valid default. The attributes and expected values are listed in the style attributes section of tango.txt. To control the number of styles available, set __TANGO_NUM_STYLES and the size of __Tango_Styles[]. ================ Tango code ================ Tango implements a simple scripting language with functions embedded in strings. Code is identified by the character '@' (by default; set __TANGO_CODE_DELIMITER to change this). @ is followed immediately by a function name, then up to two arguments in parentheses, separated by spaces. Parentheses are needed even if a function takes no arguments. For example, the string "@playsfx(64)Hello, @savename()!" would play sound 64 and print (possibly) "Hello, Link!" Variables are also available. These can be used to set the properties of the text. For instance, @speed controls how quickly the text is drawn. Each slot has two variables, @a0 and @a1, used to store arbitrary data or communicate with ZScript. You can also create your own variables for the same purposes. It's also possible to use @## or @(##)to insert a character directly into the text. The string "@90@69@76@68@65" would be printed as "ZELDA" This is useful for inserting line breaks (@26) and font characters beyond the ASCII range. Also, @0 can be used to terminate the text early; anything after @0 won't be printed. ================ Extending Tango code ================ It's possible to create your own variables and functions. The name of the new function or variable must be a series of lower-case letters and numbers, and the first character must be a letter. There's no set limit on length, but the name must convert to a number small enough to be represented in ZScript (no greater than 214747.9999). The name of the function or variable needs to be converted to a number. Tango_ConvertFunctionName() and Tango_ConvertVariableName() will do this for you; they'll even write the result to allegro.log in a form suitable to copy and paste directly into a script. If you'd rather do the math yourself, see the section titled "identifier conversion" in tango.txt. User-defined functions can be numeric, effect, or condition functions. To make Tango handle a function, add the implementation to __Tango_RunCustomFunction(). The function argument is the function ID. args is an array containing the arguments. A function can take up to four arguments; any unused arguments will be 0. For debugging purposes, you may want to call Tango_LogUndefinedFunction() if the function is not recognized. A simple example: const float FUNC_DOSTUFF2 = 543.3828; // @dostuff2() float __Tango_RunCustomFunction(float function, float args) { if(function==FUNC_DOSTUFF2) { // This will just return the sum of the arguments. return args[0]+args[1]; } else { // Unknown function Tango_LogUndefinedFunction(function); } return 0; } To implement a variable, use Tango_GetCustomVar() and Tango_SetCustomVar(). The var argument is the variable id. A trivial example of a custom variable: int myVar; const float VAR_MYVAR = 4.0891; // @myvar float Tango_GetCustomVar(int var) { if(var==VAR_MYVAR) return myVar; else // Unknown { Tango_LogInvalidVariable(var); return 0; } } void Tango_SetCustomVar(int var, float value) { if(var==VAR_MYVAR) myVar=value; else // Unknown Tango_LogInvalidVariable(var); } Note that it's possible, although very unlikely, for two function or variable names to convert to the same number. In that case, you'll just have to rename one of them. It's okay for a variable and a function to have the same name. ================ String control codes ================ String control codes are supported only in ZC messages, not ZScript strings. They're disabled by default. To enable them, import stringControlCode.zh instead of stringControlCodeDisabled.zh. Control codes cannot be mixed with Tango code. Something like \20\@rand(61, 63) or @if(@a0 \16\6) will not work. Note that codes 16 and 17 (add or remove item) don't work quite the same as they normally do. The item is simply added to or removed from the inventory; no changes are made to any counters. ================ Warnings ================ Although Tango performs a lot of input validation, catching every problem is not feasible. Some errors can hang or crash the game, so be prepared for that when making changes. Text is drawn into offscreen bitmaps one character at a time, even when an entire string is drawn at once. Using TANGO_FLAG_INSTANTANEOUS with long strings will push you significantly closer to the drawing limit.