void ComBoard :: Load(const char *fileName, xBYTE I_bones)
{
    Destroy();
    this->I_bones = I_bones;
    FileName = Filesystem::GetFullPath(fileName);

    std::ifstream in;
    in.open(FileName.c_str());
    if (in.is_open())
    {
        std::string dir = Filesystem::GetParentDir(fileName);
        char buffer[255];
        int  len;

        AutoHint hint;
        Action   action;
        Combo    combo;
        action.Clear();
        combo.Clear();

        enum LoadMode
        {
            LoadMode_None,
            LoadMode_Auto,
            LoadMode_Mirror,
            LoadMode_Action,
            LoadMode_Combo
        } mode = LoadMode_None;

        while (in.good())
        {
            in.getline(buffer, 255);
            if (buffer[0] == 0 || buffer[0] == '#') continue;
            len = strlen(buffer);
            if (buffer[len - 1] == '\r') buffer[len - 1] = 0;

            if (*buffer == '[')
            {
                if (StartsWith(buffer, "[action]"))
                {
                    if (combo.SN_action.length())
                        action.L_combos.push_back(combo);
                    if (action.SN_name.length())
                        L_actions.push_back(action);
                    else
                        action.Destroy();
                    action.Clear();
                    combo.Clear();
                    mode = LoadMode_Action;
                    continue;
                }
                if (StartsWith(buffer, "[auto]"))
                {
                    mode = LoadMode_Auto;
                    continue;
                }
                if (StartsWith(buffer, "[mirror]"))
                {
                    mode = LoadMode_Mirror;
                    continue;
                }
                mode = LoadMode_None;
                continue;
            }
            if (mode == LoadMode_Action || mode == LoadMode_Combo)
            {
                if (*buffer == '(')
                {
                    if (mode != LoadMode_None && StartsWith(buffer, "(combo)"))
                    {
                        if (combo.SN_action.length())
                            action.L_combos.push_back(combo);
                        combo.Clear();
                        mode = LoadMode_Combo;
                        continue;
                    }
                    continue;
                }
            }
            if (mode == LoadMode_Auto)
            {
                if (StartsWith(buffer, "stop"))
                {
                    StopAction.SN_action = ReadSubstring(buffer+4);
                    continue;
                }
                if (StartsWith(buffer, "step"))
                {
                    const char* params = NULL;
                    hint.SN_action = ReadSubstring(buffer+4, params);
                    if (params)
                    {
                        int flag = 1;
                        sscanf(params, "%f %d", &hint.S_max_change, &flag);
                        hint.FL_breakable = flag;
                    }
                    L_hint[AutoHint::HINT_STEP].push_back(hint);
                    continue;
                }
                if (StartsWith(buffer, "back"))
                {
                    const char* params = NULL;
                    hint.SN_action = ReadSubstring(buffer+4, params);
                    if (params)
                    {
                        int flag = 1;
                        sscanf(params, "%f %d", &hint.S_max_change, &flag);
                        hint.FL_breakable = flag;
                    }
                    L_hint[AutoHint::HINT_BACK].push_back(hint);
                    continue;
                }
                if (StartsWith(buffer, "left"))
                {
                    const char* params = NULL;
                    hint.SN_action = ReadSubstring(buffer+4, params);
                    if (params)
                    {
                        int flag = 1;
                        sscanf(params, "%f %d", &hint.S_max_change, &flag);
                        hint.FL_breakable = flag;
                    }
                    L_hint[AutoHint::HINT_LEFT].push_back(hint);
                    continue;
                }
                if (StartsWith(buffer, "right"))
                {
                    const char* params = NULL;
                    hint.SN_action = ReadSubstring(buffer+5, params);
                    if (params)
                    {
                        int flag = 1;
                        sscanf(params, "%f %d", &hint.S_max_change, &flag);
                        hint.FL_breakable = flag;
                    }
                    L_hint[AutoHint::HINT_RIGHT].push_back(hint);
                    continue;
                }
            }
            if (mode == LoadMode_Mirror)
            {
                if (StartsWith(buffer, "bones"))
                {
                    int b1, b2;
                    sscanf(buffer+5, "%d %d", &b1, &b2);
                    Mirror mirror;
                    mirror.ID_bone1 = b1;
                    mirror.ID_bone2 = b2;
                    L_mirror.push_back(mirror);
                    continue;
                }
            }
            if (mode == LoadMode_Action)
            {
                if (StartsWith(buffer, "name"))
                {
                    action.SN_name = ReadSubstring(buffer+4);
                    continue;
                }
                if (StartsWith(buffer, "anim"))
                {
                    const char* params = NULL;
                    std::string animFile = Filesystem::GetFullPath(dir + "/" + ReadSubstring(buffer+4, params));

                    int start = 0, end = 0;
                    if (params)
                        sscanf(params, "%d %d", &start, &end);

                    if (end <= start)
                        action.Anims.AddAnimation(animFile.c_str(), start);
                    else
                        action.Anims.AddAnimation(animFile.c_str(), start, end);
                    continue;
                }
                if (StartsWith(buffer, "time"))
                {
                    float time;
                    sscanf(buffer+4, "%f", &time);
                    action.T_duration = time;
                    continue;
                }
                if (StartsWith(buffer, "post"))
                {
                    action.SN_next = ReadSubstring(buffer+4);
                    continue;
                }
                if (StartsWith(buffer, "rotate"))
                {
                    int val;
                    sscanf(buffer+6, "%d", &val);
                    action.FL_pos_rotation = val != 0;
                    continue;
                }
                if (StartsWith(buffer, "mirror"))
                {
                    int val;
                    sscanf(buffer+6, "%d", &val);
                    action.FL_mirror = val;
                    continue;
                }
                if (StartsWith(buffer, "power"))
                {
                    sscanf(buffer+5, "%f", &action.W_punch);
                    continue;
                }
                if (StartsWith(buffer, "puncht"))
                {
                    sscanf(buffer+6, "%f", &action.T_punch);
                    continue;
                }
            }
            if (mode == LoadMode_Combo)
            {
                if (StartsWith(buffer, "action"))
                {
                    combo.SN_action = ReadSubstring(buffer+6);
                    continue;
                }
                if (StartsWith(buffer, "key"))
                {
                    char name[255];
                    sscanf(buffer+3, "%s", name);
                    if (StartsWith(name, "LeftPunch"))      combo.Key = Combo::Keys::LeftPunch;
                    else if (StartsWith(name, "LeftKick"))       combo.Key = Combo::Keys::LeftKick;
                    else if (StartsWith(name, "LeftHandGuard"))  combo.Key = Combo::Keys::LeftHandGuard;
                    else if (StartsWith(name, "LeftLegGuard"))   combo.Key = Combo::Keys::LeftLegGuard;
                    else if (StartsWith(name, "RightPunch"))     combo.Key = Combo::Keys::RightPunch;
                    else if (StartsWith(name, "RightKick"))      combo.Key = Combo::Keys::RightKick;
                    else if (StartsWith(name, "RightHandGuard")) combo.Key = Combo::Keys::RightHandGuard;
                    else if (StartsWith(name, "RightLegGuard"))  combo.Key = Combo::Keys::RightLegGuard;
                    else if (StartsWith(name, "Forward"))        combo.Key = Combo::Keys::Forward;
                    else if (StartsWith(name, "Backward"))       combo.Key = Combo::Keys::Backward;
                    else if (StartsWith(name, "Left"))           combo.Key = Combo::Keys::Left;
                    else if (StartsWith(name, "Right"))          combo.Key = Combo::Keys::Right;
                    else                                    combo.Key = Combo::Keys::Undefined;
                    continue;
                }
                if (StartsWith(buffer, "first"))
                {
                    float time;
                    sscanf(buffer+5, "%f", &time);
                    combo.T_first = time;
                    continue;
                }
                if (StartsWith(buffer, "last"))
                {
                    float time;
                    sscanf(buffer+4, "%f", &time);
                    combo.T_last = time;
                    continue;
                }
                if (StartsWith(buffer, "time"))
                {
                    float time;
                    sscanf(buffer+4, "%f", &time);
                    combo.T_time = time;
                    continue;
                }
                if (StartsWith(buffer, "prec"))
                {
                    int val;
                    sscanf(buffer+4, "%d", &val);
                    combo.FL_time_shift = val == 0;
                    continue;
                }
                if (StartsWith(buffer, "shift"))
                {
                    int val;
                    sscanf(buffer+5, "%d", &val);
                    combo.FL_pos_shift = val != 0;
                    continue;
                }
            }
        }
        if (combo.SN_action.length())
            action.L_combos.push_back(combo);
        if (action.SN_name.length())
            L_actions.push_back(action);
        else
            action.Destroy(); // Release animations

        in.close();

        UpdateIDs();
    }
}