int ONScripterLabel::clickNewPage( char *out_text )
{
    if ( out_text ){
        drawDoubleChars( out_text, &sentence_font, true, true, accumulation_surface, &text_info );
        num_chars_in_sentence++;
    }
    if ( skip_flag || draw_one_page_flag || ctrl_pressed_status ) flush( refreshMode() );
    
    if ( (skip_flag || ctrl_pressed_status) && !textgosub_label  ){
        event_mode = WAIT_SLEEP_MODE;
        advancePhase();
        num_chars_in_sentence = 0;
        clickstr_state = CLICK_NEWPAGE;
    }
    else{
        key_pressed_flag = false;
        if ( textgosub_label ){
            saveoffCommand();

            textgosub_clickstr_state = CLICK_NEWPAGE;
            gosubReal( textgosub_label, script_h.getNext() );
            indent_offset = 0;
            line_enter_status = 0;
            page_enter_status = 0;
            string_buffer_offset = 0;
            return RET_CONTINUE;
        }

        clickstr_state = CLICK_NEWPAGE;
        doClickEnd();
    }
    return RET_WAIT | RET_NOREAD;
}
void PonscripterLabel::leaveSystemCall(bool restore_flag)
{
    current_font = &sentence_font;
    display_mode = shelter_display_mode;
    system_menu_mode = SYSTEM_NULL;
    system_menu_enter_flag = false;
    yesno_caller = SYSTEM_NULL;
    key_pressed_flag = false;

    if (restore_flag) {
        current_text_buffer = cached_text_buffer;
        restoreTextBuffer();
	buttons.swap(shelter_buttons);
	shelter_buttons.clear();
	select_links.swap(shelter_select_links);
	shelter_select_links.clear();

        event_mode = shelter_event_mode;
        draw_cursor_flag = shelter_draw_cursor_flag;
        if (event_mode & WAIT_BUTTON_MODE) {
            SDL_WarpMouseInWindow(screen, shelter_mouse_state.x, shelter_mouse_state.y);
        }
    }

    dirty_rect.fill(screen_width, screen_height);
    flush(refreshMode());

    //printf("leaveSystemCall %d %d\n",event_mode, clickstr_state);

    refreshMouseOverButton();
    advancePhase();
}
void PonscripterLabel::executeSystemLoad()
{
    SaveFileInfo save_file_info;

    current_font = &menu_font;
    if (event_mode & WAIT_BUTTON_MODE) {
        if (current_button_state.button == 0) return;

        event_mode = IDLE_EVENT_MODE;

        if (current_button_state.button > 0) {
            searchSaveFile(save_file_info, current_button_state.button);
            if (!save_file_info.valid) {
                event_mode = WAIT_BUTTON_MODE;
                refreshMouseOverButton();
                return;
            }

            deleteButtons();
            yesno_selected_file_no = current_button_state.button;
            yesno_caller = SYSTEM_LOAD;
            system_menu_mode = SYSTEM_YESNO;
            advancePhase();
        }
        else {
            deleteButtons();
            leaveSystemCall();
        }
    }
    else {
        system_menu_mode = SYSTEM_LOAD;
        createSaveLoadMenu(false);
    }
}
void PonscripterLabel::startTimer(int count)
{
    int duration = proceedAnimation();

    if (duration > 0 && duration < count) {
        resetRemainingTime(duration);
        advancePhase(duration);
        remaining_time = count;
    }
    else {
        advancePhase(count);
        remaining_time = 0;
    }

    event_mode |= WAIT_TIMER_MODE;
}
void PonscripterLabel::keyDownEvent(SDL_KeyboardEvent* event)
{
    switch (event->keysym.sym) {
    case SDLK_RCTRL:
        ctrl_pressed_status |= 0x01;
        goto ctrl_pressed;
    case SDLK_LCTRL:
        ctrl_pressed_status |= 0x02;
        goto ctrl_pressed;
    case SDLK_RSHIFT:
        shift_pressed_status |= 0x01;
        break;
    case SDLK_LSHIFT:
        shift_pressed_status |= 0x02;
        break;
    default:
        break;
    }

    return;

    ctrl_pressed:
    current_button_state.button  = 0;
    volatile_button_state.button = 0;
    playClickVoice();
    stopAnimation(clickstr_state);
    advancePhase();
    return;
}
void PonscripterLabel::executeSystemSave()
{
    current_font = &menu_font;
    if (event_mode & WAIT_BUTTON_MODE) {
        if (current_button_state.button == 0) return;

        event_mode = IDLE_EVENT_MODE;

        deleteButtons();

        if (current_button_state.button > 0) {
            yesno_selected_file_no = current_button_state.button;
            yesno_caller = SYSTEM_SAVE;
            system_menu_mode = SYSTEM_YESNO;
            advancePhase();
            return;
        }

        leaveSystemCall();
    }
    else {
        system_menu_mode = SYSTEM_SAVE;
        createSaveLoadMenu(true);
    }
}
void PonscripterLabel::trapHandler()
{
    trap_mode = TRAP_NONE;
    setCurrentLabel(trap_dist);
    readToken();
    stopAnimation(clickstr_state);
    event_mode = IDLE_EVENT_MODE;
    advancePhase();
}
void PonscripterLabel::executeSystemEnd()
{
    if (yesno_caller == SYSTEM_END) {
        leaveSystemCall();
    }
    else {
        yesno_caller = SYSTEM_END;
        system_menu_mode = SYSTEM_YESNO;
        advancePhase();
    }
}
void ONScripter::timerEvent(int count)
{
    if (!(event_mode & WAIT_TIMER_MODE)) return;

    int duration = proceedAnimation();
            
    if (duration > 0){
        if (count == -1 || duration < count){
            resetRemainingTime( duration );
            advancePhase( duration );
        }
        else{
            resetRemainingTime( count );
        }
    }
}
int PonscripterLabel::setEffect(Effect& effect, bool generate_effect_dst, bool update_backup_surface)
{
    if (effect.effect == 0) return RET_CONTINUE;

    if (update_backup_surface)
        refreshSurface(backup_surface, &dirty_rect.bounding_box,
                       REFRESH_NORMAL_MODE);

    int effect_no = effect.effect;
    if (effect_cut_flag && skip_flag) effect_no = 1;

    SDL_BlitSurface(accumulation_surface, NULL, effect_src_surface, NULL);

    if (generate_effect_dst) {
        int refresh_mode = refreshMode();
        if (update_backup_surface && refresh_mode == REFRESH_NORMAL_MODE) {
            SDL_BlitSurface(backup_surface, &dirty_rect.bounding_box,
                            effect_dst_surface, &dirty_rect.bounding_box);
        }
        else {
            if (effect_no == 1)
                refreshSurface(effect_dst_surface, &dirty_rect.bounding_box,
                               refresh_mode);
            else
                refreshSurface(effect_dst_surface, NULL, refresh_mode);
        }
    }

    /* Load mask image */
    if (effect_no == 15 || effect_no == 18) {
        if (!effect.anim.image_surface) {
            parseTaggedString(&effect.anim, true);
            setupAnimationInfo(&effect.anim);
        }
    }
    if (effect_no == 11 || effect_no == 12 || effect_no == 13 ||
            effect_no == 14 || effect_no == 16 || effect_no == 17)
        dirty_rect.fill( screen_width, screen_height );

    effect_counter = 0;
    effect_start_time_old = SDL_GetTicks();
    event_mode = EFFECT_EVENT_MODE;
    advancePhase();

    return RET_WAIT | RET_REREAD;
}
void PonscripterLabel::mouseWheelEvent(SDL_MouseWheelEvent* event) {
    if (variable_edit_mode) return;


    if (automode_flag) {
        remaining_time = -1;
        setAutoMode(false);
        return;
    }

    setSkipMode(false);

    if (event->y > 0 //Scroll up
             && ((event_mode & WAIT_TEXT_MODE)
                 || (usewheel_flag && (event_mode & WAIT_BUTTON_MODE))
                 || system_menu_mode == SYSTEM_LOOKBACK)) {
        current_button_state.button  = -2;
        volatile_button_state.button = -2;
        if (event_mode & WAIT_TEXT_MODE) system_menu_mode = SYSTEM_LOOKBACK;
    }
    else if (event->y < 0 //Scroll down
             && ((enable_wheeldown_advance_flag &&
                  (event_mode & WAIT_TEXT_MODE))
                 || (usewheel_flag && (event_mode & WAIT_BUTTON_MODE))
                 || system_menu_mode == SYSTEM_LOOKBACK)) {
        if (event_mode & WAIT_TEXT_MODE) {
            current_button_state.button  = 0;
            volatile_button_state.button = 0;
        }
        else {
            current_button_state.button  = -3;
            volatile_button_state.button = -3;
        }
    } else {
      return;
    }
    /* Perhaps handle x too in case they have a trackpad sideways scroll? */

    if (event_mode & (WAIT_INPUT_MODE | WAIT_BUTTON_MODE)) {
      playClickVoice();
      stopAnimation(clickstr_state);
      advancePhase();
    }

}
int PonscripterLabel::clickNewPage(bool display_char)
{
    const char* c = script_h.getStrBuf(string_buffer_offset);

    if (current_read_language != -1 && current_read_language != current_language) {
        clickstr_state = CLICK_NEWPAGE;
    }

    if (display_char) {
        drawChar(c, &sentence_font, true, true, accumulation_surface,
                 &text_info);
        ++num_chars_in_sentence;
    }
    
    if (skip_flag || draw_one_page_flag || skip_to_wait ||
        ctrl_pressed_status || (sentence_font.wait_time == 0))
        flush(refreshMode());

    skip_to_wait = 0;

    if ((skip_flag || ctrl_pressed_status) && !textgosub_label) {
        event_mode = WAIT_SLEEP_MODE;
        advancePhase();
        num_chars_in_sentence = 0;
    }
    else {
        key_pressed_flag = false;
        if (textgosub_label) {
            saveoffCommand("saveoff");

            textgosub_clickstr_state = CLICK_NEWPAGE;
            gosubReal(textgosub_label, script_h.getNext());
            indent_offset = 0;
            line_enter_status = 0;
            string_buffer_offset = 0;
            return RET_CONTINUE;
        }

        doClickEnd();
    }

    return RET_WAIT | RET_NOREAD;
}
void ONScripterLabel::doClickEnd()
{
    if ( automode_flag ){
        event_mode =  WAIT_TEXT_MODE | WAIT_INPUT_MODE | WAIT_VOICE_MODE;
        if ( automode_time < 0 )
            startTimer( -automode_time * num_chars_in_sentence );
        else
            startTimer( automode_time );
    }
    else if ( autoclick_time > 0 ){
        event_mode = WAIT_SLEEP_MODE;
        startTimer( autoclick_time );
    }
    else{
        event_mode = WAIT_TEXT_MODE | WAIT_INPUT_MODE | WAIT_TIMER_MODE;
        advancePhase();
    }
    draw_cursor_flag = true;
    num_chars_in_sentence = 0;
}
void PonscripterLabel::executeSystemMenu()
{
    int counter = 1;

    current_font = &menu_font;
    if (event_mode & WAIT_BUTTON_MODE) {
        if (current_button_state.button == 0) return;

        event_mode = IDLE_EVENT_MODE;

        deleteButtons();

        if (current_button_state.button == -1) {
	    playSound(menuselectvoice_file_name[MENUSELECTVOICE_CANCEL],
		      SOUND_WAVE | SOUND_OGG, false, MIX_WAVE_CHANNEL);

            leaveSystemCall();
            return;
        }

	playSound(menuselectvoice_file_name[MENUSELECTVOICE_CLICK],
		  SOUND_WAVE | SOUND_OGG, false, MIX_WAVE_CHANNEL);

	for (RMenuElt::iterator it = rmenu.begin(); it != rmenu.end(); ++it) {
	    if (current_button_state.button == counter++) {
                system_menu_mode = it->system_call_no;
                break;
            }
        }

        advancePhase();
    }
    else {
	playSound(menuselectvoice_file_name[MENUSELECTVOICE_OPEN],
		  SOUND_WAVE | SOUND_OGG, false, MIX_WAVE_CHANNEL);

        system_menu_mode = SYSTEM_MENU;
        yesno_caller = SYSTEM_MENU;

        text_info.fill(0, 0, 0, 0);
        flush(refreshMode());

        current_font->area_x = screen_width * screen_ratio2 / screen_ratio1;
        current_font->area_y = current_font->line_top(rmenu.size());
        current_font->top_x  = 0;
        current_font->top_y  = (screen_height * screen_ratio2 / screen_ratio1 -
                                current_font->area_y) / 2;
        current_font->SetXY(0, 0);

	for (RMenuElt::iterator it = rmenu.begin(); it != rmenu.end(); ++it) {
            const float sw = float (screen_width * screen_ratio2)
		           / float (screen_ratio1);
            current_font->SetXY((sw - current_font->StringAdvance(it->label)) / 2);
	    buttons[counter++] = getSelectableSentence(it->label, current_font,
						       false);
            flush(refreshMode());
        }

        flushEvent();
        event_mode = WAIT_BUTTON_MODE;
        refreshMouseOverButton();
    }
}
int PonscripterLabel::processText()
{
    if (string_buffer_restore > 0) {
        string_buffer_offset = string_buffer_restore;
        string_buffer_restore = -1;
    }
    if (debug_level > 1) {
        fprintf(stderr,"processText: %d:'%s", string_buffer_offset, script_h.getStrBuf(string_buffer_offset));
    }
    if (event_mode & (WAIT_INPUT_MODE | WAIT_SLEEP_MODE)) {
        draw_cursor_flag = false;
        if (script_h.readStrBuf(string_buffer_offset) == '!') {
            string_buffer_offset++;
            if (script_h.readStrBuf(string_buffer_offset) == 'w' ||
                script_h.readStrBuf(string_buffer_offset) == 'd') {
                ++string_buffer_offset;
                while (script_h.isadigit(script_h.readStrBuf(string_buffer_offset))) {
                    ++string_buffer_offset;
                }
                while (script_h.isawspace(script_h.readStrBuf(string_buffer_offset)))
                    ++string_buffer_offset;
            }
        }
        else if (clickstr_state == CLICK_WAIT) {
            string_buffer_offset += file_encoding->NextCharSizeWithLigatures
                (script_h.getStrBuf(string_buffer_offset), &sentence_font);
            clickstr_state = CLICK_NONE;
        }
        else if (clickstr_state == CLICK_NEWPAGE) {
            event_mode = IDLE_EVENT_MODE;
            string_buffer_offset += file_encoding->NextCharSizeWithLigatures
                (script_h.getStrBuf(string_buffer_offset), &sentence_font);
            newPage(true);
            clickstr_state = CLICK_NONE;
            return RET_CONTINUE | RET_NOREAD;
        }
        else
            string_buffer_offset +=
                file_encoding->NextCharSizeWithLigatures
                (script_h.getStrBuf(string_buffer_offset), &sentence_font);
        event_mode = IDLE_EVENT_MODE;
    }

    if (script_h.readStrBuf(string_buffer_offset) == 0x0a ||
        script_h.readStrBuf(string_buffer_offset) == 0x00) {
        indent_offset = 0; // redundant
        skip_to_wait = 0;
        return RET_CONTINUE;
    }

    new_line_skip_flag = false;

    char ch = script_h.readStrBuf(string_buffer_offset);

    // Chronotrig, multilang inline command hack, ignore ! and # commands when current language isn't being read
    if (current_read_language != -1 && current_read_language != current_language) {
        int startingChar = string_buffer_offset;
        if (ch == '!') {
            string_buffer_offset++;
            if (script_h.readStrBuf(string_buffer_offset) == 'w' ||
                script_h.readStrBuf(string_buffer_offset) == 'd') {
                ++string_buffer_offset;
                while (script_h.isadigit(script_h.readStrBuf(string_buffer_offset))) {
                    ++string_buffer_offset;
                }
                while (script_h.isawspace(script_h.readStrBuf(string_buffer_offset)))
                    ++string_buffer_offset;

            } else if (script_h.readStrBuf(string_buffer_offset) == 's') {
                string_buffer_offset++;
                if (script_h.readStrBuf(string_buffer_offset) == 'd') {
                    string_buffer_offset++;
                } else {
                    while (script_h.isadigit(script_h.readStrBuf(string_buffer_offset))) {
                        ++string_buffer_offset;
                    }
                    while (script_h.isawspace(script_h.readStrBuf(string_buffer_offset)))
                        ++string_buffer_offset;
                }
            }
            if (string_buffer_offset - startingChar > 3) {
                return RET_CONTINUE;
            } else {
                string_buffer_offset = startingChar;
            }
        } else if (ch == '#') {
            char hexchecker;
            bool isValidHex = true;
            for (int i = 0; i <= 5; ++i) {
                hexchecker = script_h.readStrBuf(string_buffer_offset + i + 1);
                if (!script_h.isaxdigit(hexchecker)) {
                    isValidHex = false;
                }
            }
            if (isValidHex) {
                string_buffer_offset += 7;
                return RET_CONTINUE;
            }
        }
    }

    if (ch == '@') { // wait for click
        return clickWait(false);
    }
    else if (ch == '\\') { // new page
        return clickNewPage(false);
    }
    else if (ch == '_') { // Ignore following forced return
        clickstr_state = CLICK_IGNORE;
        ++string_buffer_offset;
        return RET_CONTINUE | RET_NOREAD;
    }
    else if (ch == '!') {
        ++string_buffer_offset;
        if (script_h.readStrBuf(string_buffer_offset) == 's') {
            ++string_buffer_offset;
            bool in_skip = (skip_flag || ctrl_pressed_status);
            int prev_t = sentence_font.wait_time;
            if (script_h.readStrBuf(string_buffer_offset) == 'd') {
                sentence_font.wait_time = -1;
                ++string_buffer_offset;
            }
            else {
                int t = 0;
                while (script_h.isadigit(script_h.readStrBuf(string_buffer_offset))) {
                    t = t * 10 + script_h.readStrBuf(string_buffer_offset) -'0';
                    ++string_buffer_offset;
                }
                sentence_font.wait_time = t;
                while (script_h.isawspace(script_h.readStrBuf(string_buffer_offset)))
                    ++string_buffer_offset;
            }
            if (!in_skip && (prev_t == 0) && (sentence_font.wait_time != 0))
                flush(refreshMode());
        }
        else if (script_h.readStrBuf(string_buffer_offset) == 'w'
                 || script_h.readStrBuf(string_buffer_offset) == 'd') {
            bool flag = false;
            bool in_skip = (skip_flag || draw_one_page_flag || ctrl_pressed_status);
            if (script_h.readStrBuf(string_buffer_offset) == 'd')
                flag = true;

            ++string_buffer_offset;
            int tmp_string_buffer_offset = string_buffer_offset;
            int t = 0;
            while (script_h.isadigit(script_h.readStrBuf(string_buffer_offset))) {
                t = t * 10 + script_h.readStrBuf(string_buffer_offset) - '0';
                ++string_buffer_offset;
            }
            while (script_h.isawspace(script_h.readStrBuf(string_buffer_offset)))
                string_buffer_offset++;
            flush(refreshMode());
            if (flag && in_skip) {
                skip_to_wait = 0;
                return RET_CONTINUE | RET_NOREAD;
            }
            else {
                if (!flag && in_skip) {
                    //Mion: instead of skipping entirely, let's do a shortened wait (safer)
                    if (t > 100) {
                        t = t / 10;
                    } else if (t > 10) {
                        t = 10;
                    }
                }
                skip_to_wait = 0;
                event_mode = WAIT_SLEEP_MODE;
                if (flag) event_mode |= WAIT_INPUT_MODE;

                key_pressed_flag = false;
                startTimer(t);
                string_buffer_offset = tmp_string_buffer_offset - 2;
                return RET_WAIT | RET_NOREAD;
            }
        }
        else {
            --string_buffer_offset;
            goto notacommand;
        }

        return RET_CONTINUE | RET_NOREAD;
    }
    else if (ch == '#') {
        char hexchecker;
        for (int i = 0; i <= 5; ++i) {
            hexchecker = script_h.readStrBuf(string_buffer_offset + i + 1);
            if (!script_h.isaxdigit(hexchecker))
                goto notacommand;
        }

        sentence_font.color
            = readColour(script_h.getStrBuf(string_buffer_offset));
        string_buffer_offset += 7;

        return RET_CONTINUE | RET_NOREAD;
    }
    else if (ch == '/') {
        if (script_h.readStrBuf(string_buffer_offset + 1) != 0x0a)
            goto notacommand;
        else { // skip new line
            new_line_skip_flag = true;
            string_buffer_offset++;
            return RET_CONTINUE; // skip the following eol
        }
    }
    else {
        notacommand:

        if (clickstr_state == CLICK_IGNORE) {
            clickstr_state = CLICK_NONE;
        }
        else {
            const char* c = script_h.getStrBuf(string_buffer_offset);
            if (script_h.checkClickstr(c)) {
                if (sentence_font.isNoRoomForLines(clickstr_line))
                    return clickNewPage(true);
                else
                    return clickWait(true);
            }
        }

        bool flush_flag = !(skip_flag || draw_one_page_flag ||
                            skip_to_wait || ctrl_pressed_status ||
                            (sentence_font.wait_time == 0) ||
                             (current_read_language != -1 && current_read_language != current_language));

        drawChar(script_h.getStrBuf(string_buffer_offset), &sentence_font,
                 flush_flag, true, accumulation_surface, &text_info);
        ++num_chars_in_sentence;

        if (flush_flag) {
            event_mode = WAIT_SLEEP_MODE;
            int wait_time = 0;
            if ( sentence_font.wait_time == -1 )
                wait_time = default_text_speed[text_speed_no];
            else
                wait_time = sentence_font.wait_time;
            advancePhase(wait_time * 100 / global_speed_modifier);
            return RET_WAIT | RET_NOREAD;
        }
        event_mode = IDLE_EVENT_MODE;
        //Mion: hack using RET_CONTINUE | RET_WAIT for unflushed text
        return RET_CONTINUE | RET_WAIT | RET_NOREAD;
    }

    return RET_NOMATCH;
}
void PonscripterLabel::mousePressEvent(SDL_MouseButtonEvent* event)
{
    if (variable_edit_mode) return;

    if (automode_flag) {
        remaining_time = -1;
        setAutoMode(false);
        return;
    }

    if (event->button == SDL_BUTTON_RIGHT
        && trap_mode & TRAP_RIGHT_CLICK) {
        trapHandler();
        return;
    }
    else if (event->button == SDL_BUTTON_LEFT
             && trap_mode & TRAP_LEFT_CLICK) {
        trapHandler();
        return;
    }

    //Mouse didn't have a mouse-down event
    if(current_button_state.down_x == -1 && current_button_state.down_y == -1) {
        current_button_state.ignore_mouseup = true;
    }

    /* Use both = -1 to indicate we haven't received a mousedown yet */
    if(event->type == SDL_MOUSEBUTTONUP){
        current_button_state.down_x = -1;
        current_button_state.down_y = -1;
    }

    current_button_state.x = event->x;
    current_button_state.y = event->y;
    current_button_state.down_flag = false;
    setSkipMode(false);

    if (event->button == SDL_BUTTON_RIGHT
        && event->type == SDL_MOUSEBUTTONUP
        && !current_button_state.ignore_mouseup
        && ((rmode_flag && (event_mode & WAIT_TEXT_MODE))
            || (event_mode & WAIT_BUTTON_MODE))) {
        current_button_state.button  = -1;
        volatile_button_state.button = -1;
        if (event_mode & WAIT_TEXT_MODE) {
            if (!rmenu.empty())
                system_menu_mode = SYSTEM_MENU;
            else
                system_menu_mode = SYSTEM_WINDOWERASE;
        }
    }
    else if (event->button == SDL_BUTTON_LEFT
             && ((!current_button_state.ignore_mouseup && event->type == SDL_MOUSEBUTTONUP) || btndown_flag)) {
        current_button_state.button  = current_over_button;
        volatile_button_state.button = current_over_button;
//#ifdef SKIP_TO_WAIT
        if (event_mode & WAIT_SLEEP_MODE) skip_to_wait = 1;
//#endif

        if (event->type == SDL_MOUSEBUTTONDOWN) {
            current_button_state.down_flag = true;
        }
    } else {
      return;
    }

    if (event_mode & (WAIT_INPUT_MODE | WAIT_BUTTON_MODE)) {
        playClickVoice();
        stopAnimation(clickstr_state);
        advancePhase();
    }
}
void PonscripterLabel::executeSystemYesNo()
{
    current_font = &menu_font;
    if (event_mode & WAIT_BUTTON_MODE) {
        if (current_button_state.button == 0) return;

        event_mode = IDLE_EVENT_MODE;

        deleteButtons();

        if (current_button_state.button == 1) { // yes is selected
	    playSound(menuselectvoice_file_name[MENUSELECTVOICE_YES],
		      SOUND_WAVE | SOUND_OGG, false, MIX_WAVE_CHANNEL);

            if (yesno_caller == SYSTEM_SAVE) {
                saveSaveFile(yesno_selected_file_no);
                leaveSystemCall();
            }
            else if (yesno_caller == SYSTEM_LOAD) {
                current_font = &sentence_font;
                if (loadSaveFile(yesno_selected_file_no)) {
                    system_menu_mode = yesno_caller;
                    advancePhase();
                    return;
                }

                leaveSystemCall(false);
                saveon_flag = true;
                internal_saveon_flag = true;
                text_on_flag  = false;
                indent_offset = 0;
                line_enter_status    = 0;
                string_buffer_offset = 0;
                string_buffer_restore = -1;
		break_flag = false;

                if (loadgosub_label)
                    gosubReal(loadgosub_label, script_h.getCurrent());

                readToken();
            }
            else if (yesno_caller == SYSTEM_RESET) {
                resetCommand("reset");
                readToken();
                event_mode = IDLE_EVENT_MODE;
                leaveSystemCall(false);
            }
            else if (yesno_caller == SYSTEM_END) {
                endCommand("end");
            }
        }
        else {
	    playSound(menuselectvoice_file_name[MENUSELECTVOICE_NO],
		      SOUND_WAVE | SOUND_OGG, false, MIX_WAVE_CHANNEL);

            system_menu_mode = yesno_caller & 0xf;
            if (yesno_caller == SYSTEM_RESET)
                leaveSystemCall();

            advancePhase();
        }
    }
    else {
        text_info.fill(0, 0, 0, 0);
	pstring name;

        if (yesno_caller == SYSTEM_SAVE) {
            SaveFileInfo save_file_info;
            searchSaveFile(save_file_info, yesno_selected_file_no);
            processMessage(name, locale.message_save_confirm, save_file_info);
        }
        else if (yesno_caller == SYSTEM_LOAD) {
            SaveFileInfo save_file_info;
            searchSaveFile(save_file_info, yesno_selected_file_no);
            processMessage(name, locale.message_load_confirm, save_file_info);
        }
        else if (yesno_caller == SYSTEM_RESET)
            name = locale.message_reset_confirm;
        else if (yesno_caller == SYSTEM_END)
            name = locale.message_end_confirm;

        current_font->area_x = int (ceil(current_font->StringAdvance(name)));
        current_font->area_y = current_font->line_top(4);
        current_font->top_x  = (screen_width * screen_ratio2 / screen_ratio1 - current_font->area_x) / 2;
        current_font->top_y  = (screen_height * screen_ratio2 / screen_ratio1 - current_font->area_y) / 2;
        current_font->SetXY(0, 0);

	buttons[0] = getSelectableSentence(name, current_font, false);

        flush(refreshMode());

        float yes_len = current_font->StringAdvance(locale.message_yes),
              no_len  = current_font->StringAdvance(locale.message_no);

        name = locale.message_yes;
        current_font->SetXY(float (current_font->area_x) / 4 - yes_len / 2,
			current_font->line_top(2));
	buttons[1] = getSelectableSentence(name, current_font, false);

        name = locale.message_no;
        current_font->SetXY(float (current_font->area_x) * 3 / 4 - no_len / 2,
			current_font->line_top(2));
        buttons[2] = getSelectableSentence(name, current_font, false);

        flush(refreshMode());

        event_mode = WAIT_BUTTON_MODE;
        refreshMouseOverButton();
    }
}
Example #18
0
void ServerController::processClient(sf::Packet &packet, sf::TcpSocket &client)
{
	std::string protocol;
		
	packet >> protocol;
		
	std::cout << "Interpreting Packet Protocol: " << protocol << std::endl;
		
	if(protocol=="LOGIN"){
		loginAccount(packet, client);
	}
	else if(protocol=="REGISTER"){
		registerAccount(packet, client);
	}
	else if(protocol=="CONFERENCE_LIST"){
		getConferences(packet, client);
	}
	else if(protocol=="CONFERENCE_ACCESS"){
		getAccess(packet, client);
	}
	else if(protocol=="VIEW_SUBMISSIONS"){
		getSubmissions(packet, client);
	}
	else if(protocol=="SUBMIT_PAPER"){
		paperSubmission(packet, client);
	}
	else if (protocol=="ADMIN_STATUS"){
		getAdminStatus(packet, client);
	}
	else if (protocol=="CREATE_CONFERENCE"){
		createConference(packet, client);
	}
	else if (protocol=="GET_NOTIFICATIONS"){
		getNotifications(packet, client);
	}
	else if (protocol=="CHECK_PHASE"){
		checkPhase(packet, client);
	}
	else if (protocol=="BID_LIST"){
		bidList(packet, client);
	}
	else if (protocol=="BID_PAPER"){
		bidPaper(packet, client);
	}
	else if (protocol=="ADVANCE_PHASE"){
		advancePhase(packet, client);
	}
	else if(protocol=="BYE"){
		logoutUser(packet, client);
	}
	else if(protocol=="GET_ALLOCATIONS"){
		getAllocations(packet, client);
	}
	else if(protocol=="CONFERENCE_SUBMISSIONS"){
		getConferenceSubs(packet, client);
	}
	else if(protocol=="REVIEW_LIST"){
		getReviewList(packet, client, true);
	}
	else if (protocol=="SUB_DETAIL"){
		sendSubDetail(packet, client);
	}
	else if (protocol=="SUBMIT_REVIEW"){
		submitReview(packet, client);
	}
	else if (protocol=="GET_COMMENTS"){
		getComments(packet, client);
	}
	else if (protocol=="SEND_COMMENT"){
		sendComments(packet, client);
	}
	else if (protocol=="ADD_REVIEWER"){
		addMember(packet, client, Account::Access_Reviewer);
	}
	else if (protocol=="ADD_AUTHOR"){
		addMember(packet, client, Account::Access_Author);
	}
	else if (protocol=="CHANGE_MAX_ALLOCATED_CONF"){
		changeLimit(packet, client, "ALLOCATED");
	}
	else if (protocol=="CHANGE_MAX_PAPERREVIEWERS_CONF"){
		changeLimit(packet, client, "PAPERREV");
	}
	else if (protocol=="GET_MAX_ALLOCATED_CONF"){
		getLimit(packet, client, "ALLOCATED");
	}
	else if (protocol=="GET_MAX_PAPERREVIEWERS_CONF"){
		getLimit(packet, client, "PAPERREV");
	}
	else if (protocol=="GET_FULLNAME"){
		getAccountName(packet, client);
	}
	else if (protocol=="VIEW_REVIEW"){
		getReview(packet, client);
	}
	else if (protocol=="NOTIFY_COUNT"){
		checkNotifyCount(packet, client);
	}
	else if (protocol=="APPROVE_PAPER"){
		decidePaper(packet, client, true);
	}
	else if (protocol=="REJECT_PAPER"){
		decidePaper(packet, client, false);
	}
	else if (protocol=="MY_REVIEWS"){
		getReviewList(packet, client, false);
	}
	else if (protocol=="DID_REVIEW"){
		checkReviewed(packet, client);
	}
	else if (protocol=="FINAL_REVIEW"){
		getFinalReview(packet, client);
	}
	else if (protocol=="CONF_REVIEWERS"){
		getReviewers(packet, client);
	}
	else if (protocol=="CONF_SUBMISSIONS"){
		getConfSubmissions(packet, client);
	}
	else if (protocol=="FILLED_ALLOCATION"){
		checkPaperAlloc(packet, client);
	}
	else if (protocol=="GET_FREE_REVIEWERS"){
		getFreeReviewers(packet, client);
	}
	else if (protocol=="ASSIGN_REVIEWER"){
		assignReviewer(packet, client);
	}
	else if (protocol=="CHANGE_PASSWORD"){
		changePassword(packet, client);
	}
	else {
		std::cout << "Unrecognised protocol" << std::endl;
	}
}
void PonscripterLabel::keyPressEvent(SDL_KeyboardEvent* event)
{
    current_button_state.button = 0;
    current_button_state.down_flag = false;

    // This flag is set by anything before autmode that would like to not interrupt automode.
    // At present, this is volume mute and fullscreen. The commands don't simply return in case
    // the keypresses are handled below (e.g. telling the script the key 'a' was pressed)
    bool automode_ignore = false;

    if (event->type == SDL_KEYUP) {
        if (variable_edit_mode) {
            variableEditMode(event);
            return;
        }

        if (event->keysym.sym == SDLK_m) {
            volume_on_flag = !volume_on_flag;
            setVolumeMute(!volume_on_flag);
            printf("turned %s volume mute\n", !volume_on_flag?"on":"off");
            automode_ignore = true;
        }

        if (event->keysym.sym == SDLK_f) {
            if (fullscreen_mode) menu_windowCommand("menu_window");
            else menu_fullCommand("menu_full");
            return;
            automode_ignore = true;
        }

        if (edit_flag && event->keysym.sym == SDLK_z) {
            variable_edit_mode = EDIT_SELECT_MODE;
            variable_edit_sign = 1;
            variable_edit_num  = 0;
            wm_edit_string = EDIT_MODE_PREFIX EDIT_SELECT_STRING;
            SDL_SetWindowTitle(screen, wm_title_string);
        }
    }

    if (automode_flag && !automode_ignore) {
        remaining_time = -1;
        setAutoMode(false);
        return;
    }

    if (event->type == SDL_KEYUP
        && (event->keysym.sym == SDLK_RETURN
            || event->keysym.sym == SDLK_KP_ENTER
            || event->keysym.sym == SDLK_SPACE
            || event->keysym.sym == SDLK_s))
        setSkipMode(false);

    if (shift_pressed_status && event->keysym.sym == SDLK_q &&
	current_mode == NORMAL_MODE) {
        endCommand("end");
    }

    if ((trap_mode & TRAP_LEFT_CLICK)
        && (event->keysym.sym == SDLK_RETURN
            || event->keysym.sym == SDLK_KP_ENTER
            || event->keysym.sym == SDLK_SPACE)) {
        trapHandler();
        return;
    }
    else if ((trap_mode & TRAP_RIGHT_CLICK)
             && (event->keysym.sym == SDLK_ESCAPE)) {
        trapHandler();
        return;
    }

    const bool wait_button_mode = event_mode & WAIT_BUTTON_MODE;
    const bool key_or_btn = event->type == SDL_KEYUP || btndown_flag;
    const bool enter_key = !getenter_flag &&
	                   (event->keysym.sym == SDLK_RETURN ||
			    event->keysym.sym == SDLK_KP_ENTER);
    const bool space_lclick = spclclk_flag || !useescspc_flag;
    const bool space_key = event->keysym.sym == SDLK_SPACE;
    if (wait_button_mode && ((key_or_btn && enter_key) ||
			     (space_lclick && space_key))) {
	if (event->keysym.sym == SDLK_RETURN   ||
	    event->keysym.sym == SDLK_KP_ENTER ||
	    (spclclk_flag && event->keysym.sym == SDLK_SPACE))
	{
      current_button_state.button =
        volatile_button_state.button = current_over_button;
      if (event->type == SDL_KEYDOWN) {
          current_button_state.down_flag = true;
      }
  }
  else {
	    current_button_state.button =
	    volatile_button_state.button = 0;
	}
	playClickVoice();
	stopAnimation(clickstr_state);
	advancePhase();
	return;
    }

    if (event->type == SDL_KEYDOWN) return;

    if ((event_mode & (WAIT_INPUT_MODE | WAIT_BUTTON_MODE))
        && (autoclick_time == 0 || (event_mode & WAIT_BUTTON_MODE))) {
        if (!useescspc_flag && event->keysym.sym == SDLK_ESCAPE) {
            current_button_state.button = -1;
            if (rmode_flag && event_mode & WAIT_TEXT_MODE) {
                if (!rmenu.empty())
                    system_menu_mode = SYSTEM_MENU;
                else
                    system_menu_mode = SYSTEM_WINDOWERASE;
            }
        }
        else if (useescspc_flag && event->keysym.sym == SDLK_ESCAPE) {
            current_button_state.button = -10;
        }
        else if (!spclclk_flag && useescspc_flag && event->keysym.sym == SDLK_SPACE) {
            current_button_state.button = -11;
        }
        else if (((!getcursor_flag && event->keysym.sym == SDLK_LEFT) ||
                  event->keysym.sym == SDLK_h) &&
                 (event_mode & WAIT_TEXT_MODE ||
                  (usewheel_flag && !getcursor_flag &&
                   event_mode & WAIT_BUTTON_MODE) ||
                  system_menu_mode == SYSTEM_LOOKBACK))
	{
	    current_button_state.button  = -2;
            volatile_button_state.button = -2;
            if (event_mode & WAIT_TEXT_MODE) system_menu_mode = SYSTEM_LOOKBACK;
        }
        else if (((!getcursor_flag && event->keysym.sym == SDLK_RIGHT) ||
                  event->keysym.sym == SDLK_l) &&
                 ((enable_wheeldown_advance_flag &&
                   event_mode & WAIT_TEXT_MODE) ||
		  (usewheel_flag && event_mode & WAIT_BUTTON_MODE) ||
                  system_menu_mode == SYSTEM_LOOKBACK))
	{
	    if (event_mode & WAIT_TEXT_MODE) {
                current_button_state.button  = 0;
                volatile_button_state.button = 0;
            }
            else {
                current_button_state.button  = -3;
                volatile_button_state.button = -3;
            }
        }
	else if (((!getcursor_flag && event->keysym.sym == SDLK_UP) ||
                  event->keysym.sym == SDLK_k ||
                  event->keysym.sym == SDLK_p) &&
                 event_mode & WAIT_BUTTON_MODE){
            shiftCursorOnButton(1);
            return;
        }
        else if (((!getcursor_flag && event->keysym.sym == SDLK_DOWN) ||
                  event->keysym.sym == SDLK_j ||
                  event->keysym.sym == SDLK_n) &&
                 event_mode & WAIT_BUTTON_MODE){
            shiftCursorOnButton(-1);
            return;
        }
	else if (getpageup_flag && event->keysym.sym == SDLK_PAGEUP) {
            current_button_state.button = -12;
        }
        else if (getpagedown_flag && event->keysym.sym == SDLK_PAGEDOWN) {
            current_button_state.button = -13;
        }
        else if ((getenter_flag && event->keysym.sym == SDLK_RETURN)
                 || (getenter_flag && event->keysym.sym == SDLK_KP_ENTER)) {
            current_button_state.button = -19;
        }
        else if (gettab_flag && event->keysym.sym == SDLK_TAB) {
            current_button_state.button = -20;
        }
        else if (getcursor_flag && event->keysym.sym == SDLK_UP) {
            current_button_state.button = -40;
        }
        else if (getcursor_flag && event->keysym.sym == SDLK_RIGHT) {
            current_button_state.button = -41;
        }
        else if (getcursor_flag && event->keysym.sym == SDLK_DOWN) {
            current_button_state.button = -42;
        }
        else if (getcursor_flag && event->keysym.sym == SDLK_LEFT) {
            current_button_state.button = -43;
        }
        else if (getinsert_flag && event->keysym.sym == SDLK_INSERT) {
            current_button_state.button = -50;
        }
        else if (getzxc_flag && event->keysym.sym == SDLK_z) {
            current_button_state.button = -51;
        }
        else if (getzxc_flag && event->keysym.sym == SDLK_x) {
            current_button_state.button = -52;
        }
        else if (getzxc_flag && event->keysym.sym == SDLK_c) {
            current_button_state.button = -53;
        }
        else if (getfunction_flag) {
            if (event->keysym.sym == SDLK_F1)
                current_button_state.button = -21;
            else if (event->keysym.sym == SDLK_F2)
                current_button_state.button = -22;
            else if (event->keysym.sym == SDLK_F3)
                current_button_state.button = -23;
            else if (event->keysym.sym == SDLK_F4)
                current_button_state.button = -24;
            else if (event->keysym.sym == SDLK_F5)
                current_button_state.button = -25;
            else if (event->keysym.sym == SDLK_F6)
                current_button_state.button = -26;
            else if (event->keysym.sym == SDLK_F7)
                current_button_state.button = -27;
            else if (event->keysym.sym == SDLK_F8)
                current_button_state.button = -28;
            else if (event->keysym.sym == SDLK_F9)
                current_button_state.button = -29;
            else if (event->keysym.sym == SDLK_F10)
                current_button_state.button = -30;
            else if (event->keysym.sym == SDLK_F11)
                current_button_state.button = -31;
            else if (event->keysym.sym == SDLK_F12)
                current_button_state.button = -32;
        }

        if (current_button_state.button != 0) {
            volatile_button_state.button = current_button_state.button;
            stopAnimation(clickstr_state);
            advancePhase();
            return;
        }
    }

    if (event_mode & WAIT_INPUT_MODE && !key_pressed_flag
        && (autoclick_time == 0 || (event_mode & WAIT_BUTTON_MODE))) {
        if (event->keysym.sym == SDLK_RETURN
            || event->keysym.sym == SDLK_KP_ENTER
            || event->keysym.sym == SDLK_SPACE) {
            key_pressed_flag = true;
            playClickVoice();
            stopAnimation(clickstr_state);
            advancePhase();
        }
    }

    if (event_mode & (WAIT_INPUT_MODE | WAIT_TEXTBTN_MODE)
        && !key_pressed_flag) {
        if (event->keysym.sym == SDLK_s && !automode_flag) {
            setSkipMode(true);
            //printf("toggle skip to true\n");
            key_pressed_flag = true;
            stopAnimation(clickstr_state);
            advancePhase();
        }
        else if (event->keysym.sym == SDLK_o) {
            draw_one_page_flag = !draw_one_page_flag;
            //printf("toggle draw one page flag to %s\n", (draw_one_page_flag ? "true" : "false"));
            if (draw_one_page_flag) {
                stopAnimation(clickstr_state);
                advancePhase();
            }
        }
        else if (event->keysym.sym == SDLK_a && mode_ext_flag &&
                 !automode_flag)
        {
            setAutoMode(true);
            //printf("change to automode\n");
            key_pressed_flag = true;
            stopAnimation(clickstr_state);
            advancePhase();
        }
        else if (event->keysym.sym == SDLK_0) {
            if (++text_speed_no > 2) text_speed_no = 0;

            sentence_font.wait_time = -1;
        }
        else if (event->keysym.sym == SDLK_1) {
            text_speed_no = 0;
            sentence_font.wait_time = -1;
        }
        else if (event->keysym.sym == SDLK_2) {
            text_speed_no = 1;
            sentence_font.wait_time = -1;
        }
        else if (event->keysym.sym == SDLK_3) {
            text_speed_no = 2;
            sentence_font.wait_time = -1;
        }
    }

    if (event_mode & WAIT_SLEEP_MODE) {
      if (event->keysym.sym == SDLK_RETURN ||
          event->keysym.sym == SDLK_KP_ENTER ||
          event->keysym.sym == SDLK_SPACE) {
        skip_to_wait = 1;
      }
    }
}
/* **************************************** *
* Event loop
* **************************************** */
int PonscripterLabel::eventLoop()
{
    SDL_Event event, tmp_event;

    /* Note, this rate can change if the window is dragged to a new
       screen or the monitor settings are changed while running.
       We do not handle either of these cases */
    Uint32 refresh_delay = getRefreshRateDelay();
    Uint32 last_refresh = 0, current_time;
    timer_event_flag = false;
#ifdef WIN32
    Uint32 win_flags;
#endif

    queueRerender();

    advancePhase();

    // when we're on the first of a button-waiting frame (menu, etc), we snap mouse cursor to button when
    //   using keyboard/gamecontroller to vastly improve the experience when using not using a mouse directly
    bool using_buttonbased_movement = true;  // true to snap to main menu when it loads
    first_buttonwait_mode_frame = false;  // if it's the first frame of a buttonwait (menu/choice), snap to default button
    SDL_GetMouseState(&last_mouse_x, &last_mouse_y);

    while (SDL_WaitEvent(&event)) {
        // ignore continous SDL_MOUSEMOTION
        while (event.type == SDL_MOUSEMOTION) {
            if (SDL_PeepEvents(&tmp_event, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT) == 0) break;

            // improve using keyboard/gamecontroller controls
            if ((last_mouse_x != ( (SDL_MouseButtonEvent *) &event)->x) || (last_mouse_y != ( (SDL_MouseButtonEvent *) &event)->y)) {
                using_buttonbased_movement = false;

                last_mouse_x = ( (SDL_MouseButtonEvent *) &event)->x;
                last_mouse_y = ( (SDL_MouseButtonEvent *) &event)->y;
            }

            if (tmp_event.type != SDL_MOUSEMOTION) break;

            SDL_PeepEvents(&tmp_event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT);
            event = tmp_event;
        }

        switch (event.type) {
        case SDL_MOUSEMOTION:
            mouseMoveEvent((SDL_MouseMotionEvent*) &event);
            break;

        case SDL_MOUSEBUTTONDOWN:
            current_button_state.down_x = ( (SDL_MouseButtonEvent *) &event)->x;
            current_button_state.down_y = ( (SDL_MouseButtonEvent *) &event)->y;
            current_button_state.ignore_mouseup = false;
            if (!btndown_flag) break;

        case SDL_MOUSEBUTTONUP:
            mousePressEvent((SDL_MouseButtonEvent*) &event);
            break;

        case SDL_MOUSEWHEEL:
            mouseWheelEvent(&event.wheel);
            break;

        // NOTE: we reverse KEYUP and KEYDOWN for controller presses, because otherwise it feels really slow and junky
        // If necessary, we can make keyPressEvent actually interpret controller keys but this works fine for now
        case SDL_CONTROLLERBUTTONDOWN:
            using_buttonbased_movement = true;
            event.key.type = SDL_KEYUP;
            // printf("Controller button press: %s\n", SDL_GameControllerGetStringForButton((SDL_GameControllerButton)event.cbutton.button));
            event.key.keysym.sym = transControllerButton(event.cbutton.button);
            if (event.key.keysym.sym == SDLK_UNKNOWN)
                break;

            event.key.keysym.sym = transKey(event.key.keysym.sym);

            keyDownEvent((SDL_KeyboardEvent*) &event);
            keyPressEvent((SDL_KeyboardEvent*) &event);

            break;

        case SDL_CONTROLLERBUTTONUP:
            using_buttonbased_movement = true;
            event.key.type = SDL_KEYDOWN;
            // printf("Controller button release: %s\n", SDL_GameControllerGetStringForButton((SDL_GameControllerButton)event.cbutton.button));
            event.key.keysym.sym = transControllerButton(event.cbutton.button);
            if (event.key.keysym.sym == SDLK_UNKNOWN)
                break;

            event.key.keysym.sym = transKey(event.key.keysym.sym);

            keyUpEvent((SDL_KeyboardEvent*) &event);
            if (btndown_flag)
                keyPressEvent((SDL_KeyboardEvent*) &event);

            break;

        case SDL_JOYBUTTONDOWN:
            using_buttonbased_movement = true;
            event.key.type = SDL_KEYDOWN;
            event.key.keysym.sym = transJoystickButton(event.jbutton.button);
            if (event.key.keysym.sym == SDLK_UNKNOWN)
                break;

        case SDL_KEYDOWN:
            if ((event.key.keysym.sym == SDLK_UP) || (event.key.keysym.sym == SDLK_DOWN) ||
                (event.key.keysym.sym == SDLK_LEFT) || (event.key.keysym.sym == SDLK_RIGHT))
                using_buttonbased_movement = true;
            event.key.keysym.sym = transKey(event.key.keysym.sym);
            keyDownEvent((SDL_KeyboardEvent*) &event);
            if (btndown_flag)
                keyPressEvent((SDL_KeyboardEvent*) &event);

            break;

        case SDL_JOYBUTTONUP:
            using_buttonbased_movement = true;
            event.key.type = SDL_KEYUP;
            event.key.keysym.sym = transJoystickButton(event.jbutton.button);
            if (event.key.keysym.sym == SDLK_UNKNOWN)
                break;

        case SDL_KEYUP:
            event.key.keysym.sym = transKey(event.key.keysym.sym);
            keyUpEvent((SDL_KeyboardEvent*) &event);
            keyPressEvent((SDL_KeyboardEvent*) &event);
            break;

        case SDL_JOYAXISMOTION:
        {
            SDL_KeyboardEvent ke = transJoystickAxis(event.jaxis);
            if (ke.keysym.sym != SDLK_UNKNOWN) {
                if (ke.type == SDL_KEYDOWN) {
                    keyDownEvent(&ke);
                    if (btndown_flag)
                        keyPressEvent(&ke);
                }
                else if (ke.type == SDL_KEYUP) {
                    keyUpEvent(&ke);
                    keyPressEvent(&ke);
                }
            }

            break;
        }

        case ONS_SOUND_EVENT:
        case ONS_FADE_EVENT:
        case ONS_MIDI_EVENT:
        case ONS_MUSIC_EVENT:
            flushEventSub(event);
            break;

        case INTERNAL_REDRAW_EVENT:
            /* Handle cursor shifting for controller/keyboard button-based movement */
            if (first_buttonwait_mode_frame && using_buttonbased_movement && buttons.size() > 1) {
                shiftCursorOnButton(0);
            }

            if (event_mode & WAIT_BUTTON_MODE)
                first_buttonwait_mode_frame = true;
            else if (first_buttonwait_mode_frame)
                first_buttonwait_mode_frame = false;

            /* Stop rerendering while minimized; wait for the restore event + queueRerender */
            if(minimized_flag) {
                break;
            }

            current_time = SDL_GetTicks();
            if((current_time - last_refresh) >= refresh_delay || last_refresh == 0) {
                /* It has been longer than the refresh delay since we last started a refresh. Start another */

                last_refresh = current_time;
                rerender();

                /* Refresh time since rerender does take some odd ms */
                current_time = SDL_GetTicks();
            }

            SDL_PumpEvents();
            /* Remove all pending redraw events on the queue */
            while(SDL_PeepEvents(&tmp_event, 1, SDL_GETEVENT, INTERNAL_REDRAW_EVENT, INTERNAL_REDRAW_EVENT) == 1)
                ;

            /* If there are any events on the queue, re-add us and let it get those events asap.
             * It'll then come back to us with no events and we'll just sleep until it's time to redraw again.
             * If there are no events, sleep right away
             */
            if(SDL_PeepEvents(&tmp_event, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT) == 0) {
                if(timer_event_flag && timer_event_time <= current_time) {
                    timer_event_flag = false;

                    timerEvent();
                } else if(last_refresh <= current_time && refresh_delay >= (current_time - last_refresh)) {
                    SDL_Delay(std::min(refresh_delay / 3, refresh_delay - (current_time - last_refresh)));
                }
            }
            tmp_event.type = INTERNAL_REDRAW_EVENT;
            SDL_PushEvent(&tmp_event);

            break;

        case ONS_WAVE_EVENT:
            flushEventSub(event);
            //printf("ONS_WAVE_EVENT %d: %x %d %x\n", event.user.code, wave_sample[0], automode_flag, event_mode);
            if (event.user.code != 0
                || !(event_mode & WAIT_VOICE_MODE)) break;

            if (remaining_time <= 0) {
                event_mode &= ~WAIT_VOICE_MODE;
                if (automode_flag)
                    current_button_state.button = 0;
                else if (usewheel_flag)
                    current_button_state.button = -5;
                else
                    current_button_state.button = -2;

                stopAnimation(clickstr_state);
                advancePhase();
            }

            break;

        case SDL_WINDOWEVENT:
            switch(event.window.event) {
              case SDL_WINDOWEVENT_FOCUS_LOST:
                break;
              case SDL_WINDOWEVENT_FOCUS_GAINED:
                /* See comment below under RESIZED */
                SDL_PumpEvents();
                SDL_PeepEvents(&tmp_event, 1, SDL_GETEVENT, SDL_MOUSEBUTTONDOWN, SDL_MOUSEBUTTONDOWN);
                current_button_state.ignore_mouseup = true;
#ifdef WIN32
                win_flags = SDL_GetWindowFlags(screen);
                /* Work around: https://bugzilla.libsdl.org/show_bug.cgi?id=2510
                 *
                 * On windows, the RESTORED event does not occur when you restore a
                 * maximized event. The only events you get are a ton of exposes and
                 * this one. The screen also remains black if it was maximized until
                 * the window is "restored".
                 */
                SDL_RestoreWindow(screen);
                if(win_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) {
                    SDL_SetWindowFullscreen(screen, SDL_WINDOW_FULLSCREEN_DESKTOP);
                } else if(win_flags & SDL_WINDOW_FULLSCREEN) {
                    SDL_SetWindowFullscreen(screen, SDL_WINDOW_FULLSCREEN);
                } else if(win_flags & SDL_WINDOW_MAXIMIZED) {
                    SDL_MaximizeWindow(screen);
                }
#endif
                break;
              case SDL_WINDOWEVENT_MAXIMIZED:
              case SDL_WINDOWEVENT_RESIZED:
                /* Due to what I suspect is an SDL bug, you get a mosuedown +
                 * mouseup event when you maximize the window by double
                 * clicking the titlebar in windows. These events both have
                 * coordinates inside of the screen, and I can't see any way
                 * to tell them apart from legitimate clicks. (it even triggers
                 * a mouse move event).
                 * To fix this bug, we kill any mousedown events when we maximize.
                 * Note, we do this under RESIZED too because if you do a
                 * "vertical maximize" (double click with the upper resize arrow)
                 * that doesn't trigger a maximized event
                 */
                SDL_PumpEvents();
                SDL_PeepEvents(&tmp_event, 1, SDL_GETEVENT, SDL_MOUSEBUTTONDOWN, SDL_MOUSEBUTTONDOWN);
                current_button_state.ignore_mouseup = true;
              case SDL_WINDOWEVENT_RESTORED:
              case SDL_WINDOWEVENT_SHOWN:
              case SDL_WINDOWEVENT_EXPOSED:
                /* If we weren't minimized, a rerender is already queued */
                if(minimized_flag) {
                    minimized_flag = false;
                    queueRerender();
                }
                break;
              case SDL_WINDOWEVENT_MINIMIZED:
              case SDL_WINDOWEVENT_HIDDEN:
                minimized_flag = true;
                break;
            }
            break;

        case SDL_QUIT:
            endCommand("end");
            break;

        default:
            break;
        }
    }
    return -1;
}
int ONScripterLabel::processText()
{
    //printf("textCommand %c %d %d %d\n", script_h.getStringBuffer()[ string_buffer_offset ], string_buffer_offset, event_mode, line_enter_status);
    char out_text[3]= {'\0', '\0', '\0'};

    if ( event_mode & (WAIT_INPUT_MODE | WAIT_SLEEP_MODE) ){
        draw_cursor_flag = false;
        if ( clickstr_state == CLICK_WAIT ){
            if (script_h.checkClickstr(script_h.getStringBuffer() + string_buffer_offset) != 1) string_buffer_offset++;
            string_buffer_offset++;
            clickstr_state = CLICK_NONE;
        }
        else if ( clickstr_state == CLICK_NEWPAGE ){
            event_mode = IDLE_EVENT_MODE;
            if (script_h.checkClickstr(script_h.getStringBuffer() + string_buffer_offset) != 1) string_buffer_offset++;
            string_buffer_offset++;
            newPage( true );
            clickstr_state = CLICK_NONE;
            return RET_CONTINUE | RET_NOREAD;
        }
        else if ( IS_TWO_BYTE(script_h.getStringBuffer()[ string_buffer_offset ]) ){
            string_buffer_offset += 2;
        }
        else if ( script_h.getStringBuffer()[ string_buffer_offset ] == '!' ){
            string_buffer_offset++;
            if ( script_h.getStringBuffer()[ string_buffer_offset ] == 'w' || script_h.getStringBuffer()[ string_buffer_offset ] == 'd' ){
                string_buffer_offset++;
                while ( script_h.getStringBuffer()[ string_buffer_offset ] >= '0' &&
                        script_h.getStringBuffer()[ string_buffer_offset ] <= '9' )
                    string_buffer_offset++;
                while (script_h.getStringBuffer()[ string_buffer_offset ] == ' ' ||
                       script_h.getStringBuffer()[ string_buffer_offset ] == '\t') string_buffer_offset++;
            }
        }
        else if ( script_h.getStringBuffer()[ string_buffer_offset + 1 ] &&
                  !(script_h.getEndStatus() & ScriptHandler::END_1BYTE_CHAR) ){
            string_buffer_offset += 2;
        }
        else
            string_buffer_offset++;

        event_mode = IDLE_EVENT_MODE;
    }

    
    if (script_h.getStringBuffer()[string_buffer_offset] == 0x0a ||
        script_h.getStringBuffer()[string_buffer_offset] == 0x00){
        indent_offset = 0; // redundant
        return RET_CONTINUE;
    }

    new_line_skip_flag = false;
    
    //printf("*** textCommand %d (%d,%d)\n", string_buffer_offset, sentence_font.xy[0], sentence_font.xy[1]);

    while( (!(script_h.getEndStatus() & ScriptHandler::END_1BYTE_CHAR) &&
            script_h.getStringBuffer()[ string_buffer_offset ] == ' ') ||
           script_h.getStringBuffer()[ string_buffer_offset ] == '\t' ) string_buffer_offset ++;

    char ch = script_h.getStringBuffer()[string_buffer_offset];
    if ( IS_TWO_BYTE(ch) ){ // Shift jis
        /* ---------------------------------------- */
        /* Kinsoku process */
        if (IS_KINSOKU( script_h.getStringBuffer() + string_buffer_offset + 2)){
            int i = 2;
            while (!sentence_font.isEndOfLine(i) &&
                   IS_KINSOKU( script_h.getStringBuffer() + string_buffer_offset + i + 2)){
                i += 2;
            }

            if (sentence_font.isEndOfLine(i)){
                sentence_font.newLine();
                for (int i=0 ; i<indent_offset ; i++){
                    current_page->add(LOC_TWOBYTE_SYMBOL(' ')[0]);
                    current_page->add(LOC_TWOBYTE_SYMBOL(' ')[1]);
                    sentence_font.advanceCharInHankaku(2);
                }
            }
        }
        
        out_text[0] = script_h.getStringBuffer()[string_buffer_offset];
        out_text[1] = script_h.getStringBuffer()[string_buffer_offset+1];
        if ( clickstr_state == CLICK_IGNORE ){
            clickstr_state = CLICK_NONE;
        }
        else{
            if (script_h.checkClickstr(&script_h.getStringBuffer()[string_buffer_offset]) > 0){
                if (sentence_font.getRemainingLine() <= clickstr_line)
                    return clickNewPage( out_text );
                else
                    return clickWait( out_text );
            }
            else{
                clickstr_state = CLICK_NONE;
            }
        }
        
        if ( skip_flag || draw_one_page_flag || ctrl_pressed_status ){
            drawChar( out_text, &sentence_font, false, true, accumulation_surface, &text_info );
            num_chars_in_sentence++;
                
            string_buffer_offset += 2;
            return RET_CONTINUE | RET_NOREAD;
        }
        else{
            drawChar( out_text, &sentence_font, true, true, accumulation_surface, &text_info );
            num_chars_in_sentence++;
            event_mode = WAIT_SLEEP_MODE;
            if ( sentence_font.wait_time == -1 )
                advancePhase( default_text_speed[text_speed_no] );
            else
                advancePhase( sentence_font.wait_time );
            return RET_WAIT | RET_NOREAD;
        }
    }
    else if ( ch == '@' ){ // wait for click
        return clickWait( NULL );
    }
    else if ( ch == '\\' ){ // new page
        return clickNewPage( NULL );
    }
    else if ( ch == '_' ){ // Ignore following forced return
        clickstr_state = CLICK_IGNORE;
        string_buffer_offset++;
        return RET_CONTINUE | RET_NOREAD;
    }
    else if ( ch == '!' && !(script_h.getEndStatus() & ScriptHandler::END_1BYTE_CHAR) ){
        string_buffer_offset++;
        if ( script_h.getStringBuffer()[ string_buffer_offset ] == 's' ){
            string_buffer_offset++;
            if ( script_h.getStringBuffer()[ string_buffer_offset ] == 'd' ){
                sentence_font.wait_time = -1;
                string_buffer_offset++;
            }
            else{
                int t = 0;
                while( script_h.getStringBuffer()[ string_buffer_offset ] >= '0' &&
                       script_h.getStringBuffer()[ string_buffer_offset ] <= '9' ){
                    t = t*10 + script_h.getStringBuffer()[ string_buffer_offset ] - '0';
                    string_buffer_offset++;
                }
                sentence_font.wait_time = t;
                while (script_h.getStringBuffer()[ string_buffer_offset ] == ' ' ||
                       script_h.getStringBuffer()[ string_buffer_offset ] == '\t') string_buffer_offset++;
            }
        }
        else if ( script_h.getStringBuffer()[ string_buffer_offset ] == 'w' ||
                  script_h.getStringBuffer()[ string_buffer_offset ] == 'd' ){
            bool flag = false;
            if ( script_h.getStringBuffer()[ string_buffer_offset ] == 'd' ) flag = true;
            string_buffer_offset++;
            int tmp_string_buffer_offset = string_buffer_offset;
            int t = 0;
            while( script_h.getStringBuffer()[ string_buffer_offset ] >= '0' &&
                   script_h.getStringBuffer()[ string_buffer_offset ] <= '9' ){
                t = t*10 + script_h.getStringBuffer()[ string_buffer_offset ] - '0';
                string_buffer_offset++;
            }
            while (script_h.getStringBuffer()[ string_buffer_offset ] == ' ' ||
                   script_h.getStringBuffer()[ string_buffer_offset ] == '\t') string_buffer_offset++;
            if ( skip_flag || draw_one_page_flag || ctrl_pressed_status ){
                return RET_CONTINUE | RET_NOREAD;
            }
            else{
                event_mode = WAIT_SLEEP_MODE;
                if ( flag ) event_mode |= WAIT_INPUT_MODE;
                key_pressed_flag = false;
                startTimer( t );
                string_buffer_offset = tmp_string_buffer_offset - 2;
                return RET_WAIT | RET_NOREAD;
            }
        }
        return RET_CONTINUE | RET_NOREAD;
    }
    else if ( ch == '#' && !(script_h.getEndStatus() & ScriptHandler::END_1BYTE_CHAR) ){
        readColor( &sentence_font.color, script_h.getStringBuffer() + string_buffer_offset );
        readColor( &ruby_font.color, script_h.getStringBuffer() + string_buffer_offset );
        string_buffer_offset += 7;
        return RET_CONTINUE | RET_NOREAD;
    }
    else if ( ch == '(' && !(script_h.getEndStatus() & ScriptHandler::END_1BYTE_CHAR)){
        current_page->add('(');
        startRuby( script_h.getStringBuffer() + string_buffer_offset + 1, sentence_font );
        
        string_buffer_offset++;
        return RET_CONTINUE | RET_NOREAD;
    }
    else if ( ch == '/' && !(script_h.getEndStatus() & ScriptHandler::END_1BYTE_CHAR) ){
        if ( ruby_struct.stage == RubyStruct::BODY ){
            current_page->add('/');
            sentence_font.addLineOffset(ruby_struct.margin);
            string_buffer_offset = ruby_struct.ruby_end - script_h.getStringBuffer();
            if (*ruby_struct.ruby_end == ')'){
                if ( skip_flag || draw_one_page_flag || ctrl_pressed_status )
                    endRuby(false, true, accumulation_surface, &text_info);
                else
                    endRuby(true, true, accumulation_surface, &text_info);
                current_page->add(')');
                string_buffer_offset++;
            }

            return RET_CONTINUE | RET_NOREAD;
        }
        else{ // skip new line
            new_line_skip_flag = true;
            string_buffer_offset++;
            if (script_h.getStringBuffer()[string_buffer_offset] != 0x0a)
                errorAndExit( "'new line' must follow '/'." );
            return RET_CONTINUE; // skip the following eol
        }
    }
    else if ( ch == ')' && !(script_h.getEndStatus() & ScriptHandler::END_1BYTE_CHAR) &&
              ruby_struct.stage == RubyStruct::BODY ){
        current_page->add(')');
        string_buffer_offset++;
        ruby_struct.stage = RubyStruct::NONE;
        return RET_CONTINUE | RET_NOREAD;
    }
    else{
        out_text[0] = ch;
        
        if ( clickstr_state == CLICK_IGNORE ){
            clickstr_state = CLICK_NONE;
        }
        else{
            int matched_len = script_h.checkClickstr(script_h.getStringBuffer() + string_buffer_offset);

            if (matched_len > 0){
                if (matched_len == 2) out_text[1] = script_h.getStringBuffer()[ string_buffer_offset + 1 ];
                if (sentence_font.getRemainingLine() <= clickstr_line)
                    return clickNewPage( out_text );
                else
                    return clickWait( out_text );
            }
            else if (script_h.getStringBuffer()[ string_buffer_offset + 1 ] &&
                     script_h.checkClickstr(&script_h.getStringBuffer()[string_buffer_offset+1]) == 1 &&
                     script_h.getEndStatus() & ScriptHandler::END_1BYTE_CHAR){
                if ( script_h.getStringBuffer()[ string_buffer_offset + 2 ] &&
                     script_h.checkClickstr(&script_h.getStringBuffer()[string_buffer_offset+2]) > 0){
                    clickstr_state = CLICK_NONE;
                }
                else if (script_h.getStringBuffer()[ string_buffer_offset + 1 ] == '@'){
                    return clickWait( out_text );
                }
                else if (script_h.getStringBuffer()[ string_buffer_offset + 1 ] == '\\'){
                    return clickNewPage( out_text );
                }
                else{
                    out_text[1] = script_h.getStringBuffer()[ string_buffer_offset + 1 ];
                    if (sentence_font.getRemainingLine() <= clickstr_line)
                        return clickNewPage( out_text );
                    else
                        return clickWait( out_text );
                }
            }
            else{
                clickstr_state = CLICK_NONE;
            }
        }
        
        bool flush_flag = true;
        if ( skip_flag || draw_one_page_flag || ctrl_pressed_status )
            flush_flag = false;
        if ( script_h.getStringBuffer()[ string_buffer_offset + 1 ] &&
             script_h.getStringBuffer()[ string_buffer_offset + 1 ] != 0x0a &&
             !(script_h.getEndStatus() & ScriptHandler::END_1BYTE_CHAR)){
            out_text[1] = script_h.getStringBuffer()[ string_buffer_offset + 1 ];
            drawDoubleChars( out_text, &sentence_font, flush_flag, true, accumulation_surface, &text_info );
            num_chars_in_sentence++;
        }
        else if (script_h.getEndStatus() & ScriptHandler::END_1BYTE_CHAR){
            drawDoubleChars( out_text, &sentence_font, flush_flag, true, accumulation_surface, &text_info );
            num_chars_in_sentence++;
        }
        
        if ( skip_flag || draw_one_page_flag || ctrl_pressed_status ){
            if ( script_h.getStringBuffer()[ string_buffer_offset + 1 ] &&
                 !(script_h.getEndStatus() & ScriptHandler::END_1BYTE_CHAR))
                string_buffer_offset++;
            string_buffer_offset++;
            return RET_CONTINUE | RET_NOREAD;
        }
        else{
            event_mode = WAIT_SLEEP_MODE;
            if ( sentence_font.wait_time == -1 )
                advancePhase( default_text_speed[text_speed_no] );
            else
                advancePhase( sentence_font.wait_time );
            return RET_WAIT | RET_NOREAD;
        }
    }

    return RET_NOMATCH;
}
void PonscripterLabel::timerEvent(void)
{
    timerEventTop:

    int ret;

    if (event_mode & WAIT_TIMER_MODE) {
        int duration = proceedAnimation();

        if (duration == 0
            || (remaining_time >= 0
                && remaining_time - duration <= 0)) {
            bool end_flag  = true;
            bool loop_flag = false;
            if (remaining_time >= 0) {
                remaining_time = -1;
                if (event_mode & WAIT_VOICE_MODE && wave_sample[0]) {
                    end_flag = false;
                    if (duration > 0) {
                        resetRemainingTime(duration);
                        advancePhase(duration);
                    }
                }
                else {
                    loop_flag = true;
                    if (automode_flag || autoclick_time > 0)
                        current_button_state.button = 0;
                    else if (usewheel_flag)
                        current_button_state.button = -5;
                    else
                        current_button_state.button = -2;
                }
            }

            if (end_flag
                && event_mode & (WAIT_INPUT_MODE | WAIT_BUTTON_MODE)
                && (clickstr_state == CLICK_WAIT
                    || clickstr_state == CLICK_NEWPAGE)) {
                playClickVoice();
                stopAnimation(clickstr_state);
            }

            if (end_flag || duration == 0)
                event_mode &= ~WAIT_TIMER_MODE;

            if (loop_flag) goto timerEventTop;
        }
        else {
            if (remaining_time > 0)
                remaining_time -= duration;

            resetRemainingTime(duration);
            advancePhase(duration);
        }
    }
    else if (event_mode & EFFECT_EVENT_MODE) {
        const char* current = script_h.getCurrent();
        ret = this->parseLine();

        if (ret & RET_CONTINUE) {
            if (ret == RET_CONTINUE) {
                readToken(); // skip trailing \0 and mark kidoku
            }

            if (effect_blank == 0 || effect_counter == 0) goto timerEventTop;

            startTimer(effect_blank);
        }
        else {
            script_h.setCurrent(current);
            readToken();
            advancePhase();
        }

        return;
    }
    else {
        if (system_menu_mode != SYSTEM_NULL
            || (event_mode & WAIT_INPUT_MODE
                && volatile_button_state.button == -1)) {
            if (!system_menu_enter_flag)
                event_mode |= WAIT_TIMER_MODE;

            executeSystemCall();
        }
        else
            executeLabel();
    }

    volatile_button_state.button = 0;
}
void PonscripterLabel::flushEventSub(SDL_Event &event)
{
    if (event.type == ONS_SOUND_EVENT) {
        if (music_play_loop_flag) {
            stopBGM(true);
            if (music_file_name)
                playSound(music_file_name, SOUND_OGG_STREAMING | SOUND_MP3, true);
        }
        else {
            stopBGM(false);
        }
    }
// The event handler for the mp3 fadeout event itself.  Simply sets the volume of the mp3 being played lower and lower until it's 0,
// and until the requisite mp3 fadeout time has passed.  Recommend for integration.  [Seung Park, 20060621]
    else if (event.type == ONS_FADE_EVENT) {
        if (skip_flag || draw_one_page_flag ||
            ctrl_pressed_status || skip_to_wait)
        {
            mp3fadeout_duration = 0;
            if (mp3_sample) SMPEG_setvolume(mp3_sample, 0);
        }

        Uint32 tmp = SDL_GetTicks() - mp3fadeout_start;
        if (tmp < mp3fadeout_duration) {
            tmp  = mp3fadeout_duration - tmp;
            tmp *= music_volume;
            tmp /= mp3fadeout_duration;

            if (mp3_sample) SMPEG_setvolume(mp3_sample, tmp);
        }
        else {
            SDL_RemoveTimer(timer_mp3fadeout_id);
            timer_mp3fadeout_id = 0;

            event_mode &= ~WAIT_TIMER_MODE;
            stopBGM(false);
            advancePhase();
        }
    }
    else if (event.type == ONS_MIDI_EVENT) {
#ifdef MACOSX
        if (!Mix_PlayingMusic()) {
            ext_music_play_once_flag = !midi_play_loop_flag;
            Mix_FreeMusic(midi_info);
            playMIDI(midi_play_loop_flag);
        }

#else
        ext_music_play_once_flag = !midi_play_loop_flag;
        Mix_FreeMusic(midi_info);
        playMIDI(midi_play_loop_flag);
#endif
    }
    else if (event.type == ONS_MUSIC_EVENT) {
        ext_music_play_once_flag = !music_play_loop_flag;
        Mix_FreeMusic(music_info);
        playExternalMusic(music_play_loop_flag);
    }
    else if (event.type == ONS_WAVE_EVENT) { // for processing btntim2 and automode correctly
        if (wave_sample[event.user.code]) {
            Mix_FreeChunk(wave_sample[event.user.code]);
            wave_sample[event.user.code] = NULL;
            if (event.user.code == MIX_LOOPBGM_CHANNEL0
                && loop_bgm_name[1]
                && wave_sample[MIX_LOOPBGM_CHANNEL1])
                Mix_PlayChannel(MIX_LOOPBGM_CHANNEL1,
                    wave_sample[MIX_LOOPBGM_CHANNEL1], -1);
        }
    }
}