/* $Id: game.c,v 1.1.1.1 2010/07/17 17:30:32 culot Exp $ */ /* vim: et ai sts=2 ts=2 sw=2: * */ /* * 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 #include #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--; }