#include "blocks.hpp" #include "global_vars.hpp" #include "objectids.hpp" #include "sprites.hpp" #include "editor_visitor.hpp" #include #include #include "visitors/mario_visitor.hpp" #include "visitors/bounce_visitor.hpp" #include "blocks/simpleblocks.hpp" #include "blocks/coineditorblock.hpp" #include "blocks/coinblock.hpp" #include "blocks/mushroomblock.hpp" #include "mario.hpp" #define CAN_BE_DESTROYED_FLAG 0x0000000000000001 #define HAS_COLLISION 0x0000000000000002 MarioBlock::MarioBlock( int x, int y, const std::shared_ptr< SDLPP::Renderer > &renderer, std::shared_ptr< SDLPP::Texture > texture, SDL_Rect src, bool can_be_destroyed, bool destructible ) : RectangleRender( x * BLOCK_SIZE, 1 - ( 16 - y ) * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE, renderer, texture, src ) { _can_be_destroyed = can_be_destroyed; _destructible = can_be_destroyed && destructible; setMovementSpeed( 1 ); _coins = 0; _mushroom = false; _base_src = src; } void MarioBlock::visit( SDLPP::Visitor &visitor ) { #ifdef EDITOR if ( !_tool && _terrain && visitor.getVisitorType() == VisitorType::Terrain ) { destroy(); } if ( !_tool && !_terrain && visitor.getVisitorType() == VisitorType::Modifier ) { destroy(); } #else if ( visitor.getFromId() == MARIO_TOP_DETECT && dynamic_cast< MarioVisitor & >( visitor ).canDestroy() ) { // TODO if big mario and _can_be_destroyed if ( _destructible && !hasCoin() ) { destroy(); } else { BounceVisitor bv; bv.setVisitorType( VisitorType::Terrain ); setPos( getPos() - SDLPP::Vec2D< double >( 0, BLOCK_SIZE ) ); if ( getCollisions().size() < 2 ) addCollision( SDLPP::RectColider( 0.1, 0.1, 0.8, 0.8, BOUNCE_COLLISION ) ); updateSizeAndPosition(); g_playground->visitCollisions( *this, bv ); setPos( getPos() + SDLPP::Vec2D< double >( 0, BLOCK_SIZE ) ); updateSizeAndPosition(); if ( bv.canBounce() ) bounce(); } if ( hasCoin() ) { removeCoin(); auto coin = createTerrainBlock(COIN_ID, LandType::OVERWORLD, renderer); coin->setPos(getPos()); std::dynamic_pointer_cast(coin)->setParent(this); dynamic_cast< MarioVisitor & >( visitor ).setCoin(); dynamic_cast< MarioVisitor & >( visitor ).setCoinBlock(coin); } if ( hasMushroom() ) { removeMushroom(); auto mushroom = createTerrainBlock(MUSHROOM_ID, LandType::OVERWORLD, renderer); mushroom->setPos(getPos()); std::dynamic_pointer_cast(mushroom)->setParent(this); dynamic_cast< MarioVisitor & >( visitor ).setMushroomBlock(mushroom); } } #endif visitor.visit( *this ); } void MarioBlock::setTool( bool tool ) { _tool = tool; } void MarioBlock::setTerrain( bool terrain ) { _terrain = terrain; } void MarioBlock::bounce() { if ( _bouncing ) { return; } _bouncing = true; og_pos = getPos(); ticks_to_bounce = bounce_ticks; setMovement( 0, -bounce_speed ); } void MarioBlock::travelToPos(const SDLPP::Vec2D &target) { if(_traveling) { return; } _traveling = true; _target = target; auto movement = (_target - getPos()); auto abs_mov_x = movement.getX(); if(abs_mov_x < 0) { abs_mov_x *= -1; } auto abs_mov_y = movement.getY(); if(abs_mov_y < 0) { abs_mov_y *= -1; } movement = movement / (abs_mov_x > abs_mov_y ? abs_mov_x : abs_mov_y); movement = movement * travel_speed; setMovement(movement.getX(), movement.getY()); } void MarioBlock::gravity(int ticks) { if(_on_ground) { return; } _ticks_till_gravity -= ticks; if(_ticks_till_gravity < 0) { addMovement(0, _gravity_acceleration); _ticks_till_gravity = _base_gravity_ticks; } } bool MarioBlock::isBouncing() const { return _bouncing; } bool MarioBlock::isTraveling() const { return _traveling; } void MarioBlock::custom_move( int ticks ) { if ( !_bouncing && !_traveling ) { return; } if( _bouncing ) { if ( getMovement().getY() < 0 ) { ticks_to_bounce -= ticks; if ( ticks_to_bounce < 0 ) { setMovement( 0, bounce_speed ); ticks_to_bounce = bounce_ticks; } } else { if ( getPos().getY() >= og_pos.getY() ) { setMovement( 0, 0 ); setPos( getPos().getX(), og_pos.getY() ); _bouncing = false; } } } if(_traveling) { bool overshot_x = (getMovement().getX() < 0 && getPos().getX() <= _target.getX()) || (getMovement().getX() > 0 && getPos().getX() >= _target.getX()); bool overshot_y = (getMovement().getY() < 0 && getPos().getY() <= _target.getY()) || (getMovement().getY() > 0 && getPos().getY() >= _target.getY()); if(overshot_x) { setPos(_target.getX(), getPos().getY()); setMovement(0, getMovement().getY()); } if(overshot_y) { setPos(getPos().getX(), _target.getY()); setMovement(getMovement().getX(), 0); } if(getMovement() == SDLPP::Vec2D(0,0)) { _traveling = false; } } } void MarioBlock::setType( LandType::Value type ) { _type = type; setWorldTypeSrc( _type ); } LandType::Value MarioBlock::getType() const { return _type; } bool MarioBlock::hasCoin() { return _coins > 0; } bool MarioBlock::hasMushroom() { return _mushroom; } void MarioBlock::removeCoin() { _coins--; } void MarioBlock::removeMushroom() { _mushroom = false; } void MarioBlock::addMushroom() { _mushroom = true; } void MarioBlock::setCoinCount( int coins ) { _coins = coins; } void MarioBlock::setDestructible( bool destructible ) { _destructible = destructible; } void MarioBlock::ensureCollision() { if ( getCollisions().size() == 0 ) { addCollision( SDLPP::RectColider( 0, 0, 1, 1 ) ); } } void MarioBlock::setWorldTypeSrc( LandType::Value world ) { auto rect = _base_src; switch ( world ) { case LandType::OVERWORLD: rect.x += OVERWORLD_SHIFT.getX(); rect.y += OVERWORLD_SHIFT.getY(); break; case LandType::UNDERWORLD: rect.x += UNDERWORLD_SHIFT.getX(); rect.y += UNDERWORLD_SHIFT.getY(); break; case LandType::WATER: rect.x += WATER_SHIFT.getX(); rect.y += WATER_SHIFT.getY(); break; case LandType::BOWSER: rect.x += BOWSER_SHIFT.getX(); rect.y += BOWSER_SHIFT.getY(); break; } setTextureSourceRect( rect ); } const std::vector< uint64_t > possibleBlocks = { FLOOR_ID, STEP_ID, HILL_TOP_ID, HILL_DOTS_LEFT_ID, HILL_FILL_ID, HILL_INCLINE_ID, HILL_DOTS_RIGHT_ID, HILL_DECLINE_ID, CLOUD_LEFT_TOP_ID, CLOUD_MIDDLE_TOP_ID, CLOUD_RIGHT_TOP_ID, VINE_TOP_ID, CLOUD_LEFT_BOTTOM_ID, CLOUD_MIDDLE_BOTTOM_ID, CLOUD_RIGHT_BOTTOM_ID, VINE_BOTTOM_ID, BRICK_TOP_ID, BRICK_ID, FLAG_ID, WATER_TOP_ID, BUSH_LEFT_ID, BUSH_MIDDLE_ID, BUSH_RIGHT_ID, WATER_FILL_ID, PIPE_LEFT_TOP_ID, PIPE_RIGHT_TOP_ID, CASTLE_TOWER_ID, CASTLE_TOWER_FILLED_ID, PIPE_LEFT_BOTTOM_ID, PIPE_RIGHT_BOTTOM_ID, CASTLE_LEFT_ID, CASTLE_RIGHT_ID, POLE_TOP_ID, CASTLE_ENTRY_ID, SIDEWAY_PIPE_END_TOP_ID, SIDEWAY_PIPE_MIDDLE_TOP_ID, POLE_BOTTOM_ID, CASTLE_BLACK_ID, SIDEWAY_PIPE_END_BOTTOM_ID, SIDEWAY_PIPE_MIDDLE_BOTTOM_ID, SIDEWAY_PIPE_CONNECTOR_TOP_ID, TREE_PLATFORM_TOP_LEFT_ID, TREE_PLATFORM_TOP_MIDDLE_ID, TREE_PLATFORM_TOP_RIGHT_ID, SIDEWAY_PIPE_CONNECTOR_BOTTOM_ID, MUSHROOM_PLATFORM_TOP_LEFT_ID, MUSHROOM_PLATFORM_TOP_MIDDLE_ID, MUSHROOM_PLATFORM_TOP_RIGHT_ID, TREE_PLATFORM_BARK_ID, MUSHROOM_PLATFORM_BARK_TOP_ID, TREE_LEAVES_TOP_ID, TREE_LEAVES_SMALL_ID, CANNON_TOWER_ID, MUSHROOM_PLATFORM_BARK_BOTTOM_ID, TREE_LEAVES_BOTTOM_ID, TREE_BARK_ID, CANNON_PEDESTAL_ID, CANNON_ID, }; const std::vector< uint64_t > possibleMods = { DESTRUCTIBLE_MODIFIER_ID, BACKGROUND_MODIFIER_ID, COIN_MODIFIER_ID, MUSHROOM_MODIFIER_ID, }; const std::vector< uint64_t > possibleCharacters = { MARIO_ID, }; const std::vector< LandType::Value > possibleLands = { LandType::OVERWORLD, LandType::UNDERWORLD, LandType::WATER, LandType::BOWSER }; std::shared_ptr< MarioBlock > createBlockById( uint64_t id, int x, int y, std::shared_ptr< SDLPP::Renderer > &renderer ) { std::shared_ptr< MarioBlock > result = nullptr; switch ( id ) { case FLOOR_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< FloorBlock >( x, y, renderer ) ); break; case HILL_INCLINE_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< HillInclineBlock >( x, y, renderer ) ); break; case HILL_DECLINE_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< HillDeclineBlock >( x, y, renderer ) ); break; case HILL_DOTS_RIGHT_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< HillDotsRightBlock >( x, y, renderer ) ); break; case HILL_DOTS_LEFT_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< HillDotsLeftBlock >( x, y, renderer ) ); break; case HILL_FILL_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< HillFillBlock >( x, y, renderer ) ); break; case HILL_TOP_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< HillTopBlock >( x, y, renderer ) ); break; case BUSH_LEFT_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< BushLeftBlock >( x, y, renderer ) ); break; case BUSH_MIDDLE_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< BushMiddleBlock >( x, y, renderer ) ); break; case BUSH_RIGHT_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< BushRightBlock >( x, y, renderer ) ); break; case CLOUD_LEFT_BOTTOM_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< CloudLeftBottomBlock >( x, y, renderer ) ); break; case CLOUD_MIDDLE_BOTTOM_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< CloudMiddleBottomBlock >( x, y, renderer ) ); break; case CLOUD_RIGHT_BOTTOM_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< CloudRightBottomBlock >( x, y, renderer ) ); break; case CLOUD_LEFT_TOP_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< CloudLeftTopBlock >( x, y, renderer ) ); break; case CLOUD_MIDDLE_TOP_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< CloudMiddleTopBlock >( x, y, renderer ) ); break; case CLOUD_RIGHT_TOP_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< CloudRightTopBlock >( x, y, renderer ) ); break; case PIPE_LEFT_BOTTOM_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< PipeLeftBottomBlock >( x, y, renderer ) ); break; case PIPE_RIGHT_BOTTOM_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< PipeRightBottomBlock >( x, y, renderer ) ); break; case PIPE_LEFT_TOP_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< PipeLeftTopBlock >( x, y, renderer ) ); break; case PIPE_RIGHT_TOP_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< PipeRightTopBlock >( x, y, renderer ) ); break; case CASTLE_LEFT_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< CastleLeftBlock >( x, y, renderer ) ); break; case CASTLE_RIGHT_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< CastleRightBlock >( x, y, renderer ) ); break; case CASTLE_BLACK_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< CastleBlackBlock >( x, y, renderer ) ); break; case CASTLE_ENTRY_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< CastleEntryBlock >( x, y, renderer ) ); break; case CASTLE_TOWER_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< CastleTowerBlock >( x, y, renderer ) ); break; case CASTLE_TOWER_FILLED_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< CastleTowerFilledBlock >( x, y, renderer ) ); break; case VINE_TOP_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< VineTopBlock >( x, y, renderer ) ); break; case VINE_BOTTOM_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< VineBottomBlock >( x, y, renderer ) ); break; case POLE_TOP_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< PoleTopBlock >( x, y, renderer ) ); break; case POLE_BOTTOM_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< PoleBottomBlock >( x, y, renderer ) ); break; case FLAG_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< FlagBlock >( x, y, renderer ) ); break; case STEP_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< StepBlock >( x, y, renderer ) ); break; case BRICK_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< BrickBlock >( x, y, renderer ) ); break; case BRICK_TOP_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< BrickTopBlock >( x, y, renderer ) ); break; case SIDEWAY_PIPE_END_TOP_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< SidewayPipeEndTopBlock >( x, y, renderer ) ); break; case SIDEWAY_PIPE_END_BOTTOM_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< SidewayPipeEndBottomBlock >( x, y, renderer ) ); break; case SIDEWAY_PIPE_MIDDLE_TOP_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< SidewayPipeMiddleTopBlock >( x, y, renderer ) ); break; case SIDEWAY_PIPE_MIDDLE_BOTTOM_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< SidewayPipeMiddleBottomBlock >( x, y, renderer ) ); break; case SIDEWAY_PIPE_CONNECTOR_TOP_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< SidewayPipeConnectorTopBlock >( x, y, renderer ) ); break; case SIDEWAY_PIPE_CONNECTOR_BOTTOM_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< SidewayPipeConnectorBottomBlock >( x, y, renderer ) ); break; case TREE_PLATFORM_TOP_LEFT_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< TreePlatformTopLeftBlock >( x, y, renderer ) ); break; case TREE_PLATFORM_TOP_MIDDLE_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< TreePlatformTopMiddleBlock >( x, y, renderer ) ); break; case TREE_PLATFORM_TOP_RIGHT_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< TreePlatformTopRightBlock >( x, y, renderer ) ); break; case TREE_PLATFORM_BARK_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< TreePlatformBarkBlock >( x, y, renderer ) ); break; case WATER_TOP_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< WaterTopBlock >( x, y, renderer ) ); break; case WATER_FILL_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< WaterFillBlock >( x, y, renderer ) ); break; case MUSHROOM_PLATFORM_TOP_LEFT_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< MushroomPlatformTopLeftBlock >( x, y, renderer ) ); break; case MUSHROOM_PLATFORM_TOP_MIDDLE_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< MushroomPlatformTopMiddleBlock >( x, y, renderer ) ); break; case MUSHROOM_PLATFORM_TOP_RIGHT_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< MushroomPlatformTopRightBlock >( x, y, renderer ) ); break; case MUSHROOM_PLATFORM_BARK_TOP_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< MushroomPlatformBarkTopBlock >( x, y, renderer ) ); break; case MUSHROOM_PLATFORM_BARK_BOTTOM_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< MushroomPlatformBarkBottomBlock >( x, y, renderer ) ); break; case TREE_BARK_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< TreeBarkBlock >( x, y, renderer ) ); break; case TREE_LEAVES_SMALL_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< TreeLeavesSmallBlock >( x, y, renderer ) ); break; case TREE_LEAVES_TOP_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< TreeLeavesTopBlock >( x, y, renderer ) ); break; case TREE_LEAVES_BOTTOM_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< TreeLeavesBottomBlock >( x, y, renderer ) ); break; case CANNON_TOWER_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< CannonTowerBlock >( x, y, renderer ) ); break; case CANNON_PEDESTAL_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< CannonPedestalBlock >( x, y, renderer ) ); break; case CANNON_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< CannonBlock >( x, y, renderer ) ); break; case MARIO_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< Mario >( x, y, renderer ) ); break; case DESTRUCTIBLE_MODIFIER_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< DestructibleModifierBlock >( x, y, renderer ) ); break; case BACKGROUND_MODIFIER_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< BackgroundModifierBlock >( x, y, renderer ) ); break; #ifdef EDITOR case COIN_MODIFIER_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< CoinEditorBlock >( x, y, renderer ) ); break; #endif case MUSHROOM_MODIFIER_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< MushroomModifierBlock >( x, y, renderer ) ); break; #ifndef EDITOR case COIN_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< CoinBlock >( x, y, renderer ) ); break; case MUSHROOM_ID: result = std::static_pointer_cast< MarioBlock >( std::make_shared< MushroomBlock >( x, y, renderer ) ); break; #endif } return result; } std::shared_ptr< MarioBlock > createBlock( std::shared_ptr< SDLPP::Renderer > &renderer, int x, int y, uint64_t id, LandType::Value land_type, bool destructible, bool editor ) { auto block = createBlockById( id, x, y, renderer ); if ( block == nullptr ) { return nullptr; } block->setAlignment( SDLPP::OBJ_CENTER, SDLPP::OBJ_CENTER ); block->setStatic(); block->setType( land_type ); if ( destructible ) { block->setDestructible(); } if ( editor ) { block->ensureCollision(); } return block; } // TODO coin count std::shared_ptr< MarioBlock > createTerrainBlock( uint64_t block_id, LandType::Value type, std::shared_ptr< SDLPP::Renderer > &renderer, int x, int y, bool destructible, bool editor ) { return createBlock( renderer, x, y, block_id, type, destructible, editor ); } std::shared_ptr< MarioBlock > createTerrainBlock( uint64_t block_id, LandType::Value type, std::shared_ptr< SDLPP::Renderer > &renderer, bool destructible, bool editor ) { return createTerrainBlock( block_id, type, renderer, 0, 0, destructible, editor ); } std::shared_ptr< MarioBlock > createMario( LandType::Value type, std::shared_ptr< SDLPP::Renderer > &renderer, int x, int y, bool editor ) { // TODO add type additions auto mario = createBlock( renderer, x, y, MARIO_ID, type, false, true ); if ( editor ) { mario->setTerrain( false ); mario->removeCollisions(); mario->ensureCollision(); } return mario; } enum BlockRole::Value getBlockRole( uint64_t id ) { if ( id >= 0x7000 ) return BlockRole::TERRAIN; if ( id == MARIO_ID ) return BlockRole::MARIO; if ( id < MARIO_ID ) return BlockRole::MODIFIER; // TODO modifier/character return BlockRole::MODIFIER; } void MarioBlock::setBaseRect(SDL_Rect rect) { _base_src = rect; setType(getType()); } void MarioBlock::checkVisibility(double rightmost_x) { // we assume that object's X > 0 as otherwise it would be destroyed if(!getHidden() && getAbsolutePos().getX() < rightmost_x) { _was_visible = true; } } bool MarioBlock::wasVisible() const { return _was_visible; }