bool PlayerCollisions::checkleft(CPlayer& player)
{
    if (player.fy < 0.0f)
        return false;

    short tile_y = (short)player.fy / TILESIZE;

    if (tile_y < 0 || tile_y >= MAPHEIGHT)
        return false;

    short tile_y2 = ((short)player.fy + PH) / TILESIZE;

    if (tile_y2 < 0 || tile_y2 >= MAPHEIGHT)
        return false;

    short tile_x = player.ix / TILESIZE;

    if (tile_x < 0 || tile_x >= MAPWIDTH)
        return false;

    int topTile = g_map->map(tile_x, tile_y);
    int bottomTile = g_map->map(tile_x, tile_y2);
    IO_Block * topBlock = g_map->block(tile_x, tile_y);
    IO_Block * bottomBlock = g_map->block(tile_x, tile_y2);

    if ((topTile & tile_flag_solid) || (bottomTile & tile_flag_solid) ||
            (topBlock && !topBlock->isTransparent() && !topBlock->isHidden()) ||
            (bottomBlock && !bottomBlock->isTransparent() && !bottomBlock->isHidden())) {
        player.setXf((float)((tile_x << 5) + TILESIZE) + 0.2f);
        player.flipsidesifneeded();
        return true;
    }

    return false;
}
bool PlayerCollisions::checktop(CPlayer& player)
{
    if (player.topY() < 0.0f)
        return false;

    short tile_y = player.topY() / TILESIZE;

    if (tile_y < 0 || tile_y >= MAPHEIGHT)
        return false;

    short tile_x_left = player.leftX() / TILESIZE;

    if (tile_x_left < 0 || tile_x_left >= MAPWIDTH)
        return false;

    short tile_x_right = -1;
    if (player.rightX() >= 640)
        tile_x_right = (player.rightX() - 640) / TILESIZE;
    else
        tile_x_right = player.rightX() / TILESIZE;

    if (tile_x_right < 0 || tile_x_right >= MAPWIDTH)
        return false;

    int leftTile = g_map->map(tile_x_left, tile_y);
    int rightTile = g_map->map(tile_x_right, tile_y);
    IO_Block * leftBlock = g_map->block(tile_x_left, tile_y);
    IO_Block * rightBlock = g_map->block(tile_x_right, tile_y);

    if ((leftTile & tile_flag_solid) || (rightTile & tile_flag_solid) ||
            (leftBlock && !leftBlock->isTransparent() && !leftBlock->isHidden()) ||
            (rightBlock && !rightBlock->isTransparent() && !rightBlock->isHidden())) {
        player.setYf((float)((tile_y << 5) + TILESIZE) + 0.2f);
        return true;
    }

    return false;
}
Example #3
0
void IO_MovingObject::collision_detection_map()
{
	xf(fx + velx);
	flipsidesifneeded();

	fPrecalculatedY = fy + vely;  //Fixes weird float rounding error.  Must be computed here before casting to int.  Otherwise, this will miss the bottom collision, but then hit the side collision and the player can slide out of 1x1 spaces.

	float fPlatformVelX = 0.0f;
	float fPlatformVelY = 0.0f;

	float fTempY = fy;

	if(platform)
	{
		if(!onice)
		{
			fPlatformVelX = platform->fVelX;
			xf(fx + fPlatformVelX);
			flipsidesifneeded();
		}
		
		fPlatformVelY = platform->fVelY;

		if(platform->fOldVelY < 0.0f)
			fy += platform->fOldVelY;
		
		fPrecalculatedY += platform->fOldVelY;
	}

	iHorizontalPlatformCollision = -1;
	iVerticalPlatformCollision = -1;

	g_map.movingPlatformCollision(this);

	fy = fTempY;

	if(fPrecalculatedY + collisionHeight < 0.0f)
	{				// on top outside of the screen
		yf(fPrecalculatedY);
		vely = CapFallingVelocity(GRAVITATION + vely);
		
		if(!platform)
		{
			inair = true;
			onice = false;
		}

		return;
	}
	else if(fPrecalculatedY + collisionHeight >= 480.0f)
	{	//on ground outside of the screen?
		yi(-collisionHeight);
		fOldY = fy - 1.0f;
		onice = false;
		return;
	}

	//Could be optimized with bit shift >> 5
	short ty = (short)fy / TILESIZE;
	short ty2 = ((short)fy + collisionHeight) / TILESIZE;
	short tx = -1;
	

	//-----------------------------------------------------------------
	//  x axis first (--)
	//-----------------------------------------------------------------
	if(fy + collisionHeight >= 0.0f)
	{
		if(velx + fPlatformVelX > 0.01f || iHorizontalPlatformCollision == 3)
		{		//moving right
			if(fx + collisionWidth >= 640.0f)
			{
				tx = (short)(fx + collisionWidth - 640.0f) / TILESIZE;
				fOldX -= 640.0f;
			}
			else
                tx = ((short)fx + collisionWidth) / TILESIZE;

			IO_Block * topblock = g_map.block(tx, ty);
			IO_Block * bottomblock = g_map.block(tx, ty2);

			bool fTopBlockSolid = topblock && !topblock->isTransparent() && !topblock->isHidden();
			bool fBottomBlockSolid = bottomblock && !bottomblock->isTransparent() && !bottomblock->isHidden();
			if(fTopBlockSolid || fBottomBlockSolid)
			{
				bool processOtherBlock = true;
				if(fTopBlockSolid) //collide with top block
				{	
					if(iHorizontalPlatformCollision == 3)
					{
						KillObjectMapHazard();
						return;
					}

					topblock->collide(this, 1);
					flipsidesifneeded();
					removeifprojectile(this, true, true);

					processOtherBlock = false;

					SideBounce(true);
				}
				
				if(processOtherBlock && fBottomBlockSolid) //then bottom
				{	
					if(iHorizontalPlatformCollision == 3)
					{
						KillObjectMapHazard();
						return;
					}

					bottomblock->collide(this, 1);
					flipsidesifneeded();
					removeifprojectile(this, true, true);

					SideBounce(true);
				}
			}
			else if((g_map.map(tx, ty) & tile_flag_solid) || (g_map.map(tx, ty2) & tile_flag_solid))
			{	//collision on the right side.

				if(iHorizontalPlatformCollision == 3)
				{
					KillObjectMapHazard();
					return;
				}

				xf((float)((tx << 5) - collisionWidth) - 0.2f); //move to the edge of the tile (tile on the right -> mind the object width)
				fOldX = fx;
				
				if(velx > 0.0f)
					velx = -velx;

				flipsidesifneeded();
				removeifprojectile(this, true, true);

				SideBounce(true);
			}
		}
		else if(velx + fPlatformVelX < -0.01f || iHorizontalPlatformCollision == 1)
		{	//moving left
			tx = (short)fx / TILESIZE;

			//Just in case fx < 0 and wasn't caught by flipsidesifneeded()
			if(tx < 0)
				tx = 0;

			IO_Block * topblock = g_map.block(tx, ty);
			IO_Block * bottomblock = g_map.block(tx, ty2);

			bool fTopBlockSolid = topblock && !topblock->isTransparent() && !topblock->isHidden();
			bool fBottomBlockSolid = bottomblock && !bottomblock->isTransparent() && !bottomblock->isHidden();
			if(fTopBlockSolid || fBottomBlockSolid)
			{
				bool processOtherBlock = true;
				if(fTopBlockSolid) //collide with top block
				{	
					if(iHorizontalPlatformCollision == 1)
					{
						KillObjectMapHazard();
						return;
					}

					topblock->collide(this, 3);
					flipsidesifneeded();
					removeifprojectile(this, true, true);

					processOtherBlock = false;

					SideBounce(false);
				}
				
				if(processOtherBlock && fBottomBlockSolid) //then bottom
				{	
					if(iHorizontalPlatformCollision == 1)
					{
						KillObjectMapHazard();
						return;
					}

					bottomblock->collide(this, 3);
					flipsidesifneeded();
					removeifprojectile(this, true, true);

					SideBounce(false);
				}
			}
			else if((g_map.map(tx, ty) & tile_flag_solid) || (g_map.map(tx, ty2) & tile_flag_solid))
			{
				if(iHorizontalPlatformCollision == 1)
				{
					KillObjectMapHazard();
					return;
				}

				xf((float)((tx << 5) + TILESIZE) + 0.2f);			//move to the edge of the tile
				fOldX = fx;

				if(velx < 0.0f)
					velx = -velx;

				flipsidesifneeded();
				removeifprojectile(this, true, true);

				SideBounce(false);
			}
		}
	}

	short txl = -1, txr = -1;

	txl = ix / TILESIZE;

	if(ix + collisionWidth >= 640)
        txr = (ix + collisionWidth - 640) / TILESIZE;
	else
		txr = (ix + collisionWidth) / TILESIZE;

	//-----------------------------------------------------------------
	//  then y axis (|)
	//-----------------------------------------------------------------

	float fMovingUp = vely;
	if(platform)
		fMovingUp = vely + fPlatformVelY - bounce;

	if(fMovingUp < -0.01f)
	{
		ty = (short)(fPrecalculatedY) / TILESIZE;

		IO_Block * leftblock = g_map.block(txl, ty);
		IO_Block * rightblock = g_map.block(txr, ty);
		
		if(leftblock && !leftblock->isTransparent() && !leftblock->isHidden()) //then left
		{	
			if(iVerticalPlatformCollision == 2)
				KillObjectMapHazard();

			leftblock->collide(this, 0);
			return;
		}
		
		if(rightblock && !rightblock->isTransparent() && !rightblock->isHidden()) //then right
		{	
			if(iVerticalPlatformCollision == 2)
				KillObjectMapHazard();

			rightblock->collide(this, 0);
			return;
		}

		if((g_map.map(txl, ty) & tile_flag_solid) || (g_map.map(txr, ty) & tile_flag_solid))
		{
			if(iVerticalPlatformCollision == 2)
				KillObjectMapHazard();

			yf((float)((ty << 5) + TILESIZE) + 0.2f);
			fOldY = fy - 1.0f;
			
			if(vely < 0.0f)
				vely = -vely;	
		}
		else
		{
			yf(fPrecalculatedY);
			vely += GRAVITATION;
		}

		if(!platform)
		{
			inair = true;
        	onice = false;
		}
	}
	else
	{	//moving down / on ground
		ty = ((short)fPrecalculatedY + collisionHeight) / TILESIZE;

		IO_Block * leftblock = g_map.block(txl, ty);
		IO_Block * rightblock = g_map.block(txr, ty);

		bool fLeftBlockSolid = leftblock && !leftblock->isTransparent() && !leftblock->isHidden();
		bool fRightBlockSolid = rightblock && !rightblock->isTransparent() && !rightblock->isHidden();

		if(fLeftBlockSolid || fRightBlockSolid)
		{
			bool processOtherBlock = true;
			if(fLeftBlockSolid) //collide with left block
			{	
				processOtherBlock = leftblock->collide(this, 2);

				if(!platform)
				{
					inair = false;
					onice = false;
				}
			}
			
			if(processOtherBlock && fRightBlockSolid) //then right
			{	
				rightblock->collide(this, 2);
				
				if(!platform)
				{
					inair = false;
					onice = false;
				}
			}
			
			if(iVerticalPlatformCollision == 0)
				KillObjectMapHazard();

			return;
		}

		int leftTile = g_map.map(txl, ty);
		int rightTile = g_map.map(txr, ty);

		if((leftTile & tile_flag_solid_on_top) || (rightTile & tile_flag_solid_on_top))
		{
			if((fOldY + collisionHeight) / TILESIZE < ty)
			{
				vely = BottomBounce();
				yf((float)((ty << 5) - collisionHeight) - 0.2f);
				fOldY = fy - GRAVITATION;
				
				if(!platform)
				{
					inair = false;
					onice = false;
				}

				platform = NULL;

				if(iVerticalPlatformCollision == 0)
					KillObjectMapHazard();

				return;
			}
		}

		bool fSuperDeathTileUnderObject = fObjectDiesOnSuperDeathTiles && (((leftTile & tile_flag_super_death_top) && (rightTile & tile_flag_super_death_top)) ||
									 ((leftTile & tile_flag_super_death_top) && !(rightTile & tile_flag_solid)) ||
									 (!(leftTile & tile_flag_solid) && (rightTile & tile_flag_super_death_top)));

		if(((leftTile & tile_flag_solid) || (rightTile & tile_flag_solid)) && !fSuperDeathTileUnderObject)
		{	
			vely = BottomBounce();
			yf((float)((ty << 5) - collisionHeight) - 0.2f);
			fOldY = fy;

			if(!platform)
			{
				inair = false;

				if((leftTile & tile_flag_ice && ((rightTile & tile_flag_ice) || rightTile == tile_flag_nonsolid || rightTile == tile_flag_gap)) ||
					(rightTile & tile_flag_ice && ((leftTile & tile_flag_ice) || leftTile == tile_flag_nonsolid || leftTile == tile_flag_gap)))
					onice = true;
				else 
					onice = false;
			}
			
			platform = NULL;

			if(iVerticalPlatformCollision == 0)
				KillObjectMapHazard();
		}
		else if(fSuperDeathTileUnderObject)
		{
			KillObjectMapHazard();
			return;
		}
		else
		{
			yf(fPrecalculatedY);
			vely = CapFallingVelocity(GRAVITATION + vely);
			
			if(!platform)
				inair = true;
		}
	}

	if(!platform && inair)
		onice = false;
}
void PlayerWarpStatus::chooseWarpExit(CPlayer& player)
{
    WarpExit * exit = g_map->getRandomWarpExit(warpconnection, warpid);
    assert(exit);
    player.setXi(exit->x);
    player.setYi(exit->y);
    player.fOldX = player.fx;
    player.fOldY = player.fy;
    player.oldvelx = player.velx;

    player.lockjump = false;
    player.ClearPowerupStates();

    //Trigger block that we warp into
    short iCol = player.leftX() / TILESIZE;
    short iRow = player.topY() / TILESIZE;
    IO_Block* block = NULL;

    assert(exit->direction != WARP_EXIT_UNDEFINED);

    switch(exit->direction) {
        case WARP_EXIT_UP:
            player.state = player_exiting_warp_up;
            player.velx = 0.0f;
            player.vely = -4.0f;
            warpcounter = PH + PHOFFSET;
            warpplane = exit->warpy << 5;

            if (iRow - 1 >= 0) {
                block = g_map->block(iCol, iRow - 1);

                if (block && !block->isTransparent() && !block->isHidden())
                    block->triggerBehavior();
            }
            break;
        case WARP_EXIT_RIGHT:
            player.state = player_exiting_warp_right;
            player.velx = 1.0f;
            player.vely = 1.0f;
            warpcounter = PW + PWOFFSET;
            warpplane = (exit->warpx << 5) + TILESIZE;

            if (iCol + 1 >= 20)
                iCol -= 20;

            block = g_map->block(iCol + 1, iRow);

            if (block && !block->isTransparent() && !block->isHidden())
                block->triggerBehavior();
            break;
        case WARP_EXIT_DOWN:
            player.state = player_exiting_warp_down;
            player.velx = 0.0f;
            player.vely = 1.1f;
            player.inair = true;
            warpcounter = TILESIZE - PHOFFSET;
            warpplane = (exit->warpy << 5) + TILESIZE;

            if (iRow + 1 < 15) {
                block = g_map->block(iCol, iRow + 1);

                if (block && !block->isTransparent() && !block->isHidden())
                    block->triggerBehavior();
            }
            break;
        case WARP_EXIT_LEFT:
            player.state = player_exiting_warp_left;
            player.velx = -1.0f;
            player.vely = 1.0f;
            warpcounter = PW + PWOFFSET;
            warpplane = (exit->warpx << 5);

            if (iCol - 1 < 0)
                iCol += 20;

            block = g_map->block(iCol - 1, iRow);

            if (block && !block->isTransparent() && !block->isHidden())
                block->triggerBehavior();
            break;
        default:
            assert(false);
            break;
    }

    //Make player shielded when exiting the warp (if that option is turned on)
    if (game_values.shieldstyle > 0) {
        if (!player.isShielded() || player.shield.time_left() < game_values.shieldtime) {
            player.shield.reset();
        }
    }

    //Lock the warp (if that option is turned on)
    if (game_values.warplocktime > 0) {
        if (game_values.warplockstyle == 1 || game_values.warplockstyle == 2) //Lock the warp exit
            exit->locktimer = game_values.warplocktime;
    }
}