summaryrefslogtreecommitdiffstats
path: root/src/Entities/Minecart.h
blob: bf3c74da5529008c284f7b7fab67610d915e208f (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
229
230
231
232
233
234
235
236
237
238
239
240
241
242

// Minecart.h

// Declares the cMinecart class representing a minecart in the world





#pragma once

#include "Entity.h"
#include "../World.h"
#include "../UI/WindowOwner.h"





class cMinecart : public cEntity
{
	using Super = cEntity;

  public:
	CLASS_PROTODEF(cMinecart)

	/** Minecart payload, values correspond to packet subtype */
	enum ePayload
	{
		mpNone = 0,  // Empty minecart, ridable by player or mobs
		mpChest = 1,  // Minecart-with-chest, can store a grid of 3 * 8 items
		mpFurnace = 2,  // Minecart-with-furnace, can be powered
		mpTNT = 3,  // Minecart-with-TNT, can be blown up with activator rail
		mpHopper = 5,  // Minecart-with-hopper, can be hopper
		// TODO: Spawner minecarts, (and possibly any block in a minecart with NBT editing)
	};

	// cEntity overrides:
	virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
	virtual void HandlePhysics(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
	virtual bool DoTakeDamage(TakeDamageInfo & TDI) override;
	virtual void KilledBy(TakeDamageInfo & a_TDI) override;
	virtual void OnRemoveFromWorld(cWorld & a_World) override;
	virtual void HandleSpeedFromAttachee(float a_Forward, float a_Sideways) override;
	int LastDamage(void) const { return m_LastDamage; }
	ePayload GetPayload(void) const { return m_Payload; }

  protected:
	ePayload m_Payload;
	int m_LastDamage;
	Vector3i m_DetectorRailPosition;
	bool m_bIsOnDetectorRail;

	/** Applies an acceleration to the minecart parallel to a_ForwardDirection but without allowing backward speed. */
	void ApplyAcceleration(Vector3d a_ForwardDirection, double a_Acceleration);

	cMinecart(ePayload a_Payload, Vector3d a_Pos);

	/** Handles physics on normal rails
	For each tick, slow down on flat rails, speed up or slow down on ascending / descending rails (depending on
	direction), and turn on curved rails. */
	void HandleRailPhysics(NIBBLETYPE a_RailMeta, std::chrono::milliseconds a_Dt);

	/** Handles powered rail physics
		Each tick, speed up or slow down cart, depending on metadata of rail (powered or not)
	*/
	void HandlePoweredRailPhysics(NIBBLETYPE a_RailMeta);

	/** Handles detector rail activation
		Activates detector rails when a minecart is on them. Calls HandleRailPhysics() for physics simulations
	*/
	void HandleDetectorRailPhysics(NIBBLETYPE a_RailMeta, std::chrono::milliseconds a_Dt);

	/** Handles activator rails */
	virtual void HandleActivatorRailPhysics(NIBBLETYPE a_RailMeta, std::chrono::milliseconds a_Dt);

	/** Snaps a mincecart to a rail's axis, resetting its speed
		For curved rails, it changes the cart's direction as well as snapping it to axis */
	void SnapToRail(NIBBLETYPE a_RailMeta);
	/** Tests if a solid block is in front of a cart, and stops the cart (and returns true) if so; returns false if no
	 * obstruction */
	bool TestBlockCollision(NIBBLETYPE a_RailMeta);
	/** Tests if there is a block at the specified position which is impassable to minecarts */
	bool IsSolidBlockAtPosition(Vector3i a_Offset);
	/** Tests if a solid block is at a specific offset of the minecart position */
	bool IsSolidBlockAtOffset(int a_XOffset, int a_YOffset, int a_ZOffset);

	bool IsBlockCollisionAtOffset(Vector3i a_Offset);

	/** Tests if this mincecart's bounding box is intersecting another entity's bounding box (collision) and pushes
	 * mincecart away if necessary */
	bool TestEntityCollision(NIBBLETYPE a_RailMeta);
};





class cRideableMinecart final : public cMinecart
{
	using Super = cMinecart;

  public:
	CLASS_PROTODEF(cRideableMinecart)

	cRideableMinecart(Vector3d a_Pos, const cItem & a_Content, int a_ContentHeight);

	const cItem & GetContent(void) const { return m_Content; }
	int GetBlockHeight(void) const { return m_ContentHeight; }

	// cEntity overrides:
	virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override;
	virtual void OnRightClicked(cPlayer & a_Player) override;

  protected:
	cItem m_Content;
	int m_ContentHeight;
};





class cMinecartWithChest final : public cMinecart,
								 public cItemGrid::cListener,
								 public cEntityWindowOwner
{
	using Super = cMinecart;

  public:
	CLASS_PROTODEF(cMinecartWithChest)

	cMinecartWithChest(Vector3d a_Pos);

	enum
	{
		ContentsHeight = 3,
		ContentsWidth = 9,
	};

	const cItem & GetSlot(int a_Idx) const { return m_Contents.GetSlot(a_Idx); }
	void SetSlot(int a_Idx, const cItem & a_Item) { m_Contents.SetSlot(a_Idx, a_Item); }


  protected:
	cItemGrid m_Contents;
	void OpenNewWindow(void);

	// cItemGrid::cListener overrides:
	virtual void OnSlotChanged(cItemGrid * a_Grid, int a_SlotNum) override
	{
		UNUSED(a_SlotNum);
		ASSERT(a_Grid == &m_Contents);
		if (m_World != nullptr)
		{
			if (GetWindow() != nullptr)
			{
				GetWindow()->BroadcastWholeWindow();
			}

			m_World->MarkChunkDirty(GetChunkX(), GetChunkZ());
		}
	}

	// cEntity overrides:
	virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override;
	virtual void OnRemoveFromWorld(cWorld & a_World) override;
	virtual void OnRightClicked(cPlayer & a_Player) override;
};





class cMinecartWithFurnace final : public cMinecart
{
	using Super = cMinecart;

  public:
	CLASS_PROTODEF(cMinecartWithFurnace)

	cMinecartWithFurnace(Vector3d a_Pos);

	// cEntity overrides:
	virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override;
	virtual void OnRightClicked(cPlayer & a_Player) override;
	virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;

	// Set functions.
	void SetIsFueled(bool a_IsFueled, int a_FueledTimeLeft = -1)
	{
		m_IsFueled = a_IsFueled;
		m_FueledTimeLeft = a_FueledTimeLeft;
	}

	// Get functions.
	int GetFueledTimeLeft(void) const { return m_FueledTimeLeft; }
	bool IsFueled(void) const { return m_IsFueled; }

  private:
	int m_FueledTimeLeft;
	bool m_IsFueled;
};





class cMinecartWithTNT final : public cMinecart
{
	using Super = cMinecart;

  public:
	CLASS_PROTODEF(cMinecartWithTNT)

	cMinecartWithTNT(Vector3d a_Pos);
	void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;

  private:
	int m_TNTFuseTicksLeft;
	bool m_isTNTFused = false;

	virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override;
	void HandleActivatorRailPhysics(NIBBLETYPE a_RailMeta, std::chrono::milliseconds a_Dt) override;
};





class cMinecartWithHopper final : public cMinecart
{
	using Super = cMinecart;

  public:
	CLASS_PROTODEF(cMinecartWithHopper)

	cMinecartWithHopper(Vector3d a_Pos);

  private:
	virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override;
};