////////////////////////////////////////////////////////////////////// // XLogical - A puzzle game // // Copyright (C) 2000 Neil Brown, Tom Warkentin // // This program 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. // // This program 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 this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // or at the website: http://www.gnu.org // //////////////////////////////////////////////////////////////////////// // Language Includes #include #include #include #include #include #ifndef USE_HASH_MAP #include #else #include #endif #include using namespace std; // Application Includes #include "defs.h" #include "graph.h" #include "levelmap.h" #ifdef FALSE #undef FALSE #endif #define FALSE 0 #ifdef TRUE #undef TRUE #endif #define TRUE 1 //#define DEBUG_FUNC //#define DEBUG_TOKENS enum tokens { NO_TOKEN = 0, STARTBLOCK, ENDBLOCK, MAP_TIME_LIMIT, BALL_SPEED, BALL_TIME_LIMIT, MAX_MOVING_BALLS, RANDOM_ORDER, RANDOM_PATTERN, PATTERN_TIME, MAP, YES, NO, // MAP TILES TELEPORT_UP, // TPUP TELEPORT_DOWN, // TPDN TELEPORT_LEFT, // TPLT TELEPORT_RIGHT, // TPRT TELEPORT_HORIZ, // TPHH TELEPORT_VERT, // TPVV TELEPORT_VERT_LEFT, // TPVL TELEPORT_VERT_RIGHT, // TPVR TELEPORT_HORIZ_UP, // TPHU TELEPORT_HORIZ_DOWN, // TPHD TELEPORT_HORIZ_VERT, // TPHV COLOR_1_BLOCK_HORIZ, // BL1H COLOR_2_BLOCK_HORIZ, // BL2H COLOR_3_BLOCK_HORIZ, // BL3H COLOR_4_BLOCK_HORIZ, // BL4H COLOR_1_BLOCK_VERT, // BL1V COLOR_2_BLOCK_VERT, // BL2V COLOR_3_BLOCK_VERT, // BL3V COLOR_4_BLOCK_VERT, // BL4V COLOR_1_BLOCK_H_V, // BL1B COLOR_2_BLOCK_H_V, // BL2B COLOR_3_BLOCK_H_V, // BL3B COLOR_4_BLOCK_H_V, // BL4B MOVING_BALLS_TILE, // MOVE NEXT_COLOR_DISP, // NEXT ORDER_TILE, // ORDR PATTERN_TILE, // PATT BALL_TIMER_TILE, // BALL START_UP, // STRU START_DOWN, // STRD START_LEFT, // STRL START_RIGHT, // STRR SPINNER_TILE, // SPIN UNUSED_TILE, // BLNK LEVEL_TIMER_TILE, // LEVL COLOR_1_PAINT_HORIZ, // PT1H COLOR_2_PAINT_HORIZ, // PT2H COLOR_3_PAINT_HORIZ, // PT3H COLOR_4_PAINT_HORIZ, // PT4H COLOR_1_PAINT_VERT, // PT1V COLOR_2_PAINT_VERT, // PT2V COLOR_3_PAINT_VERT, // PT3V COLOR_4_PAINT_VERT, // PT4V COLOR_1_PAINT_H_V, // PT1B COLOR_2_PAINT_H_V, // PT2B COLOR_3_PAINT_H_V, // PT3B COLOR_4_PAINT_H_V, // PT4B HORIZ_AND_VERT, // HHVV HORIZ_WITH_DOWN, // HHDD HORIZ_WITH_UP, // HHUU VERT_WITH_LEFT, // VVLL VERT_WITH_RIGHT, // VVRR HORIZ, // HHHH VERT, // VVVV END_UP, // ENDU END_DOWN, // ENDD END_LEFT, // ENDL END_RIGHT, // ENDR ONEWAY_UP_UDLR, // OUHV ONEWAY_UP_ULR, // OUHU ONEWAY_UP_UDL, // OUVL ONEWAY_UP_UDR, // OUVR ONEWAY_UP_UL, // OULU ONEWAY_UP_UR, // OURU ONEWAY_UP_UD, // OUVV ONEWAY_UP_END, // OUND ONEWAY_DOWN_UDLR, // ODHV ONEWAY_DOWN_DLR, // ODHD ONEWAY_DOWN_UDL, // ODVL ONEWAY_DOWN_UDR, // ODVR ONEWAY_DOWN_DL, // ODLD ONEWAY_DOWN_DR, // ODRD ONEWAY_DOWN_UD, // ODVV ONEWAY_DOWN_END, // ODND ONEWAY_LEFT_UDLR, // OLHV ONEWAY_LEFT_DLR, // OLHD ONEWAY_LEFT_ULR, // OLHU ONEWAY_LEFT_UDL, // OLVL ONEWAY_LEFT_DL, // OLLD ONEWAY_LEFT_UL, // OLLU ONEWAY_LEFT_LR, // OLHH ONEWAY_LEFT_END, // OLND ONEWAY_RIGHT_UDLR, // ORHV ONEWAY_RIGHT_DLR, // ORHD ONEWAY_RIGHT_ULR, // ORHU ONEWAY_RIGHT_UDR, // ORVR ONEWAY_RIGHT_DR, // ORRD ONEWAY_RIGHT_UR, // ORRU ONEWAY_RIGHT_LR, // ORHH ONEWAY_RIGHT_END, // ORND COVERED_UDLR, // CHVV COVERED_ULR, // CHUU COVERED_DLR, // CHDD COVERED_UDL, // CVLL COVERED_UDR, // CVRR COVERED_DL, // CDLL COVERED_DR, // CDRR COVERED_UL, // CULL COVERED_UR, // CURR COVERED_LR, // CHHH COVERED_UD, // CVVV COVERED_END_UP, // CNDU COVERED_END_DOWN, // CNDD COVERED_END_LEFT, // CNDL COVERED_END_RIGHT, // CNDR // Marker for external tokens NUM_EXTERNAL_TOKENS, // INTERNAL TOKENS AFTER THIS IDENTIFIER, INTEGER, FLOAT, UNKNOWN, // End of the tokens NUM_TOKENS }; // Possible text tokens in the map text const char *tokenStrings[] = { "notoken", "{", "}", "map_time_limit", "ball_speed", "ball_time_limit", "max_moving_balls", "random_order", "random_pattern", "pattern_time", "map", "yes", "no", "tpup", "tpdn", "tplt", "tprt", "tphh", "tpvv", "tpvl", "tpvr", "tphu", "tphd", "tphv", "bl1h", "bl2h", "bl3h", "bl4h", "bl1v", "bl2v", "bl3v", "bl4v", "bl1b", "bl2b", "bl3b", "bl4b", "move", "next", "ordr", "patt", "ball", "stru", "strd", "strl", "strr", "spin", "blnk", "levl", "pt1h", "pt2h", "pt3h", "pt4h", "pt1v", "pt2v", "pt3v", "pt4v", "pt1b", "pt2b", "pt3b", "pt4b", "hhvv", "hhdd", "hhuu", "vvll", "vvrr", "hhhh", "vvvv", "endu", "endd", "endl", "endr", "ouhv", "ouhu", "ouvl", "ouvr", "oulu", "ouru", "ouvv", "ound", "odhv", "odhd", "odvl", "odvr", "odld", "odrd", "odvv", "odnd", "olhv", "olhd", "olhu", "olvl", "olld", "ollu", "olhh", "olnd", "orhv", "orhd", "orhu", "orvr", "orrd", "orru", "orhh", "ornd", "chvv", "chuu", "chdd", "cvll", "cvrr", "cdll", "cdrr", "cull", "curr", "chhh", "cvvv", "cndu", "cndd", "cndl", "cndr" }; #define OUT(x) cerr<<(x)< TokenMap; #else struct Token_lt { bool operator()( const char *p, const char *q ) const { return( (strcasecmp( p, q ) < 0) ); } }; typedef map TokenMap; #endif TokenMap tokenMap; Clevel_map::Clevel_map( ) { #ifdef DEBUG_FUNC cerr << __FILE__ << " Clevel_map::constructor( )" << endl; #endif base_init( ); } Clevel_map::Clevel_map( char *mapText ) { #ifdef DEBUG_FUNC cerr << __FILE__ << " Clevel_map::constructor( )" << endl; #endif base_init( ); try { load_level( mapText ); } catch( const char *str ) { cerr << "ERROR: " << str << endl; } } Clevel_map::~Clevel_map( ) { #ifdef DEBUG_FUNC cerr << __FILE__ << " Clevel_map::destructor( )" << endl; #endif } char * Clevel_map::load_level( char *inText ) { #ifdef DEBUG_FUNC cerr << __FILE__ << " Clevel_map::load_level( )" << endl; #endif char *textPtr = NULL; try { textPtr = parse_map( inText ); //post_process_map( ); } catch( const char *str ) { throw( str ); } return( textPtr ); } void Clevel_map::base_init( void ) { #ifdef DEBUG_FUNC cerr << __FILE__ << " Clevel_map::base_init( )" << endl; #endif int i; xSize = 10; ySize = 7; tileSize = 64; ballSize = 16; maxBallsInMotion= 5; numBallsInMotion= 0; nextColor = (color_t)(rand( ) % 4 + 1); ballTimeLimit = 60 * kTicksInSecond; mapTimeLimit = 300 * kTicksInSecond; ballSpdPct = 50; ballSpd = BALL_SPEED_MAX * ( (float)ballSpdPct / 100.0 ); spinnersFinished= 0; spinnersOnMap = 0; startPathActive = 0; patternWaitTime = 60 * kTicksInSecond; nextPatternTime = 0; bgPixmap = BMP_BACK_GAME; haveMapTimer = 0; haveBallTimer = 0; ballStartTime = 0; // Clear up all the tiles tiles.clear( ); // Initialize some settings for( i = 0; i < 4; i++ ) { // Spinner completion pattern matching pattern[i] = NO_COLOR; // Settings for solid color spinner ordering order[i] = NO_COLOR; } // Clear the random flags randPattern = 0; randOrder = 0; } void Clevel_map::reset( void ) { #ifdef DEBUG_FUNC cerr << __FILE__ << " Clevel_map::reset( )" << endl; #endif vector< Ctile * >::iterator it; numBallsInMotion= 0; nextColor = (color_t)(rand( ) % 4 + 1); startTime = graphDriver->graph_get_time(); spinnersFinished= 0; startPathActive = 0; nextPatternTime = 0; ballStartTime = 0; for( int i = 0; i < 4; i++ ) { pattern[i] = NO_COLOR; order[i] = NO_COLOR; } randPattern = 0; randOrder = 0; for( it = tiles.begin( ); it != tiles.end( ); it++ ) { (*it)->balls.clear(); if( (*it)->get_type( ) == SPINNER ) { TILE_SPINNER( *it )->finished = 0; TILE_SPINNER( *it )->finishing = 0; TILE_SPINNER( *it )->finishing_hopper = 0; TILE_SPINNER( *it )->moving = 0; TILE_SPINNER( *it )->hopper[0] = NULL; TILE_SPINNER( *it )->hopper[1] = NULL; TILE_SPINNER( *it )->hopper[2] = NULL; TILE_SPINNER( *it )->hopper[3] = NULL; TILE_SPINNER( *it )->anim_frames.reset_anim( ); } } // Do the post processing stuff post_process_map( ); } char * Clevel_map::parse_map( char *mText ) { #ifdef DEBUG_FUNC cerr << __FILE__ << " Clevel_map::parse_map( )" << endl; #endif int done = false; int tokenID = 0; int haveMap = 0; if( get_next_token( &mText ) != IDENTIFIER ) { // We're done throw( "Expecting Level Name" ); } else { mapName = new char[ strlen( currentSymbol ) + 1]; strcpy( mapName, currentSymbol ); } if( get_next_token( &mText ) != STARTBLOCK ) { throw( "Expecting { after LEVEL NAME" ); } while( !done ) { tokenID = get_next_token( &mText ); switch( tokenID ) { case MAP_TIME_LIMIT: if( get_next_token( &mText ) == INTEGER ) { mapTimeLimit = currentInteger * kTicksInSecond; } else { throw( "Expecting Integer after MAP_TIME_LIMIT" ); } break; case BALL_TIME_LIMIT: if( get_next_token( &mText ) == INTEGER ) { ballTimeLimit = currentInteger * kTicksInSecond; } else { throw( "Expecting Integer after BALL_TIME_LIMIT" ); } break; case BALL_SPEED: if( get_next_token( &mText ) == INTEGER ) { ballSpdPct = currentInteger; } else { throw( "Expecting Integer after BALL_SPEED" ); } break; case MAX_MOVING_BALLS: if( get_next_token( &mText ) == INTEGER ) { maxBallsInMotion = currentInteger; } else { throw( "Expecting Integer after MAX_MOVING_BALLS" ); } break; case RANDOM_ORDER: if( get_next_token( &mText ) == YES ) { randOrder = 1; } break; case RANDOM_PATTERN: if( get_next_token( &mText ) == YES ) { randPattern = 1; new_pattern(); // generate a new random pattern } break; case PATTERN_TIME: if( get_next_token( &mText ) == INTEGER ) { patternWaitTime = currentInteger * kTicksInSecond; } else { throw( "Expecting Integer after PATTERN_TIME" ); } break; case MAP: if( get_next_token( &mText ) == STARTBLOCK ) { try { read_map( &mText ); } catch( const char *str ) { throw( str ); } haveMap = 1; } else { throw( "Expecting { after MAP keyword" ); } break; case ENDBLOCK: done = true; break; default: cerr << currentSymbol << endl; throw( "IDENTIFIER out of place." ); break; } } // Skip trailing whitespace so we start fresh next time skip_white( &mText ); if( haveMap ) { // Return the position we left off at return( mText ); } else { throw( "INCOMPLETE LEVEL" ); } } void Clevel_map::read_ball_colors( char **mText ) { #ifdef DEBUG_FUNC cerr << __FILE__ << " Clevel_map::read_ball_colors( )" << endl; #endif } void Clevel_map::read_color_block( char **mText, color_t *tColors, int count ) { #ifdef DEBUG_FUNC cerr << __FILE__ << " Clevel_map::read_color_block( )" << endl; #endif } void Clevel_map::read_map( char **mText ) { #ifdef DEBUG_FUNC cerr << __FILE__ << " Clevel_map::read_map( )" << endl; #endif Ctile *tempTile; int done = false; int tokenID = 0; int index = 0; int haveStart = 0; while( !done ) { skip_white( mText ); tokenID = get_next_token( mText ); switch( tokenID ) { case TELEPORT_UP: tempTile = new Ctile_teleport( EXIT_UP ); break; case TELEPORT_DOWN: tempTile = new Ctile_teleport( EXIT_DOWN ); break; case TELEPORT_LEFT: tempTile = new Ctile_teleport( EXIT_LEFT ); break; case TELEPORT_RIGHT: tempTile = new Ctile_teleport( EXIT_RIGHT ); break; case TELEPORT_HORIZ: tempTile = new Ctile_teleport( EXIT_LEFT | EXIT_RIGHT ); break; case TELEPORT_VERT: tempTile = new Ctile_teleport( EXIT_UP | EXIT_DOWN ); break; case TELEPORT_VERT_LEFT: tempTile = new Ctile_teleport( EXIT_UP | EXIT_DOWN | EXIT_LEFT); break; case TELEPORT_VERT_RIGHT: tempTile = new Ctile_teleport( EXIT_UP | EXIT_DOWN | EXIT_RIGHT); break; case TELEPORT_HORIZ_UP: tempTile = new Ctile_teleport( EXIT_UP | EXIT_LEFT | EXIT_RIGHT); break; case TELEPORT_HORIZ_DOWN: tempTile = new Ctile_teleport( EXIT_DOWN | EXIT_LEFT | EXIT_RIGHT); break; case TELEPORT_HORIZ_VERT: tempTile = new Ctile_teleport( EXIT_UP | EXIT_DOWN | EXIT_LEFT | EXIT_RIGHT); break; case COLOR_1_BLOCK_HORIZ: tempTile = new Ctile_blocker( C1, EXIT_LEFT | EXIT_RIGHT ); break; case COLOR_2_BLOCK_HORIZ: tempTile = new Ctile_blocker( C2, EXIT_LEFT | EXIT_RIGHT ); break; case COLOR_3_BLOCK_HORIZ: tempTile = new Ctile_blocker( C3, EXIT_LEFT | EXIT_RIGHT ); break; case COLOR_4_BLOCK_HORIZ: tempTile = new Ctile_blocker( C4, EXIT_LEFT | EXIT_RIGHT ); break; case COLOR_1_BLOCK_VERT: tempTile = new Ctile_blocker( C1, EXIT_UP | EXIT_DOWN ); break; case COLOR_2_BLOCK_VERT: tempTile = new Ctile_blocker( C2, EXIT_UP | EXIT_DOWN ); break; case COLOR_3_BLOCK_VERT: tempTile = new Ctile_blocker( C3, EXIT_UP | EXIT_DOWN ); break; case COLOR_4_BLOCK_VERT: tempTile = new Ctile_blocker( C4, EXIT_UP | EXIT_DOWN ); break; case COLOR_1_BLOCK_H_V: tempTile = new Ctile_blocker( C1, EXIT_UP | EXIT_DOWN | EXIT_LEFT | EXIT_RIGHT ); break; case COLOR_2_BLOCK_H_V: tempTile = new Ctile_blocker( C2, EXIT_UP | EXIT_DOWN | EXIT_LEFT | EXIT_RIGHT ); break; case COLOR_3_BLOCK_H_V: tempTile = new Ctile_blocker( C3, EXIT_UP | EXIT_DOWN | EXIT_LEFT | EXIT_RIGHT ); break; case COLOR_4_BLOCK_H_V: tempTile = new Ctile_blocker( C4, EXIT_UP | EXIT_DOWN | EXIT_LEFT | EXIT_RIGHT ); break; case MOVING_BALLS_TILE: tempTile = new Ctile_moving( ); break; case NEXT_COLOR_DISP: tempTile = new Ctile_next; break; case ORDER_TILE: tempTile = new Ctile_order; break; case PATTERN_TILE: tempTile = new Ctile_pattern; break; case START_UP: if( !haveStart ) { tempTile = new Ctile_start( EXIT_UP ); startTile = tiles.size( ); haveStart = 1; } else { throw( "Cannot have more than one start square in map" ); } break; case START_DOWN: if( !haveStart ) { tempTile = new Ctile_start( EXIT_DOWN ); startTile = tiles.size( ); haveStart = 1; } else { throw( "Cannot have more than one start square in map" ); } break; case START_LEFT: if( !haveStart ) { tempTile = new Ctile_start( EXIT_LEFT ); startTile = tiles.size( ); haveStart = 1; } else { throw( "Cannot have more than one start square in map" ); } break; case START_RIGHT: if( !haveStart ) { tempTile = new Ctile_start( EXIT_RIGHT ); startTile = tiles.size( ); haveStart = 1; } else { throw( "Cannot have more than one start square in map" ); } break; case SPINNER_TILE: tempTile = new Ctile_spinner; spinnersOnMap++; break; case UNUSED_TILE: tempTile = new Ctile_blank; break; case LEVEL_TIMER_TILE: tempTile = new Ctile_timer; break; case COLOR_1_PAINT_HORIZ: tempTile = new Ctile_painter( C1, EXIT_LEFT | EXIT_RIGHT ); break; case COLOR_2_PAINT_HORIZ: tempTile = new Ctile_painter( C2, EXIT_LEFT | EXIT_RIGHT ); break; case COLOR_3_PAINT_HORIZ: tempTile = new Ctile_painter( C3, EXIT_LEFT | EXIT_RIGHT ); break; case COLOR_4_PAINT_HORIZ: tempTile = new Ctile_painter( C4, EXIT_LEFT | EXIT_RIGHT ); break; case COLOR_1_PAINT_VERT: tempTile = new Ctile_painter( C1, EXIT_UP | EXIT_DOWN ); break; case COLOR_2_PAINT_VERT: tempTile = new Ctile_painter( C2, EXIT_UP | EXIT_DOWN ); break; case COLOR_3_PAINT_VERT: tempTile = new Ctile_painter( C3, EXIT_UP | EXIT_DOWN ); break; case COLOR_4_PAINT_VERT: tempTile = new Ctile_painter( C4, EXIT_UP | EXIT_DOWN ); break; case COLOR_1_PAINT_H_V: tempTile = new Ctile_painter( C1, EXIT_UP | EXIT_DOWN | EXIT_LEFT | EXIT_RIGHT ); break; case COLOR_2_PAINT_H_V: tempTile = new Ctile_painter( C2, EXIT_UP | EXIT_DOWN | EXIT_LEFT | EXIT_RIGHT ); break; case COLOR_3_PAINT_H_V: tempTile = new Ctile_painter( C3, EXIT_UP | EXIT_DOWN | EXIT_LEFT | EXIT_RIGHT ); break; case COLOR_4_PAINT_H_V: tempTile = new Ctile_painter( C4, EXIT_UP | EXIT_DOWN | EXIT_LEFT | EXIT_RIGHT ); break; case HORIZ_AND_VERT: tempTile = new Ctile_track( EXIT_UP | EXIT_DOWN | EXIT_LEFT | EXIT_RIGHT ); break; case HORIZ_WITH_DOWN: tempTile = new Ctile_track( EXIT_DOWN | EXIT_LEFT| EXIT_RIGHT ); break; case HORIZ_WITH_UP: tempTile = new Ctile_track( EXIT_UP | EXIT_LEFT| EXIT_RIGHT ); break; case VERT_WITH_LEFT: tempTile = new Ctile_track( EXIT_UP | EXIT_DOWN | EXIT_LEFT ); break; case VERT_WITH_RIGHT: tempTile = new Ctile_track( EXIT_UP | EXIT_DOWN | EXIT_RIGHT ); break; case HORIZ: tempTile = new Ctile_track( EXIT_LEFT| EXIT_RIGHT ); break; case VERT: tempTile = new Ctile_track( EXIT_UP | EXIT_DOWN ); break; case END_UP: tempTile = new Ctile_track( EXIT_UP ); break; case END_DOWN: tempTile = new Ctile_track( EXIT_DOWN ); break; case END_LEFT: tempTile = new Ctile_track( EXIT_LEFT ); break; case END_RIGHT: tempTile = new Ctile_track( EXIT_RIGHT ); break; case ONEWAY_UP_UDLR: tempTile = new Ctile_oneway( EXIT_UP | EXIT_DOWN | EXIT_LEFT | EXIT_RIGHT, UP ); case ONEWAY_UP_ULR: tempTile = new Ctile_oneway( EXIT_UP | EXIT_LEFT | EXIT_RIGHT, UP ); break; case ONEWAY_UP_UDL: tempTile = new Ctile_oneway( EXIT_UP | EXIT_DOWN | EXIT_LEFT, UP ); break; case ONEWAY_UP_UDR: tempTile = new Ctile_oneway( EXIT_UP | EXIT_DOWN | EXIT_RIGHT, UP ); break; case ONEWAY_UP_UL: tempTile = new Ctile_oneway( EXIT_UP | EXIT_LEFT, UP ); break; case ONEWAY_UP_UR: tempTile = new Ctile_oneway( EXIT_UP | EXIT_RIGHT, UP ); break; case ONEWAY_UP_UD: tempTile = new Ctile_oneway( EXIT_UP | EXIT_DOWN, UP ); break; case ONEWAY_UP_END: tempTile = new Ctile_oneway( EXIT_UP, UP ); break; case ONEWAY_DOWN_UDLR: tempTile = new Ctile_oneway( EXIT_UP | EXIT_DOWN | EXIT_LEFT | EXIT_RIGHT, DOWN ); break; case ONEWAY_DOWN_DLR: tempTile = new Ctile_oneway( EXIT_DOWN | EXIT_LEFT | EXIT_RIGHT, DOWN ); break; case ONEWAY_DOWN_UDL: tempTile = new Ctile_oneway( EXIT_UP | EXIT_DOWN | EXIT_LEFT, DOWN ); break; case ONEWAY_DOWN_UDR: tempTile = new Ctile_oneway( EXIT_UP | EXIT_DOWN | EXIT_RIGHT, DOWN ); break; case ONEWAY_DOWN_DL: tempTile = new Ctile_oneway( EXIT_DOWN | EXIT_LEFT, DOWN ); break; case ONEWAY_DOWN_DR: tempTile = new Ctile_oneway( EXIT_DOWN | EXIT_RIGHT, DOWN ); break; case ONEWAY_DOWN_UD: tempTile = new Ctile_oneway( EXIT_UP | EXIT_DOWN, DOWN ); break; case ONEWAY_DOWN_END: tempTile = new Ctile_oneway( EXIT_DOWN, DOWN ); break; case ONEWAY_LEFT_UDLR: tempTile = new Ctile_oneway( EXIT_UP | EXIT_DOWN | EXIT_LEFT | EXIT_RIGHT, LEFT ); break; case ONEWAY_LEFT_DLR: tempTile = new Ctile_oneway( EXIT_DOWN | EXIT_LEFT | EXIT_RIGHT, LEFT ); break; case ONEWAY_LEFT_ULR: tempTile = new Ctile_oneway( EXIT_UP | EXIT_LEFT | EXIT_RIGHT, LEFT ); break; case ONEWAY_LEFT_UDL: tempTile = new Ctile_oneway( EXIT_UP | EXIT_DOWN | EXIT_LEFT , LEFT ); break; case ONEWAY_LEFT_DL: tempTile = new Ctile_oneway( EXIT_DOWN | EXIT_LEFT , LEFT ); break; case ONEWAY_LEFT_UL: tempTile = new Ctile_oneway( EXIT_UP | EXIT_LEFT , LEFT ); break; case ONEWAY_LEFT_LR: tempTile = new Ctile_oneway( EXIT_LEFT | EXIT_RIGHT, LEFT ); break; case ONEWAY_LEFT_END: tempTile = new Ctile_oneway( EXIT_LEFT, LEFT ); break; case ONEWAY_RIGHT_UDLR: tempTile = new Ctile_oneway( EXIT_UP | EXIT_DOWN | EXIT_LEFT | EXIT_RIGHT, RIGHT ); break; case ONEWAY_RIGHT_DLR: tempTile = new Ctile_oneway( EXIT_DOWN | EXIT_LEFT | EXIT_RIGHT, RIGHT ); break; case ONEWAY_RIGHT_ULR: tempTile = new Ctile_oneway( EXIT_UP | EXIT_LEFT | EXIT_RIGHT, RIGHT ); break; case ONEWAY_RIGHT_UDR: tempTile = new Ctile_oneway( EXIT_UP | EXIT_DOWN | EXIT_RIGHT, RIGHT ); break; case ONEWAY_RIGHT_DR: tempTile = new Ctile_oneway( EXIT_DOWN | EXIT_RIGHT, RIGHT ); break; case ONEWAY_RIGHT_UR: tempTile = new Ctile_oneway( EXIT_UP | EXIT_RIGHT, RIGHT ); break; case ONEWAY_RIGHT_LR: tempTile = new Ctile_oneway( EXIT_LEFT | EXIT_RIGHT, RIGHT ); break; case ONEWAY_RIGHT_END: tempTile = new Ctile_oneway( EXIT_RIGHT, RIGHT ); break; case COVERED_UDLR: tempTile = new Ctile_covered( EXIT_UP | EXIT_DOWN | EXIT_LEFT | EXIT_RIGHT ); break; case COVERED_ULR: tempTile = new Ctile_covered( EXIT_UP | EXIT_LEFT | EXIT_RIGHT ); break; case COVERED_DLR: tempTile = new Ctile_covered( EXIT_DOWN | EXIT_LEFT | EXIT_RIGHT ); break; case COVERED_UDL: tempTile = new Ctile_covered( EXIT_UP | EXIT_DOWN | EXIT_LEFT ); break; case COVERED_UDR: tempTile = new Ctile_covered( EXIT_UP | EXIT_DOWN | EXIT_RIGHT ); break; case COVERED_DL: tempTile = new Ctile_covered( EXIT_DOWN | EXIT_LEFT ); break; case COVERED_DR: tempTile = new Ctile_covered( EXIT_DOWN | EXIT_RIGHT ); break; case COVERED_UL: tempTile = new Ctile_covered( EXIT_UP | EXIT_LEFT ); break; case COVERED_UR: tempTile = new Ctile_covered( EXIT_UP | EXIT_RIGHT ); break; case COVERED_LR: tempTile = new Ctile_covered( EXIT_LEFT | EXIT_RIGHT ); break; case COVERED_UD: tempTile = new Ctile_covered( EXIT_UP | EXIT_DOWN ); break; case COVERED_END_UP: tempTile = new Ctile_covered( EXIT_UP ); break; case COVERED_END_DOWN: tempTile = new Ctile_covered( EXIT_DOWN ); break; case COVERED_END_LEFT: tempTile = new Ctile_covered( EXIT_LEFT ); break; case COVERED_END_RIGHT: tempTile = new Ctile_covered( EXIT_RIGHT ); break; case ENDBLOCK: done = TRUE; break; default: done = TRUE; cerr << "[" << currentSymbol << "]" << endl; throw( "Unknown Map tile!" ); break; } if( !done ) { // Set the index tempTile->indexPos = index++; // Add the new tile to our list tiles.insert( tiles.end( ), tempTile ); } else { if( index < xSize * ySize ) { throw( "Not enough map tiles!!" ); } } } } void skip_white( char **cPtr ) { #ifdef DEBUG_FUNC cerr << __FILE__ << " Clevel_map::skip_white( )" << endl; #endif while ( isspace( **cPtr ) ) { //cerr <<"Skipping: [" << (int)**cPtr<< "]" << endl; *cPtr = *cPtr + 1; } } int get_next_token( char **cPtr ) { #ifdef DEBUG_FUNC cerr << __FILE__ << " Clevel_map::get_next_token( )" << endl; #endif int retVal = IDENTIFIER; skip_white( cPtr ); get_next_word( cPtr ); // Is it an integer? if( current_is_integer( ) ) { retVal = INTEGER; } else { // Is it a float? if( current_is_float( ) ) { retVal = FLOAT; } else { retVal = get_current_token_id( ); } } // Can't have a zero-length identifier if( (retVal == IDENTIFIER) && ( strlen( currentSymbol ) == 0 ) ) { retVal = UNKNOWN; } #ifdef DEBUG_TOKENS cerr << "Read in [" << currentSymbol << "]" << endl; cerr << "Current Symbol: [" << currentSymbol << "]" << endl; cerr << "Current Integer: " << currentInteger << "" << endl; cerr << "Current Float: " << currentFloat << "" << endl; #endif return( retVal ); } void get_next_word( char **tokenStr ) { #ifdef DEBUG_FUNC cerr << __FILE__ << " Clevel_map::get_next_word( )" << endl; #endif int counter = 0; bool inQuote = false; while( (**tokenStr != '\0') && (counter < MAX_BUFFER_SIZE) && (inQuote || !isspace( **tokenStr )) ) { if (**tokenStr == '\"') { if (!inQuote) { inQuote = true; (*tokenStr)++; continue; } else { (*tokenStr)++; break; } } currentSymbol[counter] = **tokenStr; (*tokenStr)++; counter++; } // Tack on our null currentSymbol[counter] = '\0'; } int current_is_integer( void ) { #ifdef DEBUG_FUNC cerr << __FILE__ << " Clevel_map::current_is_integer( )" << endl; #endif int retVal = TRUE; unsigned long i = 0; // Check for a sign if( ( currentSymbol[i] == '+' ) || ( currentSymbol[i] == '-' ) || ( isdigit( currentSymbol[i] ) ) ) { for( i=1; i < strlen( currentSymbol ); i ++ ) { if( !isdigit( currentSymbol[i] ) ) { retVal = FALSE; } } } else { retVal = FALSE; } if( retVal ) { currentInteger = strtol( currentSymbol, NULL, 10 ); } return( retVal ); } int current_is_float( void ) { #ifdef DEBUG_FUNC cerr << __FILE__ << " Clevel_map::current_is_float( )" << endl; #endif int retVal = FALSE; if( (currentFloat = strtod( currentSymbol, NULL )) ) { retVal = TRUE; } return( retVal ); } int get_current_token_id( void ) { #ifdef DEBUG_FUNC cerr << __FILE__ << " Clevel_map::get_current_token_id( )" << endl; #endif int id = IDENTIFIER; TokenMap::iterator iter; static int start = 1; // Build the token hash the first time 'round if( start ) { start = 0; // Build the hash map tokenMap.clear(); #ifdef USE_HASH_MAP tokenMap.resize( static_cast(NUM_EXTERNAL_TOKENS * 1.5) ); #endif for( int i = 0; i < NUM_EXTERNAL_TOKENS; i ++ ) { tokenMap[(char *)tokenStrings[i]] = i; } } #ifdef DEBUG_TOKENS cerr << "Searching for: [" << currentSymbol << "]" << endl; #endif iter = tokenMap.find( currentSymbol ); if( iter != tokenMap.end( ) ) { id = iter->second; } else { id = IDENTIFIER; } #ifdef DEBUG_TOKENS cerr << "FOUND: " << id << endl; #endif return( id ); } void Clevel_map::post_process_map( void ) { #ifdef DEBUG_FUNC cerr << __FILE__ << " Clevel_map::post_process_map( )" << endl; #endif vector< Ctile * >::iterator it; int idx = 0; int row; int col; for( it = tiles.begin( ); it != tiles.end( ); it++, idx++ ) { // Get the row/col we're on row = idx / xSize; col = idx % xSize; switch( (*it)->get_type( ) ) { case SPINNER: // Check UP if( idx - xSize >= 0 ) { if( (tiles[idx - xSize]->exitFlags & EXIT_DOWN) || (tiles[idx - xSize]->get_type( ) == SPINNER) ) { (*it)->exitFlags |= EXIT_UP; } } // Check Down if( idx + xSize < xSize * ySize - 1 ) { if( (tiles[idx + xSize]->exitFlags & EXIT_UP) || (tiles[idx + xSize]->get_type( ) == SPINNER) ) { (*it)->exitFlags |= EXIT_DOWN; } } // Check Left if( idx - 1 >= 0 ) { if( (tiles[idx - 1]->exitFlags & EXIT_RIGHT) || (tiles[idx - 1]->get_type( ) == SPINNER) ) { (*it)->exitFlags |= EXIT_LEFT; } } // Check right if( idx + 1 < xSize * ySize - 1 ) { if( (tiles[idx + 1]->exitFlags & EXIT_LEFT) || (tiles[idx + 1]->get_type( ) == SPINNER) ) { (*it)->exitFlags |= EXIT_RIGHT; } } break; case TIME_DISP: haveMapTimer = 1; break; case BALL_TIMER: haveBallTimer = 1; break; case TRACK: break; case PATTERN_DISP: // Set a default pattern spinnerPattern[0] = (color_t)(rand( )%4 + 1); spinnerPattern[1] = (color_t)(rand( )%4 + 1); spinnerPattern[2] = (color_t)(rand( )%4 + 1); spinnerPattern[3] = (color_t)(rand( )%4 + 1); new_pattern( ); break; case ORDER_DISP: // Set some default order if we don't have any if( order[0] == NO_COLOR ) { order[0] = (color_t)(rand( )%4 + 1); order[1] = (color_t)(rand( )%4 + 1); order[2] = (color_t)(rand( )%4 + 1); } break; default: break; } } } void Clevel_map::new_pattern( void ) { #ifdef DEBUG_FUNC cerr << __FILE__ << " Clevel_map::new_pattern( )" << endl; #endif if ( randPattern == 1 ) { // calculate new random pattern pattern[0] = (color_t)(rand( )%4 + 1); pattern[1] = (color_t)(rand( )%4 + 1); pattern[2] = (color_t)(rand( )%4 + 1); pattern[3] = (color_t)(rand( )%4 + 1); } else { // restore old pattern pattern[0] = spinnerPattern[0]; pattern[1] = spinnerPattern[1]; pattern[2] = spinnerPattern[2]; pattern[3] = spinnerPattern[3]; } } Ctile_teleport * Clevel_map::find_teleport_with_dir( Ctile_teleport *t, dir_t dir ) { #ifdef DEBUG_FUNC cerr << __FILE__ << " Clevel_map::find_teleport_with_dir( )" << endl; #endif // Dir is the direction we'd LEAVE the teleporter from... vector< Ctile *>::iterator it; it = tiles.begin( ); while( it != tiles.end( ) ) { if( ((*it)->get_type( ) == TELEPORT ) && ( TILE_TELEPORT( *it ) != t ) ) { switch( dir ) { case UP: if( (*it)->exitFlags & EXIT_UP ) { return( TILE_TELEPORT( *it ) ); } break; case DOWN: if( (*it)->exitFlags & EXIT_DOWN ) { return( TILE_TELEPORT( *it ) ); } break; case LEFT: if( (*it)->exitFlags & EXIT_LEFT ) { return( TILE_TELEPORT( *it ) ); } break; case RIGHT: if( (*it)->exitFlags & EXIT_RIGHT ) { return( TILE_TELEPORT( *it ) ); } break; default: break; } } it++; } cout << "MATCHING TELEPORT NOT FOUND! ACK!" << endl; return( NULL ); } // $Id: levelmap.cpp,v 1.4 2003-03-11 08:31:43 tom Exp $ // // $Log: levelmap.cpp,v $ // Revision 1.4 2003-03-11 08:31:43 tom // fixed g++ 3.2.3 compilation errors // // Revision 1.3 2001/07/31 20:54:54 tom // Changed system time functions to use time function provided by Cgraph // class instead of using OS system calls. This should make it easier // to port to other operating systems, e.g. BSD. // // Revision 1.2 2001/02/16 20:59:55 tom // did some WIN32 porting work on the code... just a few more files to go. // // Revision 1.1 2001/01/20 17:32:28 brown // Working toward Windows integration // // Revision 1.9 2000/10/09 03:21:37 tom // fixed resetting of order and pattern tiles // // Revision 1.8 2000/10/08 05:29:44 tom // reset spinner vars that were carried over between games // // Revision 1.7 2000/10/08 02:53:48 brown // Fixed the level editor and some graphics // // Revision 1.6 2000/10/07 19:26:21 brown // Added BALL_SPEED_PCT to the parser // Fixed debug info output // // Revision 1.5 2000/10/07 19:12:18 brown // Speed-throttling code completed // // Revision 1.4 2000/10/07 18:16:34 brown // Ball movement fixes // // Revision 1.2 2000/10/06 19:29:06 brown // Added autoconf stuff // Added GPL header to files // Added WON scroller // Added GPL to about screen // // Revision 1.1.1.1 2000/09/28 02:17:52 tom // imported sources // // Revision 1.44 2000/07/23 16:50:28 brown // Fixed level timer changing while paused // Added "finish spinner" animation // Fixed level ending before last spinner finished ( sortof ) // // Revision 1.43 2000/02/13 07:16:37 tom // - changed level names to include spaces // - made it so that player cannot advance intermission screens until bonus // is finished being moved to the player's score // // Revision 1.42 2000/02/13 06:27:18 tom // Fixed new ball timer bug and high score update bug. // // Revision 1.41 2000/02/13 03:44:50 brown // Start tile changes, as well as some font scroll changes // // Revision 1.40 2000/02/12 21:07:08 brown // // Bunch of new backgrounds // // Revision 1.39 2000/02/12 20:39:48 tom // whoops... accidentally checked in stuff without finishing my comment the // last time. Anyway, fixed up music transition between game states. // // Revision 1.38 2000/02/12 20:38:34 tom // Fixed up // // Revision 1.37 2000/01/10 02:53:48 brown // Bunch of changes - fixed start track, fixed order and pattern, fixed some // backgrounds. // // Revision 1.36 2000/01/09 02:26:16 brown // Quite a few fixes - speedup for the level loading, passwords work etc // // Revision 1.35 2000/01/02 01:30:36 tom // fixed hash table lookup of tokens // // Revision 1.34 2000/01/01 22:44:25 tom // Added a user defined comparison routine for the hash map. Commented out all // the hash map code and put back linear search code for tokens... but it still // cores. // // Revision 1.33 2000/01/01 21:51:19 brown // Mucho changes - fixed level loading and game startup screens // // Revision 1.32 1999/12/28 08:54:51 tom // Fixed level maps to work with new teleporters. // // Revision 1.31 1999/12/27 03:38:00 brown // Fixed teleporters I hope - updated graphics etc // // Revision 1.30 1999/12/25 08:18:34 tom // Added "Id" and "Log" CVS keywords to source code. //