// Frees the flares as they expire. void animateFlares(flare **flares, short count) { LIGHTING_STATE *lights; boolean inView, fastForward, atLeastOneFlareStillActive; short i; // i iterates through the flare list #ifdef BROGUE_ASSERTS assert(rogue.RNG == RNG_SUBSTANTIVE); #endif lights = backUpLighting(); fastForward = rogue.trueColorMode || rogue.playbackFastForward; do { inView = false; atLeastOneFlareStillActive = false; for (i = 0; i < count; i++) { if (flares[i]) { if (updateFlare(flares[i])) { atLeastOneFlareStillActive = true; if (drawFlareFrame(flares[i])) { inView = true; } } else { free(flares[i]); flares[i] = NULL; } } } demoteVisibility(); updateFieldOfViewDisplay(false, true); if (!fastForward && (inView || rogue.playbackOmniscience) && atLeastOneFlareStillActive) { fastForward = pauseBrogue(10); } recordOldLights(); restoreLighting(lights); } while (atLeastOneFlareStillActive); freeLightingState(lights); updateFieldOfViewDisplay(false, true); }
void titleMenu() { signed short flames[COLS][(ROWS + MENU_FLAME_ROW_PADDING)][3]; // red, green and blue signed short colorSources[MENU_FLAME_COLOR_SOURCE_COUNT][4]; // red, green, blue, and rand, one for each color source (no more than MENU_FLAME_COLOR_SOURCE_COUNT). color *colors[COLS][(ROWS + MENU_FLAME_ROW_PADDING)]; unsigned char mask[COLS][ROWS]; boolean controlKeyWasDown = false; short i, b, x, y, button; buttonState state; brogueButton buttons[6]; char whiteColorEscape[10] = ""; char goldColorEscape[10] = ""; char newGameText[100] = "", customNewGameText[100] = ""; rogueEvent theEvent; enum NGCommands buttonCommands[6] = {NG_NEW_GAME, NG_OPEN_GAME, NG_VIEW_RECORDING, NG_HIGH_SCORES, NG_QUIT}; cellDisplayBuffer shadowBuf[COLS][ROWS]; // Initialize the RNG so the flames aren't always the same. seedRandomGenerator(0); // Empty nextGamePath and nextGameSeed so that the buttons don't try to load an old game path or seed. rogue.nextGamePath[0] = '\0'; rogue.nextGameSeed = 0; // Initialize the title menu buttons. encodeMessageColor(whiteColorEscape, 0, &white); encodeMessageColor(goldColorEscape, 0, KEYBOARD_LABELS ? &itemMessageColor : &white); sprintf(newGameText, " %sN%sew Game ", goldColorEscape, whiteColorEscape); sprintf(customNewGameText, " %sN%sew Game (custom) ", goldColorEscape, whiteColorEscape); b = 0; button = -1; initializeButton(&(buttons[b])); strcpy(buttons[b].text, newGameText); buttons[b].hotkey[0] = 'n'; buttons[b].hotkey[1] = 'N'; b++; initializeButton(&(buttons[b])); sprintf(buttons[b].text, " %sO%spen Game ", goldColorEscape, whiteColorEscape); buttons[b].hotkey[0] = 'o'; buttons[b].hotkey[1] = 'O'; b++; initializeButton(&(buttons[b])); sprintf(buttons[b].text, " %sV%siew Recording ", goldColorEscape, whiteColorEscape); buttons[b].hotkey[0] = 'v'; buttons[b].hotkey[1] = 'V'; b++; initializeButton(&(buttons[b])); sprintf(buttons[b].text, " %sH%sigh Scores ", goldColorEscape, whiteColorEscape); buttons[b].hotkey[0] = 'h'; buttons[b].hotkey[1] = 'H'; b++; // Seth: /* initializeButton(&(buttons[b])); sprintf(buttons[b].text, " %sQ%suit ", goldColorEscape, whiteColorEscape); buttons[b].hotkey[0] = 'q'; buttons[b].hotkey[1] = 'Q'; b++;*/ x = COLS - 1 - 20 - 2; y = ROWS - 1; for (i = b-1; i >= 0; i--) { y -= 2; buttons[i].x = x; buttons[i].y = y; buttons[i].buttonColor = titleButtonColor; buttons[i].flags |= B_WIDE_CLICK_AREA; } blackOutScreen(); clearDisplayBuffer(shadowBuf); initializeButtonState(&state, buttons, b, x, y, 20, b*2-1); rectangularShading(x, y, 20, b*2-1, &black, INTERFACE_OPACITY, shadowBuf); drawButtonsInState(&state); initializeMenuFlames(true, colors, colorSources, flames, mask); rogue.creaturesWillFlashThisTurn = false; // total unconscionable hack do { if (!controlKeyWasDown && controlKeyIsDown()) { strcpy(state.buttons[0].text, customNewGameText); drawButtonsInState(&state); buttonCommands[0] = NG_NEW_GAME_WITH_SEED; controlKeyWasDown = true; } else if (controlKeyWasDown && !controlKeyIsDown()) { strcpy(state.buttons[0].text, newGameText); drawButtonsInState(&state); buttonCommands[0] = NG_NEW_GAME; controlKeyWasDown = false; } // Update the display. updateMenuFlames(colors, colorSources, flames); drawMenuFlames(flames, mask); overlayDisplayBuffer(shadowBuf, NULL); overlayDisplayBuffer(state.dbuf, NULL); // Pause briefly. if (pauseBrogue(MENU_FLAME_UPDATE_DELAY)) { // There was input during the pause! Get the input. nextBrogueEvent(&theEvent, true, false, true); // Process the input. button = processButtonInput(&state, NULL, &theEvent); } // Revert the display. overlayDisplayBuffer(state.rbuf, NULL); } while (button == -1 && rogue.nextGame == NG_NOTHING); drawMenuFlames(flames, mask); if (button != -1) { rogue.nextGame = buttonCommands[button]; } }
void titleMenu() { signed short flames[COLS][(ROWS + MENU_FLAME_ROW_PADDING)][3]; // red, green and blue signed short colorSources[MENU_FLAME_COLOR_SOURCE_COUNT][4]; // red, green, blue, and rand, one for each color source (no more than MENU_FLAME_COLOR_SOURCE_COUNT). color *colors[COLS][(ROWS + MENU_FLAME_ROW_PADDING)]; unsigned char mask[COLS][ROWS]; boolean controlKeyWasDown = false; short i, b, x, y, button; buttonState state; brogueButton buttons[6]; char whiteColorEscape[10] = ""; char goldColorEscape[10] = ""; char newGameText[100] = "", customNewGameText[100] = ""; rogueEvent theEvent; enum NGCommands buttonCommands[6] = {NG_NEW_GAME, NG_OPEN_GAME, NG_VIEW_RECORDING, NG_HIGH_SCORES, NG_QUIT}; BROGUE_WINDOW *root, *window, *title_window, *button_window; BROGUE_DRAW_CONTEXT *context, *title_context, *button_context; BROGUE_EFFECT *button_effect; BROGUE_GRAPHIC *title_graphic; // Initialize the RNG so the flames aren't always the same. seedRandomGenerator(0); // Empty nextGamePath and nextGameSeed so that the buttons don't try to load an old game path or seed. rogue.nextGamePath[0] = '\0'; rogue.nextGameSeed = 0; // Initialize the title menu buttons. encodeMessageColor(whiteColorEscape, 0, &white); encodeMessageColor(goldColorEscape, 0, &itemMessageColor); sprintf(newGameText, " %s(N)%s 开始新游戏", goldColorEscape, whiteColorEscape); sprintf(customNewGameText, " %s(N)%s 生成新游戏", goldColorEscape, whiteColorEscape); b = 0; button = -1; initializeButton(&(buttons[b])); strcpy(buttons[b].text, newGameText); buttons[b].hotkey[0] = 'n'; buttons[b].hotkey[1] = 'N'; b++; initializeButton(&(buttons[b])); sprintf(buttons[b].text, " %s(O)%s 读取存档 ", goldColorEscape, whiteColorEscape); buttons[b].hotkey[0] = 'o'; buttons[b].hotkey[1] = 'O'; b++; initializeButton(&(buttons[b])); sprintf(buttons[b].text, " %s(V)%s 观看录像 ", goldColorEscape, whiteColorEscape); buttons[b].hotkey[0] = 'v'; buttons[b].hotkey[1] = 'V'; b++; initializeButton(&(buttons[b])); sprintf(buttons[b].text, " %s(H)%s 最高分 ", goldColorEscape, whiteColorEscape); buttons[b].hotkey[0] = 'h'; buttons[b].hotkey[1] = 'H'; b++; initializeButton(&(buttons[b])); sprintf(buttons[b].text, " %s(Q)%s 退出游戏 ", goldColorEscape, whiteColorEscape); buttons[b].hotkey[0] = 'q'; buttons[b].hotkey[1] = 'Q'; b++; x = COLS - 1 - 20 - 2; y = ROWS - 3; for (i = b-1; i >= 0; i--) { y -= 2; buttons[i].x = 1; buttons[i].y = 1 + 2 * i; buttons[i].buttonColor = interfaceButtonColor; buttons[i].flags |= B_WIDE_CLICK_AREA; } title_graphic = BrogueGraphic_open("svg/title.svg"); root = ioGetRoot(); window = BrogueWindow_open(root, 0, 0, COLS, ROWS); context = BrogueDrawContext_open(window); title_window = BrogueWindow_open(window, 0, 0, COLS, ROWS); title_context = BrogueDrawContext_open(title_window); if (title_graphic != NULL) { BrogueDrawContext_drawGraphic(title_context, 0, 0, COLS, ROWS, title_graphic); } button_window = BrogueWindow_open(window, x, y, 22, b * 2 + 1); BrogueWindow_setColor(button_window, windowColor); button_context = BrogueDrawContext_open(button_window); button_effect = BrogueEffect_open(button_context, BUTTON_EFFECT_NAME); blackOutScreen(); initializeButtonState(&state, buttons, b, button_context, button_effect, x, y, 20, b*2-1); drawButtonsInState(button_context, button_effect, &state); initializeMenuFlames(true, colors, colorSources, flames, mask); rogue.creaturesWillFlashThisTurn = false; // total unconscionable hack do { if (!controlKeyWasDown && controlKeyIsDown()) { strcpy(state.buttons[0].text, customNewGameText); drawButtonsInState(button_context, button_effect, &state); buttonCommands[0] = NG_NEW_GAME_WITH_SEED; controlKeyWasDown = true; } else if (controlKeyWasDown && !controlKeyIsDown()) { strcpy(state.buttons[0].text, newGameText); drawButtonsInState(button_context, button_effect, &state); buttonCommands[0] = NG_NEW_GAME; controlKeyWasDown = false; } // Update the display. updateMenuFlames(colors, colorSources, flames); drawMenuFlames(context, flames); // Pause briefly. if (pauseBrogue(MENU_FLAME_UPDATE_DELAY)) { // There was input during the pause! Get the input. nextBrogueEvent(&theEvent, true, false, true); // Process the input. button = processButtonInput(button_context, button_effect, &state, NULL, &theEvent); } } while (button == -1 && rogue.nextGame == NG_NOTHING); drawMenuFlames(context, flames); if (button != -1) { rogue.nextGame = buttonCommands[button]; } BrogueWindow_close(window); BrogueGraphic_close(title_graphic); }
// Processes one round of user input, and bakes the necessary graphical changes into state->dbuf. // Does NOT display the buttons or revert the display afterward. // Assumes that the display has already been updated (via overlayDisplayBuffer(state->dbuf, NULL)) // and that input has been solicited (via nextBrogueEvent(event, ___, ___, ___)). // Also relies on the buttonState having been initialized with initializeButtonState() or otherwise. // Returns the index of a button if one is chosen. // Otherwise, returns -1. That can be if the user canceled (in which case *canceled is true), // or, more commonly, if the user's input in this particular split-second round was not decisive. short processButtonInput(buttonState *state, boolean *canceled, rogueEvent *event) { short i, k, x, y; boolean buttonUsed = false; // Mouse event: if (event->eventType == MOUSE_DOWN || event->eventType == MOUSE_UP || event->eventType == MOUSE_ENTERED_CELL) { x = event->param1; y = event->param2; // Revert the button with old focus, if any. if (state->buttonFocused >= 0) { drawButton(&(state->buttons[state->buttonFocused]), BUTTON_NORMAL, state->dbuf); state->buttonFocused = -1; } // Find the button with new focus, if any. for (i=0; i < state->buttonCount; i++) { if ((state->buttons[i].flags & B_DRAW) && (state->buttons[i].flags & B_ENABLED) && (state->buttons[i].y == y || ((state->buttons[i].flags & B_WIDE_CLICK_AREA) && abs(state->buttons[i].y - y) <= 1)) && x >= state->buttons[i].x && x < state->buttons[i].x + strLenWithoutEscapes(state->buttons[i].text)) { state->buttonFocused = i; if (event->eventType == MOUSE_DOWN) { state->buttonDepressed = i; // Keeps track of which button is down at the moment. Cleared on mouseup. } break; } } if (i == state->buttonCount) { // No focus this round. state->buttonFocused = -1; } if (state->buttonDepressed >= 0) { if (state->buttonDepressed == state->buttonFocused) { drawButton(&(state->buttons[state->buttonDepressed]), BUTTON_PRESSED, state->dbuf); } } else if (state->buttonFocused >= 0) { // If no button is depressed, then update the appearance of the button with the new focus, if any. drawButton(&(state->buttons[state->buttonFocused]), BUTTON_HOVER, state->dbuf); } // Mouseup: if (event->eventType == MOUSE_UP) { if (state->buttonDepressed == state->buttonFocused && state->buttonFocused >= 0) { // If a button is depressed, and the mouseup happened on that button, it has been chosen and we're done. buttonUsed = true; } else { // Otherwise, no button is depressed. If one was previously depressed, redraw it. if (state->buttonDepressed >= 0) { drawButton(&(state->buttons[state->buttonDepressed]), BUTTON_NORMAL, state->dbuf); } else if (!(x >= state->winX && x < state->winX + state->winWidth && y >= state->winY && y < state->winY + state->winHeight)) { // Clicking outside of a button means canceling. if (canceled) { *canceled = true; } } if (state->buttonFocused >= 0) { // Buttons don't hover-highlight when one is depressed, so we have to fix that when the mouse is up. drawButton(&(state->buttons[state->buttonFocused]), BUTTON_HOVER, state->dbuf); } state->buttonDepressed = -1; } } } // Keystroke: if (event->eventType == KEYSTROKE) { // Cycle through all of the hotkeys of all of the buttons. for (i=0; i < state->buttonCount; i++) { for (k = 0; k < 10 && state->buttons[i].hotkey[k]; k++) { if (event->param1 == state->buttons[i].hotkey[k]) { // This button was chosen. if (state->buttons[i].flags & B_DRAW) { // Restore the depressed and focused buttons. if (state->buttonDepressed >= 0) { drawButton(&(state->buttons[state->buttonDepressed]), BUTTON_NORMAL, state->dbuf); } if (state->buttonFocused >= 0) { drawButton(&(state->buttons[state->buttonFocused]), BUTTON_NORMAL, state->dbuf); } // If the button likes to flash when keypressed: if (state->buttons[i].flags & B_KEYPRESS_HIGHLIGHT) { // Depress the chosen button. drawButton(&(state->buttons[i]), BUTTON_PRESSED, state->dbuf); // Update the display. overlayDisplayBuffer(state->rbuf, NULL); overlayDisplayBuffer(state->dbuf, NULL); // Wait for a little; then we're done. pauseBrogue(50); } } state->buttonDepressed = i; buttonUsed = true; break; } } } if (!buttonUsed && (event->param1 == ESCAPE_KEY || event->param1 == ACKNOWLEDGE_KEY)) { // If the player pressed escape, we're done. if (canceled) { *canceled = true; } } } if (buttonUsed) { state->buttonChosen = state->buttonDepressed; return state->buttonChosen; } else { return -1; } }