aboutsummaryrefslogblamecommitdiffstats
path: root/game.c
blob: 0cb27f977388c22fc889aef8cd6d9d1fc926fe77 (plain) (tree)








































































































































































































































































































                                                                             
/*  $Id: game.c,v 1.1.1.1 2010/07/17 17:30:32 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 <stdio.h>
#include <string.h>
#include <ctype.h>

#include "oldrunner.h"

#ifdef LEVELS_PATH
#  define  LEVELS  LEVELS_PATH "/original.lvl"
#else
#  define  LEVELS  "./levels/original.lvl"
#endif

#define  POINTS_FOR_MONEY  50
#define  LIVES_AT_START    5

static struct game_info ginfo;

static void
game_lost (void)
{
  struct usr_input input;
  
  gfx_game_over ();
  gfx_get_input (&input);
  game_end ();
}

void
game_won (void)
{
  struct usr_input input;
  
  gfx_game_won ();
  gfx_get_input (&input);
  game_end ();
}

void
game_init (int startlvl)
{
  lvl_init ();
  if (!game_load (LEVELS))
    EXIT ("Could not load game levels. Aborting...");
  ginfo.lives = LIVES_AT_START;
  ginfo.level = startlvl + 1;
  gfx_init ();  
  lvl_load (startlvl);
  hero_init ();
  game_update ();
}

/*
 * The window will be centered on player either if the user requests it or if
 * the level board is too large to fit it the screen.
 */
static void
set_view (void)
{
  struct size lvl;

  lvl.w = lvl_width ();
  lvl.h = lvl_height ();
  
  if (AUTO_CENTER_MODE || lvl.h > VIEWPORT_HEIGHT || lvl.w > VIEWPORT_WIDTH)
    {
      struct coord player_pos;

      hero_get_pos (&player_pos);      
      gfx_center_at (&player_pos);
    }
  else
    {
      struct coord fixed_pos;

      coord_set_yx (&fixed_pos, VIEWPORT_HEIGHT / 2, lvl.w / 2);
      gfx_center_at (&fixed_pos);
    }
}

void
game_update (void)
{
  set_view ();
  lvl_objects_update ();
  hero_draw ();
  if (!(ginfo.state & NO_CHANGE))
    {
      gfx_update_info (&ginfo);
      ginfo.state = NO_CHANGE;
    }
  gfx_update ();
}

void
game_end (void)
{
  gfx_end ();
  exit (0);
}

static unsigned
read_level_row (char *row, unsigned rownum)
{
  char *rowend;
  int len;
  
  if (*row != '[')
    return 0;
  row++;

  if (!(rowend = strchr (row, ']')))
    return 0;
  *rowend = '\0';
  len = rowend - row;
  
  return lvl_set_row (rownum, len, row);
}

static unsigned
store_level_attr (const char *attr, char *val)
{
  if (!strcmp (attr, "level"))
    return lvl_set_name (val);
  else if (!strcmp (attr, "author"))
    return lvl_set_author (val);
  else if (!strcmp (attr, "size"))
    return lvl_set_size (val);
  else
    return 0;
}

/* XXX use strsep instead. */
static unsigned
read_level_attr (char *line)
{
  char *p, *attr, *val;

  attr = p = line;

  while (!isblank ((int)(*p)))
    p++;
  *p++ = '\0';

  while (isblank ((int)(*p)))
    p++;
  val = p;

  return store_level_attr (attr, val);
}

/*
 * XXX improve comment.
 *
 * A game file contains the description of the levels.
 * The following rules apply:
 *   - empty lines are ignored, as well as those beginning with #
 *   - the following keywords are used to describe a level:
 *     -  level: name of the level (default: "")
 *     - author: author of the level (default: "")
 *     -   size: in the form widthxlength (default: 26x16)
 *   - if keywords are present, they must be placed before the level layout
 *   - the reading of a level row stops as soon as the line does
 *     not start with '[', meaning a layout description must not have empty
 *     lines
 */
unsigned
game_load (const char *path)
{
  FILE *f;
  char *buf;
  unsigned rownum, newlevel;
  
  if (!(f = io_fopen (LEVELS)))
    return 0;

  newlevel = 1;
  rownum = 0;
  while ((buf = io_getln (f)))
    {
      char *p;

#define CHK_NEW_LVL  do {                       \
        if (newlevel)                           \
          {                                     \
            lvl_add_new ();                     \
            newlevel = 0;                       \
            rownum = 0;                         \
          }                                     \
    } while (0)
      
      /* Remove trailing spaces. */
      p = buf;
      while (isblank ((int)(*p)))
        p++;
      
      switch (*p)
        {
        case '[':
          CHK_NEW_LVL;
          read_level_row (p, rownum);
          rownum++;
          break;
        case '#':
        case '\0':
          if (rownum)
            newlevel = 1;
          continue;
        default:
          if (rownum)
            newlevel = 1;
          CHK_NEW_LVL;
          read_level_attr (p);
          break;
        }
      
#undef CHK_NEW_LVL      
    }

  io_fclose (f);

  return 1;
}

void
game_score_inc (void)
{
  ginfo.state |= SCORE_CHANGE;
  ginfo.score += POINTS_FOR_MONEY;
}

int
game_level_num (void)
{
  return ginfo.level;
}

void
game_level_inc (void)
{
  ginfo.state |= LEVEL_CHANGE;
  ginfo.level++;
}

void
game_level_dec (void)
{
  ginfo.state |= LEVEL_CHANGE;  
  ginfo.level--;
}

void
game_lives_inc (void)
{
  ginfo.state |= LIVES_CHANGE;  
  ginfo.lives++;
}

void
game_lives_dec (void)
{
  ginfo.state |= LIVES_CHANGE;
  if (ginfo.lives == 0)
    game_lost ();
  ginfo.lives--;
}
Un proyecto texto-plano.xyz