#include "functions.hpp" #include "custom_classes.hpp" #include "global_vars.hpp" #include "scenes.hpp" #include bool validPos( SDLPP::Scene &scene, std::shared_ptr< TetrisPiece > piece ) { for ( auto &x : piece->getObjects() ) { auto collisions = scene.getCollisions( *x, { BRICK_ID, FLOOR_ID, BORDER_LEFT_ID, BORDER_RIGHT_ID } ); if ( collisions.size() > 1 ) return false; } return true; } void updateShadow( SDLPP::Scene &scene ) { if ( !g_cur_object ) { g_cur_shadow->destroy(); g_cur_shadow.reset(); return; } if ( !g_cur_shadow ) return; g_cur_shadow->setPos( g_cur_object->getPos() ); double shadow_drop = BOTTOM_BORDER; auto &invalid_objects = g_cur_object->getObjects(); for ( auto &x : g_cur_shadow->getObjects() ) { auto block_pos = x->getPos(); if ( BOTTOM_BORDER - block_pos.second < shadow_drop ) shadow_drop = BOTTOM_BORDER - block_pos.second; // set colider column's position to current block's X position g_shadow_colider->setPos( block_pos.first, TOP_BORDER ); auto collisions = scene.getCollisions( *g_shadow_colider, { BRICK_ID } ); auto curY = block_pos.second; for ( auto &col : collisions ) { // if collision with g_cur_object, ignore if ( std::find( invalid_objects.begin(), invalid_objects.end(), col ) != invalid_objects.end() ) continue; auto possible_drop = col->getPos().second - curY; if ( possible_drop < shadow_drop && possible_drop >= 0 ) shadow_drop = possible_drop; } } // we want the shadow to rest on top of the nearest floor shadow_drop -= BLOCK_SIZE; auto shadow_pos = g_cur_shadow->getPos(); g_cur_shadow->setPos( shadow_pos.first, shadow_pos.second + shadow_drop ); } void moveThem( std::shared_ptr< SDLPP::Scene > scene, int ticks ) { if ( !g_cur_object ) return; // get movement generated by player auto movement = g_cur_object->getMovement(); g_ticks_till_fall -= ticks; if ( g_cur_object->isDescending() ) g_ticks_till_descend -= ticks; if ( g_cur_object->isMoving() ) g_ticks_till_movement -= ticks; if ( g_ticks_till_fall > 0 ) { if ( g_cur_object->isMoving() && g_ticks_till_movement <= 0 ) { g_ticks_till_movement = TICKS_TILL_MOVE; g_cur_object->movePiece( movement.first * BLOCK_SIZE, 0 ); if ( !validPos( *scene, g_cur_object ) ) { g_cur_object->movePiece( movement.first * -BLOCK_SIZE, 0 ); return; } else goto check_floor; } if ( g_cur_object->isDescending() && g_ticks_till_descend <= 0 ) { g_ticks_till_descend = TICKS_TILL_DESCEND; g_cur_object->movePiece( 0, movement.second * BLOCK_SIZE ); if ( !validPos( *scene, g_cur_object ) ) { g_cur_object->movePiece( 0, movement.second * -BLOCK_SIZE ); return; } else goto check_floor; } return; } g_ticks_till_fall = TICKS_TILL_FALL; g_cur_object->movePiece( 0, BLOCK_SIZE ); check_floor: bool fell = false; for ( auto &x : g_cur_object->getObjects() ) { auto collisions = scene->getCollisions( *x, { BRICK_ID, FLOOR_ID } ); // we get 1 collision every time with ourselves if ( collisions.size() > 1 ) { fell = true; break; } } if ( fell ) { g_cur_object->movePiece( 0, -BLOCK_SIZE ); for ( auto &block : g_cur_object->getObjects() ) { if ( scene->getCollisions( *block, { GAME_OVER } ).size() > 0 ) { g_update_scenes.push_back(g_game_over_scene); g_active_scenes.push_back( g_game_over_scene ); g_input_functions.push_back( gameOverSceneInput ); #ifdef FEATURE pauseBlocks(); #endif break; } } g_cur_object.reset(); } updateShadow( *scene ); } void quitGame() { std::cout << "Quitting!" << std::endl; g_quit = true; } void resetGame() { g_cur_object.reset(); g_checked_line = true; g_next_object.reset(); g_score = 0; g_update_score = true; g_main_scene->resetScene(); g_main_scene->setPrevTicks( SDL_GetTicks() ); g_active_scenes = { g_main_scene }; g_input_functions = { mainSceneInput }; for ( int i = 0; i < 7; i++ ) g_bag[i] = 28; } int crashFlags( std::shared_ptr< TetrisPiece > piece, std::shared_ptr< TetrisBlock > block, SDLPP::Scene &scene, int left, int right, int bottom ) { int retFlags = 0; auto collisions = scene.getCollisions( *block, { BORDER_LEFT_ID, BORDER_RIGHT_ID, FLOOR_ID } ); for ( auto &col : collisions ) { switch ( col->getId() ) { case BORDER_LEFT_ID: retFlags |= left; break; case BORDER_RIGHT_ID: retFlags |= right; break; case FLOOR_ID: retFlags |= bottom; default: break; } } collisions = scene.getCollisions( *block, { BRICK_ID } ); if ( collisions.size() > 1 ) { for ( auto &col : collisions ) { if ( piece->isLeft( *col ) ) retFlags |= left; else if ( piece->isRight( *col ) ) retFlags |= right; else retFlags |= bottom; } } return retFlags; } bool checkRotation( std::shared_ptr< TetrisPiece > piece, SDLPP::Scene &scene ) { int crash = 0; int cur_left = 0x01; int cur_right = 0x02; int was_left = 0x04; int was_right = 0x08; int bottom = 0x10; int counter = 0; do { counter++; if ( counter > 5 ) { piece->revert(); return false; } crash = 0; for ( auto &block : piece->getObjects() ) { crash |= crashFlags( piece, block, scene, cur_left, cur_right, bottom ); } if ( crash & bottom || ( crash & cur_left && crash & cur_right ) || ( crash & cur_left && crash & was_right ) || ( crash & cur_right && crash & was_left ) ) { piece->revert(); return false; } crash &= ~( was_left | was_right ); if ( crash & cur_left ) { piece->movePiece( BLOCK_SIZE, 0 ); crash &= ~cur_left; crash |= was_left; } if ( crash & cur_right ) { piece->movePiece( -BLOCK_SIZE, 0 ); crash &= ~cur_right; crash |= was_right; } } while ( crash ); return true; } std::shared_ptr< TetrisBlock > createTetrisBlock( double x, double y, const std::string &color, const std::string &outline, int index, std::shared_ptr< SDLPP::Renderer > renderer, std::shared_ptr< SDLPP::Scene > scene ) { auto ret = std::make_shared< TetrisBlock >( x, y, BLOCK_SIZE, BLOCK_SIZE, renderer, color, true, index, scene, g_bag ); ret->setOutlineColor( outline ); ret->addCollision( SDLPP::RectColider( 0.1, 0.1, 0.8, 0.8 ) ); ret->setId( BRICK_ID ); ret->centerX(); scene->addObject( ret ); return ret; } std::shared_ptr< TetrisPiece > tetrisBrick( std::shared_ptr< SDLPP::Renderer > renderer, std::shared_ptr< SDLPP::Scene > scene ) { auto retPiece = std::make_shared< TetrisPiece >(); auto color = colors["piece_brick"]; auto outline = colors["piece_brick_out"]; retPiece->addPiece( createTetrisBlock( 0.5 - BLOCK_SIZE, TOP_BORDER, color, outline, TETRIS_BRICK, renderer, scene ), -1, 0 ); retPiece->addPiece( createTetrisBlock( 0.5, TOP_BORDER, color, outline, TETRIS_BRICK, renderer, scene ), 0, 0 ); retPiece->addPiece( createTetrisBlock( 0.5 - BLOCK_SIZE, TOP_BORDER + BLOCK_SIZE, color, outline, TETRIS_BRICK, renderer, scene ), -1, 1 ); retPiece->addPiece( createTetrisBlock( 0.5, TOP_BORDER + BLOCK_SIZE, color, outline, TETRIS_BRICK, renderer, scene ), 0, 1 ); retPiece->disableRotation(); return retPiece; } std::shared_ptr< TetrisPiece > tetrisT( std::shared_ptr< SDLPP::Renderer > renderer, std::shared_ptr< SDLPP::Scene > scene ) { auto retPiece = std::make_shared< TetrisPiece >(); auto color = colors["piece_T"]; auto outline = colors["piece_T_out"]; retPiece->addPiece( createTetrisBlock( 0.5 - BLOCK_SIZE, TOP_BORDER + BLOCK_SIZE, color, outline, TETRIS_T, renderer, scene ), -1, 0 ); retPiece->addPiece( createTetrisBlock( 0.5, TOP_BORDER + BLOCK_SIZE, color, outline, TETRIS_T, renderer, scene ), 0, 0 ); retPiece->addPiece( createTetrisBlock( 0.5, TOP_BORDER, color, outline, TETRIS_T, renderer, scene ), 0, -1 ); retPiece->addPiece( createTetrisBlock( 0.5 + BLOCK_SIZE, TOP_BORDER + BLOCK_SIZE, color, outline, TETRIS_T, renderer, scene ), 1, 0 ); return retPiece; } std::shared_ptr< TetrisPiece > tetrisLRight( std::shared_ptr< SDLPP::Renderer > renderer, std::shared_ptr< SDLPP::Scene > scene ) { auto retPiece = std::make_shared< TetrisPiece >(); auto color = colors["piece_L_right"]; auto outline = colors["piece_L_right_out"]; retPiece->addPiece( createTetrisBlock( 0.5 - BLOCK_SIZE, TOP_BORDER + BLOCK_SIZE, color, outline, TETRIS_L_RIGHT, renderer, scene ), -2, 0 ); retPiece->addPiece( createTetrisBlock( 0.5, TOP_BORDER + BLOCK_SIZE, color, outline, TETRIS_L_RIGHT, renderer, scene ), -1, 0 ); retPiece->addPiece( createTetrisBlock( 0.5 + BLOCK_SIZE, TOP_BORDER + BLOCK_SIZE, color, outline, TETRIS_L_RIGHT, renderer, scene ), 0, 0 ); retPiece->addPiece( createTetrisBlock( 0.5 + BLOCK_SIZE, TOP_BORDER, color, outline, TETRIS_L_RIGHT, renderer, scene ), 0, -1 ); return retPiece; } std::shared_ptr< TetrisPiece > tetrisZRight( std::shared_ptr< SDLPP::Renderer > renderer, std::shared_ptr< SDLPP::Scene > scene ) { auto retPiece = std::make_shared< TetrisPiece >(); auto color = colors["piece_Z_right"]; auto outline = colors["piece_Z_right_out"]; retPiece->addPiece( createTetrisBlock( 0.5 - BLOCK_SIZE, TOP_BORDER + BLOCK_SIZE, color, outline, TETRIS_Z_RIGHT, renderer, scene ), -1, 0 ); retPiece->addPiece( createTetrisBlock( 0.5, TOP_BORDER + BLOCK_SIZE, color, outline, TETRIS_Z_RIGHT, renderer, scene ), 0, 0 ); retPiece->addPiece( createTetrisBlock( 0.5, TOP_BORDER, color, outline, TETRIS_Z_RIGHT, renderer, scene ), 0, -1 ); retPiece->addPiece( createTetrisBlock( 0.5 + BLOCK_SIZE, TOP_BORDER, color, outline, TETRIS_Z_RIGHT, renderer, scene ), 1, -1 ); return retPiece; } std::shared_ptr< TetrisPiece > tetrisLine( std::shared_ptr< SDLPP::Renderer > renderer, std::shared_ptr< SDLPP::Scene > scene ) { auto retPiece = std::make_shared< TetrisPiece >(); auto color = colors["piece_line"]; auto outline = colors["piece_line_out"]; retPiece->addPiece( createTetrisBlock( 0.5 - 2 * BLOCK_SIZE, TOP_BORDER, color, outline, TETRIS_LINE, renderer, scene ), -1, 0 ); retPiece->addPiece( createTetrisBlock( 0.5 - BLOCK_SIZE, TOP_BORDER, color, outline, TETRIS_LINE, renderer, scene ), 0, 0 ); retPiece->addPiece( createTetrisBlock( 0.5, TOP_BORDER, color, outline, TETRIS_LINE, renderer, scene ), 1, 0 ); retPiece->addPiece( createTetrisBlock( 0.5 + BLOCK_SIZE, TOP_BORDER, color, outline, TETRIS_LINE, renderer, scene ), 2, 0 ); return retPiece; } std::shared_ptr< TetrisPiece > tetrisLLeft( std::shared_ptr< SDLPP::Renderer > renderer, std::shared_ptr< SDLPP::Scene > scene ) { auto retPiece = std::make_shared< TetrisPiece >(); auto color = colors["piece_L_left"]; auto outline = colors["piece_L_left_out"]; retPiece->addPiece( createTetrisBlock( 0.5 - BLOCK_SIZE, TOP_BORDER, color, outline, TETRIS_L_LEFT, renderer, scene ), 0, -1 ); retPiece->addPiece( createTetrisBlock( 0.5 - BLOCK_SIZE, TOP_BORDER + BLOCK_SIZE, color, outline, TETRIS_L_LEFT, renderer, scene ), 0, 0 ); retPiece->addPiece( createTetrisBlock( 0.5, TOP_BORDER + BLOCK_SIZE, color, outline, TETRIS_L_LEFT, renderer, scene ), 1, 0 ); retPiece->addPiece( createTetrisBlock( 0.5 + BLOCK_SIZE, TOP_BORDER + BLOCK_SIZE, color, outline, TETRIS_L_LEFT, renderer, scene ), 2, 0 ); return retPiece; } std::shared_ptr< TetrisPiece > tetrisZLeft( std::shared_ptr< SDLPP::Renderer > renderer, std::shared_ptr< SDLPP::Scene > scene ) { auto retPiece = std::make_shared< TetrisPiece >(); auto color = colors["piece_Z_left"]; auto outline = colors["piece_Z_left_out"]; retPiece->addPiece( createTetrisBlock( 0.5 - BLOCK_SIZE, TOP_BORDER, color, outline, TETRIS_Z_LEFT, renderer, scene ), -1, 0 ); retPiece->addPiece( createTetrisBlock( 0.5, TOP_BORDER, color, outline, TETRIS_Z_LEFT, renderer, scene ), 0, 0 ); retPiece->addPiece( createTetrisBlock( 0.5, TOP_BORDER + BLOCK_SIZE, color, outline, TETRIS_Z_LEFT, renderer, scene ), 0, 1 ); retPiece->addPiece( createTetrisBlock( 0.5 + BLOCK_SIZE, TOP_BORDER + BLOCK_SIZE, color, outline, TETRIS_Z_LEFT, renderer, scene ), 1, 1 ); return retPiece; } void updateSize() { // have to resize rectangles for the text to be resized correctly g_main_scene->updateSizeAndPosition(); g_menu_scene->updateSizeAndPosition(); g_game_over_scene->updateSizeAndPosition(); g_options_scene->updateSizeAndPosition(); std::unordered_set< int > textObjects = { TEXT_ID, MENU_TEXT_ID, MENU_ITEM_ID }; for ( auto &x : g_main_scene->getObjects( textObjects ) ) { x->updateSizeAndPosition(); } g_score_texture->updateSizeAndPosition(); for ( auto &x : g_menu_scene->getObjects( textObjects ) ) { x->updateSizeAndPosition(); } for ( auto &x : g_game_over_scene->getObjects( textObjects ) ) { x->updateSizeAndPosition(); } for ( auto &x : g_options_scene->getObjects( textObjects ) ) { x->updateSizeAndPosition(); } } void updateBlocks() { for ( auto &x : g_main_scene->getObjects( { BRICK_ID, SHADOW_ID } ) ) { x->specialAction( PIECE_ACTION_UPDATE_BLOCK ); } } #ifdef FEATURE void pauseBlocks() { for ( auto &x : g_main_scene->getObjects( { BRICK_ID, SHADOW_ID } ) ) { x->pauseAnimation(); } } void resumeBlocks() { for ( auto &x : g_main_scene->getObjects( { BRICK_ID, SHADOW_ID } ) ) { x->resumeAnimation(); } } #endif void updateColors() { for ( auto &x : g_main_scene->getObjects( { BRICK_ID, SHADOW_ID } ) ) { x->specialAction( PIECE_ACTION_UPDATE_COLOR ); } for ( auto &x : g_main_scene->getObjects( { BARRIER_ID } ) ) { x->setColor( colors["barrier"] ); } for ( auto &x : g_main_scene->getObjects( { BACKGROUND_ID } ) ) { x->setColor( colors["background"] ); } for ( auto &x : g_main_scene->getObjects( { SHADOW_ID } ) ) { x->setColor( colors["shadow"] ); } for ( auto &x : g_main_scene->getObjects( { LINE_ID } ) ) { x->setColor( colors["line"] ); } if ( g_font_config != nullptr ) { g_font_config->setColor( colors["text"] ); g_font_config->setOutlineColor( colors["text_out"] ); for ( auto &x : g_main_scene->getObjects( { TEXT_ID } ) ) { x->updateSizeAndPosition(); } } g_menu_options[g_menu_select]->setColor( colors["menu_item_background"] ); g_game_over_options[g_game_over_select]->setColor( colors["menu_item_background"] ); g_options_options[g_options_select]->setColor( colors["menu_item_background"] ); for ( auto &x : g_menu_scene->getObjects( { MENU_BACKGROUND_ID } ) ) { x->setColor( colors["menu_background"] ); } for ( auto &x : g_game_over_scene->getObjects( { MENU_BACKGROUND_ID } ) ) { x->setColor( colors["menu_background"] ); } for ( auto &x : g_options_scene->getObjects( { MENU_BACKGROUND_ID } ) ) { x->setColor( colors["menu_background"] ); } updateSize(); }