summaryrefslogtreecommitdiffstats
path: root/src/Blocks/BlockSlab.h
blob: 566c88c716e32099165a492fc286ba5c6e34fd9d (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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228

// BlockSlab.h

// Declares cBlockSlabHandler and cBlockDoubleSlabHandler classes





#pragma once

#include "BlockHandler.h"
#include "ChunkInterface.h"
#include "../BlockInfo.h"
#include "../Entities/Player.h"
#include "../BlockInfo.h"



class cBlockSlabHandler final :
	public cBlockHandler
{
	using Super = cBlockHandler;

public:

	using Super::Super;

	/** Returns true if the specified blocktype is one of the slabs handled by this handler */
	static bool IsAnySlabType(BLOCKTYPE a_BlockType)
	{
		return (
			(a_BlockType == E_BLOCK_WOODEN_SLAB) ||
			(a_BlockType == E_BLOCK_STONE_SLAB) ||
			(a_BlockType == E_BLOCK_RED_SANDSTONE_SLAB) ||
			(a_BlockType == E_BLOCK_PURPUR_SLAB)
		);
	}

private:

	virtual cItems ConvertToPickups(const NIBBLETYPE a_BlockMeta, const cItem * const a_Tool) const override
	{
		// Reset the "top half" flag:
		return cItem(m_BlockType, 1, a_BlockMeta & 0x07);
	}


	virtual bool DoesIgnoreBuildCollision(const cWorld & a_World, const cItem & a_HeldItem, const Vector3i a_Position, const NIBBLETYPE a_Meta, const eBlockFace a_ClickedBlockFace, const bool a_ClickedDirectly) const override
	{
		/* Double slab combining uses build collision checks to replace single slabs with double slabs in the right conditions.
		For us to be replaced, the player must be:
		1. Placing the same slab material.
		2. Placing the same slab sub-kind (and existing slab is single). */
		if ((m_BlockType != a_HeldItem.m_ItemType) || ((a_Meta & 0x07) != a_HeldItem.m_ItemDamage))
		{
			return false;
		}

		const bool IsTopSlab = (a_Meta & 0x08) == 0x08;
		const auto CanClickCombine = ((a_ClickedBlockFace == BLOCK_FACE_TOP) && !IsTopSlab) || ((a_ClickedBlockFace == BLOCK_FACE_BOTTOM) && IsTopSlab);

		/* When the player clicks on us directly, we'll combine if we're
		a bottom slab and he clicked the top, or vice versa. Clicking on the sides will not combine.
		However, when indirectly clicked (on the side of another block, that caused placement to go to us)
		the conditions are exactly the opposite. */
		return a_ClickedDirectly ? CanClickCombine : !CanClickCombine;
	}





	virtual void OnCancelRightClick(
		cChunkInterface & a_ChunkInterface,
		cWorldInterface & a_WorldInterface,
		cPlayer & a_Player,
		const Vector3i a_BlockPos,
		eBlockFace a_BlockFace
	) const override
	{
		if ((a_BlockFace == BLOCK_FACE_NONE) || (a_Player.GetEquippedItem().m_ItemType != static_cast<short>(m_BlockType)))
		{
			return;
		}

		// Sends the slab back to the client. It's to refuse a doubleslab placement. */
		a_Player.GetWorld()->SendBlockTo(a_BlockPos, a_Player);
	}





	virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) const override
	{
		// Toggle the 4th bit - up / down:
		return (a_Meta ^ 0x08);
	}





	virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) const override
	{
		a_Meta &= 0x7;

		switch (m_BlockType)
		{
			case E_BLOCK_STONE_SLAB:
			{
				switch (a_Meta)
				{
					case E_META_STONE_SLAB_SANDSTONE: return 2;
					case E_META_STONE_SLAB_PLANKS: return 13;
					case E_META_STONE_SLAB_STONE_BRICK:
					case E_META_STONE_SLAB_STONE:
					case E_META_STONE_SLAB_COBBLESTONE: return 11;
					case E_META_STONE_SLAB_BRICK: return 28;
					case E_META_STONE_SLAB_NETHER_BRICK: return 35;
					case E_META_STONE_SLAB_QUARTZ: return 8;
					default:
					{
						ASSERT(!"Unhandled meta in slab handler!");
						return 0;
					}
				}
			}
			case E_BLOCK_WOODEN_SLAB:
			{
				switch (a_Meta)
				{
					case E_META_WOODEN_SLAB_BIRCH: return 2;
					case E_META_WOODEN_SLAB_JUNGLE: return 10;
					case E_META_WOODEN_SLAB_OAK: return 13;
					case E_META_WOODEN_SLAB_ACACIA: return 15;
					case E_META_WOODEN_SLAB_DARK_OAK: return 26;
					case E_META_WOODEN_SLAB_SPRUCE: return 34;
					default:
					{
						ASSERT(!"Unhandled meta in slab handler!");
						return 0;
					}
				}
			}
			case E_BLOCK_RED_SANDSTONE_SLAB:
			{
				return 10;
			}
			case E_BLOCK_PURPUR_SLAB:
			{
				return 16;
			}
			default:
			{
				ASSERT(!"Unhandled blocktype in slab handler!");
				return 0;
			}
		}
	}





	virtual bool IsInsideBlock(Vector3d a_Position, const NIBBLETYPE a_BlockMeta) const override
	{
		if (a_BlockMeta & 0x08)  // top half
		{
			return true;
		}
		return cBlockHandler::IsInsideBlock(a_Position, a_BlockMeta);
	}
} ;





class cBlockDoubleSlabHandler final :
	public cBlockHandler
{
	using Super = cBlockHandler;

public:

	using Super::Super;

private:

	virtual cItems ConvertToPickups(const NIBBLETYPE a_BlockMeta, const cItem * const a_Tool) const override
	{
		BLOCKTYPE Block = GetSingleSlabType(m_BlockType);
		return cItem(Block, 2, a_BlockMeta & 0x7);
	}





	inline static BLOCKTYPE GetSingleSlabType(BLOCKTYPE a_BlockType)
	{
		switch (a_BlockType)
		{
			case E_BLOCK_DOUBLE_STONE_SLAB:         return E_BLOCK_STONE_SLAB;
			case E_BLOCK_DOUBLE_WOODEN_SLAB:        return E_BLOCK_WOODEN_SLAB;
			case E_BLOCK_DOUBLE_RED_SANDSTONE_SLAB: return E_BLOCK_RED_SANDSTONE_SLAB;
			case E_BLOCK_PURPUR_DOUBLE_SLAB:        return E_BLOCK_PURPUR_SLAB;
		}
		ASSERT(!"Unhandled double slab type!");
		return a_BlockType;
	}





	virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) const override
	{
		// For doule slabs, the meta values are the same. Only the meaning of the 4th bit changes, but that's ignored in the below handler
		return cBlockHandler::For(GetSingleSlabType(m_BlockType)).GetMapBaseColourID(a_Meta);
	}
} ;