/** * \brief Draws text in a color specified by hue and value and with a * surrounding shadow. * * A '~' in the text is not drawn but instead toggles highlighting which * increases \c value by 4. * * \li like JE_textShade() with FULL_SHADE if (black == true && shadow_dist == 1) * * @param surface destination surface * @param x initial x-position in pixels; which direction(s) the text is drawn * from this position depends on the alignment * @param y initial upper y-position in pixels * @param text text to be drawn * @param font style/size of text * @param alignment left_aligned, centered, or right_aligned * @param hue hue component of text color * @param value value component of text color * @param black if true the shadow is drawn as solid black, if false the shadow * is drawn by darkening the pixels of the destination surface * @param shadow_dist distance in pixels that the shadows will be drawn away * from the text. (This distance is separately added to and subtracted * from the x position and y position, resulting in four shadows -- one * in each cardinal direction. If this shadow distance is small enough, * this produces a shadow that outlines the text.) */ void draw_font_hv_full_shadow( SDL_Surface *surface, int x, int y, const char *text, Font font, FontAlignment alignment, Uint8 hue, Sint8 value, bool black, int shadow_dist ) { draw_font_dark(surface, x, y - shadow_dist, text, font, alignment, black); draw_font_dark(surface, x + shadow_dist, y, text, font, alignment, black); draw_font_dark(surface, x, y + shadow_dist, text, font, alignment, black); draw_font_dark(surface, x - shadow_dist, y, text, font, alignment, black); draw_font_hv(surface, x, y, text, font, alignment, hue, value); }
/* Text is an array of strings terminated by a NULL */ void scroller_sine( const struct about_text_type text[] ) { bool ale = mt_rand() % 2; int visible_lines = vga_height / LINE_HEIGHT + 1; int current_line = -visible_lines; int y = 0; bool fade_in = true; struct coin_type { int x, y, vel, type, cur_frame; bool backwards; } coins[MAX_COINS]; struct { int x, y, ay, vx, vy; } beer[MAX_BEER]; if (ale) { memset(beer, 0, sizeof(beer)); } else { for (int i = 0; i < MAX_COINS; i++) { coins[i].x = mt_rand() % (vga_width - 12); coins[i].y = mt_rand() % (vga_height - 20 - 14); coins[i].vel = (mt_rand() % 4) + 1; coins[i].type = mt_rand() % COUNTOF(coin_defs); coins[i].cur_frame = mt_rand() % coin_defs[coins[i].type].frame_count; coins[i].backwards = false; } } fade_black(10); wait_noinput(true, true, true); play_song(40); // BEER while (!JE_anyButton()) { setdelay(3); JE_clr256(VGAScreen); if (!ale) { for (int i = 0; i < MAX_COINS/2; i++) { struct coin_type *coin = &coins[i]; blit_sprite2(VGAScreen, coin->x, coin->y, eShapes5, coin_defs[coin->type].shape_num + coin->cur_frame); } } for (int i = 0; i < visible_lines; i++) { if (current_line + i >= 0) { if (text[current_line + i].text == NULL) { break; } int line_x = VGAScreen->w / 2; int line_y = i * LINE_HEIGHT - y; // smooths edges on sine-wave text if (text[i + current_line].effect & 0x20) { draw_font_hv(VGAScreen, line_x + 1, line_y, text[i + current_line].text, normal_font, centered, text[i + current_line].effect & 0x0f, -10); draw_font_hv(VGAScreen, line_x - 1, line_y, text[i + current_line].text, normal_font, centered, text[i + current_line].effect & 0x0f, -10); } draw_font_hv(VGAScreen, line_x, line_y, text[i + current_line].text, normal_font, centered, text[i + current_line].effect & 0x0f, -4); if (text[i + current_line].effect & 0x10) { for (int j = 0; j < LINE_HEIGHT; j++) { if (line_y + j >= 10 && line_y + j <= vga_height - 10) { int waver = sinf((((line_y + j) / 2) % 10) / 5.0f * M_PI) * 3; memmove(&((Uint8 *)VGAScreen->pixels)[VGAScreen->pitch * (line_y + j) + waver], &((Uint8 *)VGAScreen->pixels)[VGAScreen->pitch * (line_y + j)], VGAScreen->pitch); } } } } } if (++y == LINE_HEIGHT) { y = 0; if (current_line < 0 || text[current_line].text != NULL) ++current_line; else current_line = -visible_lines; } if (!ale) { for (int i = MAX_COINS/2; i < MAX_COINS; i++) { struct coin_type *coin = &coins[i]; blit_sprite2(VGAScreen, coin->x, coin->y, eShapes5, coin_defs[coin->type].shape_num + coin->cur_frame); } } fill_rectangle_xy(VGAScreen, 0, 0, vga_width - 1, 14, 0); fill_rectangle_xy(VGAScreen, 0, vga_height - 14, vga_width - 1, vga_height - 1, 0); if (!ale) { for (int i = 0; i < MAX_COINS; i++) { struct coin_type *coin = &coins[i]; if (coin->backwards) { coin->cur_frame--; } else { coin->cur_frame++; } if (coin->cur_frame == coin_defs[coin->type].frame_count) { if (coin_defs[coin->type].reverse_anim) { coin->backwards = true; coin->cur_frame -= 2; } else { coin->cur_frame = 0; } } if (coin->cur_frame == -1) { coin->cur_frame = 1; coin->backwards = false; } coin->y += coin->vel; if (coin->y > vga_height - 14) { coin->x = mt_rand() % (vga_width - 12); coin->y = 0; coin->vel = (mt_rand() % 4) + 1; coin->type = mt_rand() % COUNTOF(coin_defs); coin->cur_frame = mt_rand() % coin_defs[coin->type].frame_count; } } } else { for (uint i = 0; i < COUNTOF(beer); i++) { while (beer[i].vx == 0) { beer[i].x = mt_rand() % (vga_width - 24); beer[i].y = mt_rand() % (vga_height - 28 - 50); beer[i].vx = (mt_rand() % 5) - 2; } beer[i].vy++; if (beer[i].x + beer[i].vx > vga_width - 24 || beer[i].x + beer[i].vx < 0) // check if the beer hit the sides { beer[i].vx = -beer[i].vx; } beer[i].x += beer[i].vx; if (beer[i].y + beer[i].vy > vga_height - 28) // check if the beer hit the bottom { if ((beer[i].vy) < 8) // make sure the beer bounces! { beer[i].vy += mt_rand() % 2; } else if (beer[i].vy > 16) { // make sure the beer doesn't bounce too high beer[i].vy = 16; } beer[i].vy = -beer[i].vy + (mt_rand() % 3 - 1); beer[i].x += (beer[i].vx > 0 ? 1 : -1) * (i % 2 ? 1 : -1); } beer[i].y += beer[i].vy; blit_sprite2x2(VGAScreen, beer[i].x, beer[i].y, eShapes5, BEER_SHAPE); } } JE_showVGA(); if (fade_in) { fade_in = false; fade_palette(colors, 10, 0, 255); SDL_Color white = { 255, 255, 255 }; set_colors(white, 254, 254); } wait_delay(); } fade_black(10); }
void opentyrian_menu( void ) { static const char *menu_items[] = { "About OpenTyrian", "Toggle Fullscreen", "Scaler: None", // "Play Destruct", "Jukebox", "Return to Main Menu", }; bool menu_items_disabled[] = { false, !can_init_any_scaler(false) || !can_init_any_scaler(true), false, // false, false, false, }; fade_black(10); JE_loadPic(VGAScreen, 13, false); draw_font_hv(VGAScreen, VGAScreen->w / 2, 5, opentyrian_str, large_font, centered, 15, -3); memcpy(VGAScreen2->pixels, VGAScreen->pixels, VGAScreen2->pitch * VGAScreen2->h); JE_showVGA(); play_song(36); // A Field for Mag int sel = 0; const int maxSel = COUNTOF(menu_items) - 1; uint32_t temp_scaler = scaler; bool fade_in = true, quit = false; do { memcpy(VGAScreen->pixels, VGAScreen2->pixels, VGAScreen->pitch * VGAScreen->h); for (int i = 0; i <= maxSel; i++) { const char *text = menu_items[i]; char buffer[100]; if (i == 2) /* Scaler */ { snprintf(buffer, sizeof(buffer), "Scaler: %s", scalers[temp_scaler].name); text = buffer; } int y = i != maxSel ? i * 16 + 32 : 118; draw_font_hv(VGAScreen, VGAScreen->w / 2, y, text, normal_font, centered, 15, menu_items_disabled[i] ? -8 : i != sel ? -4 : -2); } JE_showVGA(); if (fade_in) { fade_in = false; fade_palette(colors, 20, 0, 255); wait_noinput(true, false, false); } tempW = 0; JE_textMenuWait(&tempW, false); if (newkey) { switch (lastkey_sym) { case SDLK_UP: do { if (--sel < 0) sel = maxSel; } while (menu_items_disabled[sel]); JE_playSampleNum(S_CURSOR); break; case SDLK_DOWN: do { if (++sel > maxSel) sel = 0; } while (menu_items_disabled[sel]); JE_playSampleNum(S_CURSOR); break; case SDLK_LEFT: if (sel == 2) { do { if (temp_scaler == 0) temp_scaler = scalers_count; temp_scaler--; } while (!can_init_scaler(temp_scaler, fullscreen_enabled)); JE_playSampleNum(S_CURSOR); } break; case SDLK_RIGHT: if (sel == 2) { do { temp_scaler++; if (temp_scaler == scalers_count) temp_scaler = 0; } while (!can_init_scaler(temp_scaler, fullscreen_enabled)); JE_playSampleNum(S_CURSOR); } break; case SDLK_RETURN: switch (sel) { case 0: /* About */ JE_playSampleNum(S_SELECT); scroller_sine(about_text); memcpy(VGAScreen->pixels, VGAScreen2->pixels, VGAScreen->pitch * VGAScreen->h); JE_showVGA(); fade_in = true; break; case 1: /* Fullscreen */ JE_playSampleNum(S_SELECT); if (!init_scaler(scaler, !fullscreen_enabled) && // try new fullscreen state !init_any_scaler(!fullscreen_enabled) && // try any scaler in new fullscreen state !init_scaler(scaler, fullscreen_enabled)) // revert on fail { exit(EXIT_FAILURE); } set_palette(colors, 0, 255); // for switching between 8 bpp scalers break; case 2: /* Scaler */ JE_playSampleNum(S_SELECT); if (scaler != temp_scaler) { if (!init_scaler(temp_scaler, fullscreen_enabled) && // try new scaler !init_scaler(temp_scaler, !fullscreen_enabled) && // try other fullscreen state !init_scaler(scaler, fullscreen_enabled)) // revert on fail { exit(EXIT_FAILURE); } set_palette(colors, 0, 255); // for switching between 8 bpp scalers } break; case 3: /* Jukebox */ JE_playSampleNum(S_SELECT); fade_black(10); jukebox(); memcpy(VGAScreen->pixels, VGAScreen2->pixels, VGAScreen->pitch * VGAScreen->h); JE_showVGA(); fade_in = true; break; case 4: /* Return to main menu */ quit = true; JE_playSampleNum(S_SPRING); break; } break; case SDLK_ESCAPE: quit = true; JE_playSampleNum(S_SPRING); break; default: break; } } } while (!quit); }
void opentyrian_menu( void ) { typedef enum { MENU_ABOUT = 0, MENU_FULLSCREEN, MENU_SCALER, // MENU_DESTRUCT, MENU_JUKEBOX, MENU_RETURN, MenuOptions_MAX } MenuOptions; static const char *menu_items[] = { "About OpenTyrian", "Toggle Fullscreen", "Scaler: None", // "Play Destruct", "Jukebox", "Return to Main Menu", }; bool menu_items_disabled[] = { false, !can_init_any_scaler(false) || !can_init_any_scaler(true), false, // false, false, false, }; assert(COUNTOF(menu_items) == MenuOptions_MAX); assert(COUNTOF(menu_items_disabled) == MenuOptions_MAX); fade_black(10); JE_loadPic(VGAScreen, 13, false); draw_font_hv(VGAScreen, VGAScreen->surf->w / 2, 5, opentyrian_str, large_font, centered, 15, -3); memcpy(VGAScreen2->surf->pixels, VGAScreen->surf->pixels, VGAScreen2->surf->pitch * VGAScreen2->surf->h); JE_showVGA(); play_song(36); // A Field for Mag MenuOptions sel = 0; uint temp_scaler = scaler; bool fade_in = true, quit = false; do { memcpy(VGAScreen->surf->pixels, VGAScreen2->surf->pixels, VGAScreen->surf->pitch * VGAScreen->surf->h); for (MenuOptions i = 0; i < MenuOptions_MAX; i++) { const char *text = menu_items[i]; char buffer[100]; if (i == MENU_SCALER) { snprintf(buffer, sizeof(buffer), "Scaler: %s", scalers[temp_scaler].name); text = buffer; } int y = i != MENU_RETURN ? i * 16 + 32 : 118; draw_font_hv(VGAScreen, VGAScreen->surf->w / 2, y, text, normal_font, centered, 15, menu_items_disabled[i] ? -8 : i != sel ? -4 : -2); } JE_showVGA(); if (fade_in) { fade_in = false; fade_palette(colors, 20, 0, 255); wait_noinput(true, false, false); } tempW = 0; JE_textMenuWait(&tempW, false); if (newkey) { switch (lastkey_sym) { case SDLK_UP: do { if (sel-- == 0) sel = MenuOptions_MAX - 1; } while (menu_items_disabled[sel]); JE_playSampleNum(S_CURSOR); break; case SDLK_DOWN: do { if (++sel >= MenuOptions_MAX) sel = 0; } while (menu_items_disabled[sel]); JE_playSampleNum(S_CURSOR); break; case SDLK_LEFT: if (sel == MENU_SCALER) { do { if (temp_scaler == 0) temp_scaler = scalers_count; temp_scaler--; } while (!can_init_scaler(temp_scaler, fullscreen_enabled)); JE_playSampleNum(S_CURSOR); } break; case SDLK_RIGHT: if (sel == MENU_SCALER) { do { temp_scaler++; if (temp_scaler == scalers_count) temp_scaler = 0; } while (!can_init_scaler(temp_scaler, fullscreen_enabled)); JE_playSampleNum(S_CURSOR); } break; case SDLK_RETURN: switch (sel) { case MENU_ABOUT: JE_playSampleNum(S_SELECT); scroller_sine(about_text); memcpy(VGAScreen->surf->pixels, VGAScreen2->surf->pixels, VGAScreen->surf->pitch * VGAScreen->surf->h); JE_showVGA(); fade_in = true; break; case MENU_FULLSCREEN: JE_playSampleNum(S_SELECT); if (!init_scaler(scaler, !fullscreen_enabled) && // try new fullscreen state !init_any_scaler(!fullscreen_enabled) && // try any scaler in new fullscreen state !init_scaler(scaler, fullscreen_enabled)) // revert on fail { exit(EXIT_FAILURE); } break; case MENU_SCALER: JE_playSampleNum(S_SELECT); if (scaler != temp_scaler) { if (!init_scaler(temp_scaler, fullscreen_enabled) && // try new scaler !init_scaler(temp_scaler, !fullscreen_enabled) && // try other fullscreen state !init_scaler(scaler, fullscreen_enabled)) // revert on fail { exit(EXIT_FAILURE); } } break; case MENU_JUKEBOX: JE_playSampleNum(S_SELECT); fade_black(10); jukebox(); memcpy(VGAScreen->surf->pixels, VGAScreen2->surf->pixels, VGAScreen->surf->pitch * VGAScreen->surf->h); JE_showVGA(); fade_in = true; break; case MENU_RETURN: quit = true; JE_playSampleNum(S_SPRING); break; case MenuOptions_MAX: assert(false); break; } break; case SDLK_ESCAPE: quit = true; JE_playSampleNum(S_SPRING); break; default: break; } } } while (!quit); }
bool xmas_prompt( void ) { const char *prompt[] = { "Christmas has been detected.", "Activate Christmas?", }; const char *choice[] = { "Yes", "No", }; set_palette(palettes[0], 0, 255); for (uint32_t i = 0; i < COUNTOF(prompt); ++i) draw_font_hv(VGAScreen, 320 / 2, 85 + 15 * i, prompt[i], normal_font, centered, (i % 2) ? 2 : 4, -2); uint32_t selection = 0; bool decided = false, quit = false; while (!decided) { for (uint32_t i = 0; i < COUNTOF(choice); ++i) draw_font_hv(VGAScreen, 320 / 2 - 20 + 40 * i, 120, choice[i], normal_font, centered, 15, (selection == i) ? -2 : -4); JE_showVGA(); uint16_t temp = 0; JE_textMenuWait(&temp, false); if (newkey) { switch (lastkey_sym) { case SDLK_LEFT: if (selection == 0) selection = 2; selection--; break; case SDLK_RIGHT: selection++; selection %= 2; break; case SDLK_RETURN: decided = true; break; case SDLK_ESCAPE: decided = true; quit = true; break; default: break; } } } fade_black(10); return (selection == 0 && quit == false); }
void jukebox( void ) { bool trigger_quit = false, // true when user wants to quit quitting = false; bool hide_text = false; bool fade_looped_songs = true, fading_song = false; bool stopped = false; bool fx = false; int fx_num = 0; int palette_fade_steps = 15; int diff[256][3]; init_step_fade_palette(diff, vga_palette, 0, 255); JE_starlib_init(); int fade_volume = tyrMusicVolume; for (; ; ) { if (!stopped && !audio_disabled) { if (songlooped && fade_looped_songs) fading_song = true; if (fading_song) { if (fade_volume > 5) { fade_volume -= 2; } else { fade_volume = tyrMusicVolume; fading_song = false; } set_volume(fade_volume, fxVolume); } if (!playing || (songlooped && fade_looped_songs && !fading_song)) play_song(mt_rand() % MUSIC_NUM); } setdelay(1); SDL_FillRect(VGAScreenSeg, NULL, 0); // starlib input needs to be rewritten JE_starlib_main(); push_joysticks_as_keyboard(); service_SDL_events(true); if (!hide_text) { char buffer[60]; if (fx) snprintf(buffer, sizeof(buffer), "%d %s", fx_num + 1, soundTitle[fx_num]); else snprintf(buffer, sizeof(buffer), "%d %s", song_playing + 1, musicTitle[song_playing]); const int x = VGAScreen->w / 2; #ifdef ANDROID draw_font_hv(VGAScreen, x, 170, "Press the Back button to quit the jukebox.", small_font, centered, 1, 0); draw_font_hv(VGAScreen, x, 180, "Touch to change the song being played.", small_font, centered, 1, 0); #else draw_font_hv(VGAScreen, x, 170, "Press ESC to quit the jukebox.", small_font, centered, 1, 0); draw_font_hv(VGAScreen, x, 180, "Arrow keys change the song being played.", small_font, centered, 1, 0); #endif draw_font_hv(VGAScreen, x, 190, buffer, small_font, centered, 1, 4); } if (palette_fade_steps > 0) step_fade_palette(diff, palette_fade_steps--, 0, 255); JE_showVGA(); wait_delay(); #ifdef ANDROID if (mousedown) { wait_noinput(true, true, true); newkey = true; if (mouse_x < 160) lastkey_sym = SDLK_LEFT; else lastkey_sym = SDLK_RIGHT; } #else // quit on mouse click Uint16 x, y; if (JE_mousePosition(&x, &y) > 0) trigger_quit = true; #endif if (newkey) { switch (lastkey_sym) { case SDLK_ESCAPE: // quit jukebox case SDLK_q: trigger_quit = true; break; case SDLK_SPACE: hide_text = !hide_text; break; case SDLK_f: fading_song = !fading_song; break; case SDLK_n: fade_looped_songs = !fade_looped_songs; break; case SDLK_SLASH: // switch to sfx mode fx = !fx; break; case SDLK_COMMA: if (fx && --fx_num < 0) fx_num = SAMPLE_COUNT - 1; break; case SDLK_PERIOD: if (fx && ++fx_num >= SAMPLE_COUNT) fx_num = 0; break; case SDLK_SEMICOLON: if (fx) JE_playSampleNum(fx_num + 1); break; case SDLK_LEFT: case SDLK_UP: case SDLK_LCTRL: play_song((song_playing > 0 ? song_playing : MUSIC_NUM) - 1); stopped = false; break; case SDLK_RETURN: case SDLK_RIGHT: case SDLK_DOWN: case SDLK_LALT: play_song((song_playing + 1) % MUSIC_NUM); stopped = false; break; case SDLK_s: // stop song stop_song(); stopped = true; break; case SDLK_r: // restart song restart_song(); stopped = false; break; default: break; } } // user wants to quit, start fade-out if (trigger_quit && !quitting) { palette_fade_steps = 15; SDL_Color black = { 0, 0, 0 }; init_step_fade_solid(diff, black, 0, 255); quitting = true; } // if fade-out finished, we can finally quit if (quitting && palette_fade_steps == 0) break; } set_volume(tyrMusicVolume, fxVolume); }