summaryrefslogtreecommitdiffstats
path: root/src/Items/ItemDoor.h
blob: aec6bc0fe27855bba19521a8a1585dd17c03f7e5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131

#pragma once

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





class cItemDoorHandler:
	public cItemHandler
{
	using Super = cItemHandler;

public:

	cItemDoorHandler(int a_ItemType):
		Super(a_ItemType)
	{

	}




	virtual bool GetBlocksToPlace(
		cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
		const Vector3i a_PlacedBlockPos,
		eBlockFace a_ClickedBlockFace,
		const Vector3i a_CursorPos,
		sSetBlockVector & a_BlocksToSet
	) 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;
		}

		// Door (bottom block) can be placed in Y range of [1, 254]:
		if ((a_PlacedBlockPos.y < 1) || (a_PlacedBlockPos.y >= cChunkDef::Height - 2))
		{
			return false;
		}

		// The door needs a compatible block below it:
		auto BelowPos = a_PlacedBlockPos.addedY(-1);
		if (!cBlockDoorHandler::CanBeOn(a_World.GetBlock(BelowPos), a_World.GetBlockMeta(BelowPos)))
		{
			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:
			{
				ASSERT(!"Unhandled door type");
				return false;
			}
		}

		// Check the two blocks that will get replaced by the door:
		auto UpperBlockPos = a_PlacedBlockPos.addedY(1);
		BLOCKTYPE LowerBlockType = a_World.GetBlock(a_PlacedBlockPos);
		BLOCKTYPE UpperBlockType = a_World.GetBlock(UpperBlockPos);
		if (
			!cBlockDoorHandler::CanReplaceBlock(LowerBlockType) ||
			!cBlockDoorHandler::CanReplaceBlock(UpperBlockType))
		{
			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_PlacedBlockPos);
		Vector3i RightNeighborPos = RelDirToOutside;
		RightNeighborPos.TurnCCW();
		RightNeighborPos.Move(a_PlacedBlockPos);

		// Decide whether the hinge is on the left (default) or on the right:
		NIBBLETYPE UpperBlockMeta = 0x08;
		BLOCKTYPE LeftNeighborBlock = a_World.GetBlock(LeftNeighborPos);
		BLOCKTYPE RightNeighborBlock = a_World.GetBlock(RightNeighborPos);
		/*
		// DEBUG:
		FLOGD("Door being placed at {0}", a_PlacedBlockPos);
		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:
		a_BlocksToSet.emplace_back(a_PlacedBlockPos, BlockType, LowerBlockMeta);
		a_BlocksToSet.emplace_back(UpperBlockPos,    BlockType, UpperBlockMeta);
		return true;
	}




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