mirror of
https://github.com/gwenhael-le-moine/ngstar.git
synced 2024-12-27 09:58:33 +01:00
408 lines
11 KiB
C++
408 lines
11 KiB
C++
|
/*
|
||
|
* NGStar2.cc
|
||
|
*
|
||
|
* Copyright (C) 2005, 2006 Gwenhael LE MOINE
|
||
|
*
|
||
|
* This file is part of NGStar2
|
||
|
*
|
||
|
* NGStar2 is free software; you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License as published by
|
||
|
* the Free Software Foundation; either version 2 of the License, or
|
||
|
* (at your option) any later version.
|
||
|
*
|
||
|
* NGStar2 is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License
|
||
|
* along with NGStar2; if not, write to the Free Software
|
||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||
|
*/
|
||
|
|
||
|
/* includes */
|
||
|
#include "NGStar2.hh"
|
||
|
#include "tools.hh"
|
||
|
|
||
|
using namespace std;
|
||
|
|
||
|
namespace ngstar2 {
|
||
|
|
||
|
// NGSTAR2 class implementation
|
||
|
// in order of declaration
|
||
|
// private:
|
||
|
|
||
|
//
|
||
|
// Set the cell(x, y) with the given value (if valid)
|
||
|
//
|
||
|
void NGStar2::set_cell( int x, int y , char value )
|
||
|
{
|
||
|
if ( ( x <= NGSTAR_LEVEL_WIDTH ) && ( y <= NGSTAR_LEVEL_HEIGHT ) ) {
|
||
|
switch ( value ) {
|
||
|
case WALL : // char if for ngs levels
|
||
|
case 3 : // int is for gsl levels
|
||
|
this->board[y*NGSTAR_LEVEL_WIDTH+x] = wall;
|
||
|
break;
|
||
|
case EMPTY :
|
||
|
case 2 :
|
||
|
this->board[y*NGSTAR_LEVEL_WIDTH+x] = empty;
|
||
|
break;
|
||
|
case GIFT :
|
||
|
case 4 :
|
||
|
this->board[y*NGSTAR_LEVEL_WIDTH+x] = gift;
|
||
|
this->nb_gifts++;
|
||
|
break;
|
||
|
case BALL :
|
||
|
case 0 :
|
||
|
this->board[y*NGSTAR_LEVEL_WIDTH+x] = ball;
|
||
|
this->ball_X = x;
|
||
|
this->ball_Y = y;
|
||
|
break;
|
||
|
case CUBE :
|
||
|
case 1 :
|
||
|
this->board[y*NGSTAR_LEVEL_WIDTH+x] = cube;
|
||
|
this->cube_X = x;
|
||
|
this->cube_Y = y;
|
||
|
break;
|
||
|
case '\n' :
|
||
|
break;
|
||
|
default :
|
||
|
throw InvalidCellValue( value );
|
||
|
break;
|
||
|
}
|
||
|
} else {
|
||
|
throw InvalidCellCoordinates( x, y );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Load a level from file filename in NGStar format
|
||
|
//
|
||
|
inline void NGStar2::read_ngs_level( const string *filename )
|
||
|
{
|
||
|
int i;
|
||
|
int j;
|
||
|
char current_cell;
|
||
|
bool ball_set=false;
|
||
|
bool cube_set=false;
|
||
|
|
||
|
ifstream file;
|
||
|
|
||
|
file.open( filename->c_str( ), ios::in );
|
||
|
if ( file == NULL ) {
|
||
|
throw InvalidLevelFile( filename );
|
||
|
}
|
||
|
|
||
|
this->level_h = NGSTAR_LEVEL_HEIGHT;
|
||
|
this->level_w = NGSTAR_LEVEL_WIDTH;
|
||
|
this->board = new cell[ this->level_w * this->level_h ];
|
||
|
|
||
|
for ( i=NGSTAR_LEVEL_HEIGHT ; i-- ; ) {
|
||
|
for ( j=NGSTAR_LEVEL_WIDTH ; j-- ; ) {
|
||
|
file.read( ¤t_cell, 1 );
|
||
|
if ( file.eof( ) )
|
||
|
throw InvalidLevelFile( filename );
|
||
|
this->set_cell( j, i, current_cell );
|
||
|
if ( current_cell == BALL )
|
||
|
ball_set = true;
|
||
|
else
|
||
|
if ( current_cell == CUBE )
|
||
|
cube_set = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
file.close( );
|
||
|
|
||
|
if ( ball_set == false || cube_set == false ) {
|
||
|
throw InvalidLevelFile( filename );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Load a level from file filename in G-star format
|
||
|
// (from g-star source, translated into C++ and adapted
|
||
|
// but basically the structure is the same)
|
||
|
//
|
||
|
inline void NGStar2::read_gsl_level( const string *filename )
|
||
|
{
|
||
|
int i;
|
||
|
int j;
|
||
|
char current_cell;
|
||
|
char width;
|
||
|
char height;
|
||
|
bool ball_set=false;
|
||
|
bool cube_set=false;
|
||
|
|
||
|
ifstream file;
|
||
|
|
||
|
file.open( filename->c_str( ), ios::binary );
|
||
|
if ( file == NULL ) {
|
||
|
throw InvalidLevelFile( filename );
|
||
|
}
|
||
|
|
||
|
/* skeeping header "gsl1" */
|
||
|
file.seekg( 4 );
|
||
|
|
||
|
file.read( &width, 1 );
|
||
|
file.read( &height, 1 );
|
||
|
|
||
|
this->level_h = (int)height; //NGSTAR_LEVEL_HEIGHT;
|
||
|
this->level_w = (int)width; //NGSTAR_LEVEL_WIDTH;
|
||
|
this->board = new cell[ this->level_w * this->level_h ];
|
||
|
|
||
|
if (( width == NGSTAR_LEVEL_WIDTH ) && ( height == NGSTAR_LEVEL_HEIGHT )) {
|
||
|
for ( i=NGSTAR_LEVEL_HEIGHT ; i-- ; ) {
|
||
|
for ( j=NGSTAR_LEVEL_WIDTH ; j-- ; ) {
|
||
|
file.read( ¤t_cell, 1 );
|
||
|
if ( file.eof( ) )
|
||
|
throw InvalidLevelFile( filename );
|
||
|
this->set_cell( j, i, current_cell );
|
||
|
if ( current_cell == 0 )
|
||
|
ball_set = true;
|
||
|
else
|
||
|
if ( current_cell == 1 )
|
||
|
cube_set = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
file.close( );
|
||
|
|
||
|
if ( ball_set == false || cube_set == false ) {
|
||
|
throw InvalidLevelFile( filename );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Determine the format of level in filename and call
|
||
|
// the corresponding method
|
||
|
//
|
||
|
void NGStar2::read_level( const string *filename )
|
||
|
{
|
||
|
ifstream file;
|
||
|
char *foo = new char[ 5 ];
|
||
|
|
||
|
this->nb_gifts = 0;
|
||
|
|
||
|
file.open( filename->c_str( ), ios::binary );
|
||
|
if ( file == NULL ) {
|
||
|
throw InvalidLevelFile( filename );
|
||
|
}
|
||
|
|
||
|
/* verifying file type (gsl or ngs) */
|
||
|
file.read( foo, 4 );
|
||
|
foo[4] = '\0';
|
||
|
if ( (new string( foo ))->compare( "gsl1" ) == 0 ) {
|
||
|
file.close( );
|
||
|
read_gsl_level( filename );
|
||
|
}
|
||
|
else {
|
||
|
file.close( );
|
||
|
read_ngs_level( filename );
|
||
|
}
|
||
|
|
||
|
this->nb_moves = 0;
|
||
|
this->moving = ball;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Move the ball in given direction
|
||
|
// stopped by walls and the cube
|
||
|
//
|
||
|
void NGStar2::move_ball( direction direction )
|
||
|
{
|
||
|
int dh=0;
|
||
|
int dv=0;
|
||
|
unsigned int tmp_ball_X = this->ball_X;
|
||
|
unsigned int tmp_ball_Y = this->ball_Y;
|
||
|
|
||
|
/* determining the direction it will go */
|
||
|
switch ( direction ) {
|
||
|
case go_up : dv=1; break;
|
||
|
case go_down : dv=-1; break;
|
||
|
case go_left : dh=1; break;
|
||
|
case go_right : dh=-1; break;
|
||
|
default : break;
|
||
|
}
|
||
|
|
||
|
/* determining the cell it will go */
|
||
|
while (
|
||
|
/* checking board limits */
|
||
|
(( tmp_ball_Y + dv >= 0 ) &&
|
||
|
( tmp_ball_Y + dv < NGSTAR_LEVEL_HEIGHT )) &&
|
||
|
(( tmp_ball_X + dh >= 0 ) &&
|
||
|
( tmp_ball_X + dh < NGSTAR_LEVEL_WIDTH )) &&
|
||
|
/* is next cell a wall ? */
|
||
|
(this->board[(tmp_ball_Y + dv)*NGSTAR_LEVEL_WIDTH+tmp_ball_X + dh] != wall) &&
|
||
|
(this->board[(tmp_ball_Y + dv)*NGSTAR_LEVEL_WIDTH+tmp_ball_X + dh] != cube)
|
||
|
)
|
||
|
{
|
||
|
tmp_ball_Y += dv;
|
||
|
tmp_ball_X += dh;
|
||
|
|
||
|
/* did it collect a gift ? */
|
||
|
if ( this->board[tmp_ball_Y*NGSTAR_LEVEL_WIDTH+tmp_ball_X] == gift )
|
||
|
{
|
||
|
this->board[tmp_ball_Y*NGSTAR_LEVEL_WIDTH+tmp_ball_X] = empty;
|
||
|
this->nb_gifts--;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( ( tmp_ball_X != this->ball_X ) || ( tmp_ball_Y != this->ball_Y ) ) {
|
||
|
// if it's the first move then set t1 as the start of level
|
||
|
if ( this->nb_moves == 0 )
|
||
|
(void) time( &( this->t1 ) );
|
||
|
/* empty previous cell */
|
||
|
this->board[this->ball_Y*NGSTAR_LEVEL_WIDTH+this->ball_X] = empty;
|
||
|
|
||
|
/* changing coordinates */
|
||
|
this->ball_Y = tmp_ball_Y;
|
||
|
this->ball_X = tmp_ball_X;
|
||
|
|
||
|
/* set destination cell */
|
||
|
this->board[tmp_ball_Y*NGSTAR_LEVEL_WIDTH+tmp_ball_X] = ball;
|
||
|
|
||
|
++(this->nb_moves);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Move the cube in given direction
|
||
|
// stopped by walls, gifts and the ball
|
||
|
// slightly different from move_ball
|
||
|
//
|
||
|
void NGStar2::move_cube( direction direction )
|
||
|
{
|
||
|
int dh=0;
|
||
|
int dv=0;
|
||
|
unsigned int tmp_cube_X = this->cube_X;
|
||
|
unsigned int tmp_cube_Y = this->cube_Y;
|
||
|
|
||
|
/* determining the direction it will go */
|
||
|
switch ( direction ) {
|
||
|
case go_up : dv=1; break;
|
||
|
case go_down : dv=-1; break;
|
||
|
case go_left : dh=1; break;
|
||
|
case go_right : dh=-1; break;
|
||
|
default : break;
|
||
|
}
|
||
|
|
||
|
/* determining the cell it will go */
|
||
|
while (
|
||
|
/* checking board limits */
|
||
|
(( tmp_cube_Y + dv >= 0 ) &&
|
||
|
( tmp_cube_Y + dv < NGSTAR_LEVEL_HEIGHT )) &&
|
||
|
(( tmp_cube_X + dh >= 0 ) &&
|
||
|
( tmp_cube_X + dh < NGSTAR_LEVEL_WIDTH )) &&
|
||
|
/* is next cell a wall ? */
|
||
|
(this->board[(tmp_cube_Y + dv)*NGSTAR_LEVEL_WIDTH+tmp_cube_X + dh] == empty)
|
||
|
)
|
||
|
{
|
||
|
tmp_cube_Y += dv;
|
||
|
tmp_cube_X += dh;
|
||
|
}
|
||
|
|
||
|
if ( ( tmp_cube_X != this->cube_X ) || ( tmp_cube_Y != this->cube_Y ) ) {
|
||
|
// if it's the first move then set t1 as the start of level
|
||
|
if ( this->nb_moves == 0 )
|
||
|
(void) time( &( this->t1 ) );
|
||
|
/* empty previous cell */
|
||
|
this->board[this->cube_Y*NGSTAR_LEVEL_WIDTH+this->cube_X] = empty;
|
||
|
|
||
|
/* changing coordinates */
|
||
|
this->cube_Y = tmp_cube_Y;
|
||
|
this->cube_X = tmp_cube_X;
|
||
|
|
||
|
/* set destination cell */
|
||
|
this->board[tmp_cube_Y*NGSTAR_LEVEL_WIDTH+tmp_cube_X] = cube;
|
||
|
|
||
|
++(this->nb_moves);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// public:
|
||
|
|
||
|
//
|
||
|
// Constructor, initialize things
|
||
|
//
|
||
|
NGStar2::NGStar2( Configuration *config )
|
||
|
{
|
||
|
this->config = config;
|
||
|
this->load_level( );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Load level nb_level from current levelset if level exists
|
||
|
//
|
||
|
void NGStar2::load_level( )
|
||
|
{
|
||
|
string *level_filename;
|
||
|
|
||
|
if ( ( this->config->levelset != NULL ) &&
|
||
|
( this->config->current_level <= this->config->nb_levels ) ) {
|
||
|
level_filename = new string( this->config->levelsets_path->c_str( ) );
|
||
|
level_filename->append( "/" );
|
||
|
level_filename->append( this->config->levelset->c_str( ) );
|
||
|
level_filename->append( "/" );
|
||
|
level_filename->append( itos( this->config->current_level ) );
|
||
|
|
||
|
read_level( level_filename );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Load level nb_level from current levelset if level exists
|
||
|
//
|
||
|
void NGStar2::load_level( const char *filename )
|
||
|
{
|
||
|
read_level( new string( filename ) );
|
||
|
}
|
||
|
|
||
|
void NGStar2::next_level ( )
|
||
|
{
|
||
|
if( ( this->config->current_level + 1 ) <= this->config->nb_levels )
|
||
|
++(this->config->current_level);
|
||
|
|
||
|
this->load_level( );
|
||
|
}
|
||
|
|
||
|
void NGStar2::previous_level( )
|
||
|
{
|
||
|
if( this->config->current_level > 1 )
|
||
|
--(this->config->current_level);
|
||
|
|
||
|
this->load_level( );
|
||
|
}
|
||
|
|
||
|
void NGStar2::switch_moving( )
|
||
|
{
|
||
|
++( this->nb_moves );
|
||
|
this->moving = ( this->moving == ball ) ? cube : ball;
|
||
|
}
|
||
|
|
||
|
void NGStar2::move( direction where )
|
||
|
{
|
||
|
if ( this->moving == ball )
|
||
|
this->move_ball( where );
|
||
|
else
|
||
|
this->move_cube( where );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Check is there's gifts left and return the result
|
||
|
//
|
||
|
bool NGStar2::is_it_over( void )
|
||
|
{
|
||
|
return( ( this->nb_gifts > 0 ) ? false : true );
|
||
|
}
|
||
|
|
||
|
int NGStar2::get_duration( )
|
||
|
{
|
||
|
time_t t2;
|
||
|
(void) time( &( t2 ) );
|
||
|
return( (int)t2 - ( this->t1 ) );
|
||
|
}
|
||
|
|
||
|
} // end namespace ngstar2
|