// tango.zh
// Beta 2


// __Tango_Data[] indices
// Skip 0-6 for current slot data (__TCS constants)
const int __TDIDX_GLOBAL_FLAGS         = 7;
const int __TDIDX_PREV_SCREEN          = 8;
const int __TDIDX_LAST_CHOICE          = 9;
const int __TDIDX_CONDITION_MET        = 10;
const int __TDIDX_SCREEN_FREEZE        = 11;
const int __TDIDX_MENU_CAN_CANCEL      = 12;
const int __TDIDX_MENU_CURSOR_POS      = 13;
const int __TDIDX_MENU_CURSOR_COMBO    = 14;
const int __TDIDX_MENU_CURSOR_CSET     = 15;
const int __TDIDX_MENU_CURSOR_WIDTH    = 16;
const int __TDIDX_MENU_CURSOR_HEIGHT   = 17;
const int __TDIDX_MENU_CURSOR_SFX      = 91;
const int __TDIDX_MENU_SELECT_SFX      = 86;
const int __TDIDX_MENU_CANCEL_SFX      = 89;
const int __TDIDX_CHOICE_COUNT         = 21;
const int __TDIDX_MENU_SLOT            = 22;
const int __TDIDX_FIRST_CHOICE_ON_LINE = 23;
const int __TDIDX_REFRESH_STYLE        = 24;
const int __TDIDX_CHOICE_DATA          = 25;

const int __TANGO_MENU_DATA_START = 12; // Used by Tango_SaveMenuState()

// Current slot data (more __Tango_Data[] indices)
const int __TCS_ID          = 0;
const int __TCS_START       = 1;
const int __TCS_END         = 2;
const int __TCS_DEF_START   = 3;
const int __TCS_DATA_START  = 4;
const int __TCS_STYLE_START = 5;
const int __TCS_FONT        = 6;

// Menu data
const int __TANGO_CHOICE_X      = 0;
const int __TANGO_CHOICE_Y      = 1;
const int __TANGO_CHOICE_VALUE  = 2;
const int __TANGO_SIZEOF_CHOICE = 3;

// Global flags
const int __TANGO_GFLAG_UNPRESS_SPEEDUP     = 00001b;
const int __TANGO_GFLAG_UNPRESS_SUPER_SPEED = 00010b;
const int __TANGO_GFLAG_UNPRESS_ADVANCE     = 00100b;
const int __TANGO_GFLAG_UNPRESS_MENU        = 01000b;
const int __TANGO_GFLAG_UNPRESS_ALL         = 10000b;

// __Tango_SlotData[] indices
const int __TSDIDX_STYLE             = 0;
const int __TSDIDX_STATE             = 1;
const int __TSDIDX_COUNTER           = 2;
const int __TSDIDX_POSITION          = 3;
const int __TSDIDX_CHAR_X            = 4;
const int __TSDIDX_CHAR_Y            = 5;
const int __TSDIDX_SCREEN_X          = 6;
const int __TSDIDX_SCREEN_Y          = 7;
const int __TSDIDX_CSET              = 8;
const int __TSDIDX_COLOR             = 9; // Built-in fonts only
const int __TSDIDX_SPEED             = 10;
const int __TSDIDX_SFX               = 11;
const int __TSDIDX_OFFSET            = 12;
const int __TSDIDX_SCROLLING         = 13;
const int __TSDIDX_NEXT_STRING       = 14;
const int __TSDIDX_IGNORE_SPEED_KEYS = 15;
const int TANGO_VAR_A0               = 16;
const int TANGO_VAR_A1               = 17;
const int __TANGO_SIZEOF_DATA        = 18;

// __Tango_SlotDefs[] data
const int __TSDEF_TYPE   = 0;
const int __TSDEF_START  = 1;
const int __TSDEF_LENGTH = 2;
const int __TSDEF_X      = 3;
const int __TSDEF_Y      = 4;
const int __TSDEF_WIDTH  = 5;
const int __TSDEF_HEIGHT = 6;
const int __TANGO_SIZEOF_SLOTDEF = 7;

// Miscellaneous
const int TANGO_SLOT_ANY = -1;
const int TANGO_DEFAULT = -1;
const int TANGO_INVALID = -10;

// Some special characters
const int TANGO_CHAR_NEWLINE = 26;
const int __TANGO_CHAR_FILLER = -1;
const int __TANGO_CHAR_CHOICE = -10000;
const int __TANGO_CHAR_MENU_END = -20000;
const int __TANGO_PRINTABLE_CHAR = 33; // '!', the first character after space


// Loads some commonly used data about the current slot into __Tango_Data.
// Kind of ugly, but it beats recalculating the numbers whenever they're needed
// or passing them into every function.
void __Tango_SetCurrentSlot(int slot)
{
    int defStart=slot*__TANGO_SIZEOF_SLOTDEF;
    int dataStart=slot*__TANGO_SIZEOF_DATA;
    int style=__Tango_SlotData[dataStart+__TSDIDX_STYLE];
    int styleStart=style*__TANGO_SIZEOF_STYLE;
    
    __Tango_Data[__TCS_ID]=slot;
    __Tango_Data[__TCS_START]=
      __Tango_SlotDefs[defStart+__TSDEF_START];
    __Tango_Data[__TCS_END]=
      __Tango_SlotDefs[defStart+__TSDEF_START]+
      __Tango_SlotDefs[defStart+__TSDEF_LENGTH];
    __Tango_Data[__TCS_DEF_START]=defStart;
    __Tango_Data[__TCS_DATA_START]=dataStart;
    __Tango_Data[__TCS_STYLE_START]=styleStart;
    if(style!=TANGO_INVALID)
        __Tango_Data[__TCS_FONT]=
          __Tango_Styles[styleStart+TANGO_STYLE_TEXT_FONT];
    else
        __Tango_Data[__TCS_FONT]=TANGO_INVALID;
}

// Returns true if this character is a special data marker.
// End markers don't count.
bool __Tango_IsSpecialDataMarker(int character)
{
    // ZScript doesn't short-circuit, so it's slightly
    // faster to check these one at a time
    if(character==__TANGO_SETTER_MARKER)
        return true;
    if(character==__TANGO_FUNC_MARKER)
        return true;
    if(character==__TANGO_NUM_MARKER)
        return true;
    if(character==__TANGO_VAR_MARKER)
        return true;
    if(character==__TANGO_FLOW_MARKER)
        return true;
    
    return false;
}

// Various functions to make accessing the arrays a little more convenient.

float __Tango_GetCurrSlotData(int what)
{
    return __Tango_SlotData[__Tango_Data[__TCS_DATA_START]+what];
}

int __Tango_GetCurrSlotDefData(int what)
{
    return __Tango_SlotDefs[__Tango_Data[__TCS_DEF_START]+what];
}

int __Tango_GetSlotDefData(int slot, int what)
{
    return __Tango_SlotDefs[slot*__TANGO_SIZEOF_SLOTDEF+what];
}

int __Tango_GetCurrFontData(int what)
{
    int font=__Tango_Data[__TCS_FONT];
    return font[what];
}

void __Tango_SetCurrSlotData(int what, float value)
{
    __Tango_SlotData[__Tango_Data[__TCS_DATA_START]+what]=value;
}

int __Tango_GetCurrStyleData(int what)
{
    return __Tango_Styles[__Tango_Data[__TCS_STYLE_START]+what];
}

int __Tango_GetCurrentCSet()
{
    int cset=__Tango_GetCurrSlotData(__TSDIDX_CSET);
    if(cset==TANGO_DEFAULT)
        cset=__Tango_GetCurrStyleData(TANGO_STYLE_TEXT_CSET);
    return cset;
}

int __Tango_GetCurrentColor()
{
    int color=__Tango_GetCurrSlotData(__TSDIDX_COLOR);
    if(color==TANGO_DEFAULT)
        color=__Tango_GetCurrStyleData(TANGO_STYLE_TEXT_COLOR);

    return color;
}

int __Tango_GetCurrentSpeed()
{
    int speed=__Tango_GetCurrSlotData(__TSDIDX_SPEED);
    if(speed==TANGO_DEFAULT)
        return __Tango_GetCurrStyleData(TANGO_STYLE_TEXT_SPEED);
    else if(speed<0)
        return 0;
    return speed;
}

int __Tango_GetCurrentSFX()
{
    int sfx=__Tango_GetCurrSlotData(__TSDIDX_SFX);
    if(sfx==TANGO_DEFAULT)
        sfx=__Tango_GetCurrStyleData(TANGO_STYLE_TEXT_SFX);
    return sfx;
}

int __Tango_GetLineHeight()
{
    int font=__Tango_Data[__TCS_FONT];
    return font[__TANGO_FONT_CHAR_HEIGHT]+font[__TANGO_FONT_LINE_SPACING];
}

int __Tango_GetSlotState(int slot)
{
    int dataStart=slot*__TANGO_SIZEOF_DATA;
    return __Tango_SlotData[dataStart+__TSDIDX_STATE];
}

int __Tango_GetSlotFlags(int slot)
{
    int dataStart=slot*__TANGO_SIZEOF_DATA;
    if(__Tango_SlotData[dataStart+__TSDIDX_STYLE]==TANGO_INVALID)
        return 0;
    int styleStart=__Tango_SlotData[dataStart+__TSDIDX_STYLE]*
                   __TANGO_SIZEOF_STYLE;
    return __Tango_Styles[styleStart+TANGO_STYLE_FLAGS];
}

// Increment the screen freeze counter. Freeze the screen if it was 0.
void __Tango_IncScreenFreeze()
{
    if(__Tango_Data[__TDIDX_SCREEN_FREEZE]==0)
        __Tango_FreezeScreen();
    
    __Tango_Data[__TDIDX_SCREEN_FREEZE]++;
}

// Decrement the screen freeze counter. Unfreeze the screen if it's now 0.
void __Tango_DecScreenFreeze()
{
    __Tango_Data[__TDIDX_SCREEN_FREEZE]--;
    
    if(__Tango_Data[__TDIDX_SCREEN_FREEZE]==0)
        __Tango_UnfreezeScreen();
}

// string.zh's float-to-text functions don't work right in 2.50,
// so this is used instead.
int __Tango_FloatToASCII(int buffer, float value, bool allDigits)
{
    int pos=0;
    int place=100000;
    int digit;
    bool printZero=false;
    int storedZeroes=0;
    
    if(value<0)
    {
        buffer[0]='-';
        pos=1;
        value=-value;
    }
        
    
    for(int i=0; i<10; i++)
    {
        digit=((value/place)<<0)%10;
        
        // If the fractional part hasn't been reached yet,
        // or if all four of its digits are to be printed,
        // this is easy.
        if(place>=1 || allDigits)
        {
            if(digit>0 || printZero)
            {
                buffer[pos]=digit+'0';
                pos++;
                
                // Start printing 0 at the first non-zero digit.
                printZero=true;
            }
        }
        
        // Otherwise, it's trickier.
        else
        {
            // A zero isn't printed unless there's something else after it.
            // Don't print it, just keep count.
            if(digit==0)
                storedZeroes++;
            
            // Any other digit flushes the zeroes and then is printed.
            else
            {
                for(; storedZeroes>0; storedZeroes--)
                {
                    buffer[pos]='0';
                    pos++;
                }
                
                buffer[pos]=digit+'0';
                pos++;
            }
        }
        
        value%=place; // To make sure value/place doesn't overflow when place<1
        place/=10;
        
        if(place==1) // Last digit before the decimal point
            printZero=true;
        
        else if(place==0.1) // Reached the fractional part
        {
            buffer[pos]='.';
            pos++;
        }
    }
    
    buffer[pos]=NULL;
    return pos;
}

