aboutsummaryrefslogblamecommitdiffstats
path: root/gfx.c
blob: e1da220dfd57921a208412d0bb60e1bae56b99c7 (plain) (tree)
1
2
3
                                                        

                              













































































                                                                        
                                  
                                  
                                                        












































                                                                             
 











































































































































































                                                                             
                                               


















































































































































                                                                              
/*  $Id: gfx.c,v 1.2 2012/01/31 14:53:07 culot Exp $  */
/* vim: et ai sts=2 ts=2 sw=2:
 * */

/*
 * 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]          = '$';
  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 ();
}
Un proyecto texto-plano.xyz