/* $Id: gfx.c,v 1.2 2012/01/31 14:53:07 culot Exp $ */ /* * Copyright (c) 2010 Frederic Culot * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above * copyright notice, this list of conditions and the * following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other * materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "oldrunner.h" #ifdef HAVE_CURSES_H # include #elif defined HAVE_NCURSES_H # include #elif defined HAVE_NCURSES_NCURSES_H # include #elif defined HAVE_NCURSESW_NCURSES_H # include #else # error "Missing curses library header. Aborting..." #endif #define INFOBAR_HEIGHT 2 struct window { WINDOW *p; /* pointer to window */ struct size siz; struct coord pos; }; struct scrollwin { struct window pad; struct window view; }; static struct scrollwin scr; static struct size term; static chtype sprite[SPRITES]; static void sprites_init (void) { sprite[SP_NONE] = ' '; sprite[SP_BRICK] = ACS_CKBOARD; sprite[SP_BRICK_SCRACK] = '~'; sprite[SP_BRICK_LCRACK] = 'U'; sprite[SP_BRICK_BROKEN] = sprite[SP_NONE]; sprite[SP_CIMENT] = ' ' | A_REVERSE; sprite[SP_FAKE_BRICK] = sprite[SP_BRICK]; sprite[SP_LADDER] = 'H'; sprite[SP_ROPE] = ACS_HLINE; sprite[SP_ESCAPE_LADDER] = ACS_VLINE; sprite[SP_MONEY] = ACS_DIAMOND; sprite[SP_HERO] = '@'; sprite[SP_FOE] = '@' | A_REVERSE | A_BLINK; sprite[SP_INVALID] = '?'; } static void screen_init_size (void) { scr.view.siz.w = VIEWPORT_WIDTH; scr.view.siz.h = VIEWPORT_HEIGHT; getmaxyx (stdscr, term.h, term.w); /* Size of the terminal. */ coord_set_yx (&scr.view.pos, term.h > scr.view.siz.h ? (term.h - scr.view.siz.h) / 2 : 0, term.w > scr.view.siz.w ? (term.w - scr.view.siz.w) / 2 : 0); scr.pad.siz.w = LEVEL_MAX_WIDTH; scr.pad.siz.h = LEVEL_MAX_HEIGHT; coord_copy (&scr.view.pos, &scr.pad.pos); } static void screen_init (void) { screen_init_size (); scr.pad.p = newpad (scr.pad.siz.h, scr.pad.siz.w); scr.view.p = newwin (scr.view.siz.h, scr.view.siz.w, scr.view.pos.y, scr.view.pos.x); keypad (scr.view.p, TRUE); /* Enable function and arrow keys. */ nodelay (scr.view.p, TRUE); box (scr.view.p, 0, 0); wnoutrefresh (scr.view.p); } static void screen_update (void) { pnoutrefresh (scr.pad.p, scr.pad.pos.y, scr.pad.pos.x, scr.view.pos.y + (scr.view.siz.h - lvl_height()) / 2, scr.view.pos.x + (scr.view.siz.w - lvl_width()) / 2, scr.view.pos.y + scr.view.siz.h - INFOBAR_HEIGHT, scr.view.pos.x + scr.view.siz.w - 2); } static void newpopup (struct window *pop) { const int BORDERWIDTH = 2; pop->siz.w = scr.view.siz.w - 2 * BORDERWIDTH; pop->siz.h = scr.view.siz.h - 2 * BORDERWIDTH; pop->pos.y = scr.view.pos.y + BORDERWIDTH; pop->pos.x = scr.view.pos.x + BORDERWIDTH; pop->p = newwin (pop->siz.h, pop->siz.w, pop->pos.y, pop->pos.x); keypad (pop->p, TRUE); } static void delpopup (struct window *pop) { wclear (pop->p); wrefresh (pop->p); delwin (pop->p); } static void showpopup (struct window *pop) { box (pop->p, 0, 0); wrefresh (pop->p); } void gfx_init (void) { /* Curses initialization. */ initscr (); /* start the curses mode */ cbreak (); /* control chars generate a signal */ noecho (); /* controls echoing of typed chars */ curs_set (0); /* make cursor invisible */ sprites_init (); /* Game window initialization. */ screen_init (); } void gfx_end (void) { wclear (scr.view.p); wrefresh (scr.view.p); delwin (scr.pad.p); delwin (scr.view.p); endwin (); } void gfx_alert (void) { flash (); napms (200); flash (); } void gfx_center_at (struct coord *pos) { coord_set_yx (&scr.pad.pos, pos->y - VIEWPORT_HEIGHT / 2, pos->x - VIEWPORT_WIDTH / 2); } void gfx_update (void) { screen_update (); doupdate (); } void gfx_get_input (struct usr_input *input) { int key; key = wgetch (scr.view.p); input->key = key == ERR ? -1 : key; } void gfx_show_sprite (enum sprite sp, const struct coord *pos) { gfx_move_sprite (sp, 0, pos); } /* * Show the given character at the current position. * The optional previous position is also given so that graphics routines can * properly clean it up if necessary. * * note: * If the viewport is larger than the level size, a shift must be applied in * order to center the level on screen. */ void gfx_move_sprite (enum sprite sp, const struct coord *prev, const struct coord *current) { mvwaddch (scr.pad.p, current->y, current->x, sprite[sp]); if (prev) { sp = lvl_decor_at_pos (prev); mvwaddch (scr.pad.p, prev->y, prev->x, sprite[sp]); } screen_update (); } /* * Display information related to current game (score, number of lives and * current level). */ void gfx_update_info (const struct game_info *info) { const int HIGHLIGHT = WA_REVERSE | WA_BOLD; char score[BUFSIZ], lives[BUFSIZ], level[BUFSIZ]; int score_len, lives_len, level_len, yoff, xoff; score_len = snprintf (score, sizeof score, "[SCORE: %010d]", info->score); lives_len = snprintf (lives, sizeof lives, "[LIVES: %03d]", info->lives); level_len = snprintf (level, sizeof level, "[LEVEL: %03d]", info->level); yoff = scr.view.siz.h - INFOBAR_HEIGHT + 1; xoff = scr.view.siz.w - (score_len + lives_len + level_len); xoff >>= 2; if (info->state & SCORE_CHANGE) wattron (scr.view.p, HIGHLIGHT); mvwprintw (scr.view.p, yoff, xoff, score); if (info->state & SCORE_CHANGE) wattroff (scr.view.p, HIGHLIGHT); if (info->state & LIVES_CHANGE) wattron (scr.view.p, HIGHLIGHT); mvwprintw (scr.view.p, yoff, score_len + 2 * xoff, lives); if (info->state & LIVES_CHANGE) wattroff (scr.view.p, HIGHLIGHT); if (info->state & LEVEL_CHANGE) wattron (scr.view.p, HIGHLIGHT); mvwprintw (scr.view.p, yoff, score_len + lives_len + 3 * xoff, level); if (info->state & LEVEL_CHANGE) wattroff (scr.view.p, HIGHLIGHT); wnoutrefresh (scr.view.p); } void gfx_popup (const char *title, const char *msg) { struct window pop; char *any_key = "Press any key..."; newpopup (&pop); mvwhline (pop.p, 2, 1, ACS_HLINE, pop.siz.w - 2); mvwprintw (pop.p, 1, (pop.siz.w - strlen (title)) / 2, "%s", title); mvwprintw (pop.p, 5, 1, "%s", msg); mvwprintw (pop.p, pop.siz.h - 2, pop.siz.w - (strlen (any_key) + 1), "%s", any_key); showpopup (&pop); (void)wgetch (pop.p); delpopup (&pop); } void gfx_game_over (void) { const char *rip = " +-+ \n" " +-+-+-+ \n" " +-+-+-+ \n" " | | \n" " +------+-+------+ \n" " | | \n" " | R I P | \n" " ~~~~~~~~~~~| |~~~~~~~~~~ \n" " +---------------+ \n"; gfx_popup ("G A M E O V E R", rip); } /* * The ending screen was taken from the ncurses original sources * (firework.c file). * The original copyright is reproduced below. */ /**************************************************************************** * Copyright (c) 1998-2005,2006 Free Software Foundation, Inc. * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the * * "Software"), to deal in the Software without restriction, including * * without limitation the rights to use, copy, modify, merge, publish, * * distribute, distribute with modifications, sublicense, and/or sell * * copies of the Software, and to permit persons to whom the Software is * * furnished to do so, subject to the following conditions: * * * * The above copyright notice and this permission notice shall be included * * in all copies or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * * * Except as contained in this notice, the name(s) of the above copyright * * holders shall not be used in advertising or otherwise to promote the * * sale, use or other dealings in this Software without prior written * * authorization. * ****************************************************************************/ static void fw_show (struct window *win) { const char *title = "C O N G R A T U L A T I O N S"; const int titlelen = 29; mvwhline (win->p, 2, 1, ACS_HLINE, win->siz.w - 2); mvwprintw (win->p, 1, (win->siz.w - titlelen) / 2, "%s", title); showpopup (win); napms (120); } static void fw_explode (struct window *win, int row, int col) { werase (win->p); mvwprintw (win->p, row, col, "-"); fw_show (win); mvwprintw(win->p, row - 1, col - 1, " - "); mvwprintw(win->p, row + 0, col - 1, "-+-"); mvwprintw(win->p, row + 1, col - 1, " - "); fw_show (win); mvwprintw(win->p, row - 2, col - 2, " --- "); mvwprintw(win->p, row - 1, col - 2, "-+++-"); mvwprintw(win->p, row + 0, col - 2, "-+#+-"); mvwprintw(win->p, row + 1, col - 2, "-+++-"); mvwprintw(win->p, row + 2, col - 2, " --- "); fw_show (win); mvwprintw(win->p, row - 2, col - 2, " +++ "); mvwprintw(win->p, row - 1, col - 2, "++#++"); mvwprintw(win->p, row + 0, col - 2, "+# #+"); mvwprintw(win->p, row + 1, col - 2, "++#++"); mvwprintw(win->p, row + 2, col - 2, " +++ "); fw_show (win); mvwprintw(win->p, row - 2, col - 2, " # "); mvwprintw(win->p, row - 1, col - 2, "## ##"); mvwprintw(win->p, row + 0, col - 2, "# #"); mvwprintw(win->p, row + 1, col - 2, "## ##"); mvwprintw(win->p, row + 2, col - 2, " # "); fw_show (win); mvwprintw(win->p, row - 2, col - 2, " # # "); mvwprintw(win->p, row - 1, col - 2, "# #"); mvwprintw(win->p, row + 0, col - 2, " "); mvwprintw(win->p, row + 1, col - 2, "# #"); mvwprintw(win->p, row + 2, col - 2, " # # "); fw_show (win); } /* XXX quit end screen properly (free popup window) */ static void fireworks (void) { struct window pop; int start, end, row, diff, flag, direction; newpopup (&pop); showpopup (&pop); flag = 0; for (;;) { do { start = rand() % (pop.siz.w - 3); end = rand() % (pop.siz.w - 3); start = (start < 2) ? 2 : start; end = (end < 2) ? 2 : end; direction = (start > end) ? -1 : 1; diff = abs (start - end); } while (diff < 2 || diff >= pop.siz.h - 2); for (row = 0; row < diff; row++) { mvwprintw (pop.p, pop.siz.h - row, start + (row * direction), (direction < 0) ? "\\" : "/"); if (flag++) { fw_show (&pop); werase (pop.p); flag = 0; } } if (flag++) { fw_show (&pop); flag = 0; } fw_explode (&pop, pop.siz.h - row, start + (diff * direction)); werase (pop.p); fw_show (&pop); } } void gfx_game_won (void) { fireworks (); }