diff options
author | culot <culot@FreeBSD.org> | 2018-07-27 11:22:11 +0200 |
---|---|---|
committer | culot <culot@FreeBSD.org> | 2018-07-27 11:22:11 +0200 |
commit | 2b3b9dc4649727851004b8223b6af38b57c0c790 (patch) | |
tree | 418867a8ac458e7b0a7fcaca90b551628a8e6810 /gfx.c | |
download | oldrunner-2b3b9dc4649727851004b8223b6af38b57c0c790.tar.gz |
oldrunner initial import
Diffstat (limited to 'gfx.c')
-rw-r--r-- | gfx.c | 448 |
1 files changed, 448 insertions, 0 deletions
@@ -0,0 +1,448 @@ +/* $Id: gfx.c,v 1.2 2012/01/31 14:53:07 culot Exp $ */ + +/* + * Copyright (c) 2010 Frederic Culot <frederic@culot.org> + * 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 <string.h> + +#include "oldrunner.h" + +#ifdef HAVE_CURSES_H +# include <curses.h> +#elif defined HAVE_NCURSES_H +# include <ncurses.h> +#elif defined HAVE_NCURSES_NCURSES_H +# include <ncurses/ncurses.h> +#elif defined HAVE_NCURSESW_NCURSES_H +# include <ncursesw/ncurses.h> +#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 (); +} |