summaryrefslogblamecommitdiffstats
path: root/src/Items/ItemDoor.h
blob: 555aa3980890e4c97be8d0685ec9a823ed50cf84 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11




                        
                                




 
                                                  
 

                                   

                                                    
                                 
         

         
 

 






                                                    
         
                                                                                                                 
                                                         


                                     
 

                                                           

                                   




                                                                                          
                                                                                            

                                                                                          
                 
 



                                                                          
                 



                                                                                     







                                                                                  


                                             


                                                            
                                                                                                

                                                                                                            
                                         
                                                      
                                                            
                                           
                                                       


                                                                                     


                                                                                

                         
                                                                   
                                                               


                                                                                                                 
                  
 




                                                                                                                      
                 
                                                                      



                                                                               
                                            

                                                                                                                       


         

 

                                                                      

#pragma once

#include "ItemHandler.h"
#include "../World.h"
#include "../Blocks/BlockDoor.h"





class cItemDoorHandler final : public cItemHandler
{
	using Super = cItemHandler;

  public:
	constexpr cItemDoorHandler(int a_ItemType) :
		Super(a_ItemType)
	{
	}




	virtual bool CommitPlacement(
		cPlayer & a_Player,
		const cItem & a_HeldItem,
		const Vector3i a_PlacePosition,
		const eBlockFace a_ClickedBlockFace,
		const Vector3i a_CursorPosition
	) const override
	{
		// Vanilla only allows door placement while clicking on the top face of the block below the door:
		if (a_ClickedBlockFace != BLOCK_FACE_TOP)
		{
			return false;
		}

		// Get the block type of the door to place:
		BLOCKTYPE BlockType;
		switch (m_ItemType)
		{
			case E_ITEM_WOODEN_DOOR:   BlockType = E_BLOCK_OAK_DOOR; break;
			case E_ITEM_IRON_DOOR:     BlockType = E_BLOCK_IRON_DOOR; break;
			case E_ITEM_SPRUCE_DOOR:   BlockType = E_BLOCK_SPRUCE_DOOR; break;
			case E_ITEM_BIRCH_DOOR:    BlockType = E_BLOCK_BIRCH_DOOR; break;
			case E_ITEM_JUNGLE_DOOR:   BlockType = E_BLOCK_JUNGLE_DOOR; break;
			case E_ITEM_DARK_OAK_DOOR: BlockType = E_BLOCK_DARK_OAK_DOOR; break;
			case E_ITEM_ACACIA_DOOR:   BlockType = E_BLOCK_ACACIA_DOOR; break;
			default:                   UNREACHABLE("Unhandled door type");
		}

		const auto & World = *a_Player.GetWorld();
		const auto UpperBlockPosition = a_PlacePosition.addedY(1);

		// Check the block that will get replaced by the door:
		{
			BLOCKTYPE TopType;
			NIBBLETYPE TopMeta;
			World.GetBlockTypeMeta(UpperBlockPosition, TopType, TopMeta);

			if (!cBlockHandler::For(TopType).DoesIgnoreBuildCollision(
					World,
					a_HeldItem,
					UpperBlockPosition,
					TopMeta,
					a_ClickedBlockFace,
					false
				))
			{
				return false;
			}
		}

		// Get the coords of the neighboring blocks:
		NIBBLETYPE LowerBlockMeta = cBlockDoorHandler::YawToMetaData(a_Player.GetYaw());
		Vector3i RelDirToOutside = cBlockDoorHandler::GetRelativeDirectionToOutside(LowerBlockMeta);
		Vector3i LeftNeighborPos = RelDirToOutside;
		LeftNeighborPos.TurnCW();
		LeftNeighborPos.Move(a_PlacePosition);
		Vector3i RightNeighborPos = RelDirToOutside;
		RightNeighborPos.TurnCCW();
		RightNeighborPos.Move(a_PlacePosition);

		// Decide whether the hinge is on the left (default) or on the right:
		NIBBLETYPE UpperBlockMeta = 0x08;
		BLOCKTYPE LeftNeighborBlock = World.GetBlock(LeftNeighborPos);
		BLOCKTYPE RightNeighborBlock = World.GetBlock(RightNeighborPos);

		/*
		// DEBUG:
		FLOGD("Door being placed at {0}", a_PlacePosition);
		FLOGD("RelDirToOutside: {0}", RelDirToOutside);
		FLOGD("Left neighbor at {0}: {1} ({2})", LeftNeighborPos, LeftNeighborBlock,
		ItemTypeToString(LeftNeighborBlock)); FLOGD("Right neighbor at {0}: {1} ({2})", RightNeighborPos,
		RightNeighborBlock, ItemTypeToString(RightNeighborBlock));
		*/

		if (cBlockDoorHandler::IsDoorBlockType(LeftNeighborBlock) ||  // The block to the left is a door block
			(!cBlockInfo::IsSolid(LeftNeighborBlock) &&  // Prioritize hinge on the left side
			 cBlockInfo::IsSolid(RightNeighborBlock) &&  // The block to the right is solid...
			 !cBlockDoorHandler::IsDoorBlockType(RightNeighborBlock)  // ... but not a door
			))
		{
			// DEBUG: LOGD("Setting hinge to right side");
			UpperBlockMeta = 0x09;  // Upper block | hinge on right
		}

		// Set the blocks:
		return a_Player.PlaceBlocks(
			{{a_PlacePosition, BlockType, LowerBlockMeta}, {UpperBlockPosition, BlockType, UpperBlockMeta}}
		);
	}




	virtual bool IsPlaceable(void) const override { return true; }
};