Cuberite
A lightweight, fast and extensible game server for Minecraft
ItemPumpkin.h
Go to the documentation of this file.
1 
2 #pragma once
3 
4 #include "ItemHandler.h"
5 #include "Blocks/BlockPumpkin.h"
6 
7 
8 
9 
10 
11 class cItemPumpkinHandler final:
12  public cItemHandler
13 {
15 
16 public:
17 
18  using Super::Super;
19 
20 private:
21 
22  virtual bool CommitPlacement(cPlayer & a_Player, const cItem & a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) const override
23  {
24  // First try spawning a snow golem or an iron golem:
25  if (TrySpawnGolem(a_Player, a_PlacePosition))
26  {
27  // The client thinks that they placed the pumpkin, let them know it's been replaced:
28  a_Player.SendBlocksAround(a_PlacePosition);
29  return true;
30  }
31 
32  // No golem at these coords, place the block normally:
33  return a_Player.PlaceBlock(a_PlacePosition, E_BLOCK_PUMPKIN, cBlockPumpkinHandler::YawToMetaData(a_Player.GetYaw()));
34  }
35 
36 
37 
38 
39 
42  bool TrySpawnGolem(cPlayer & a_Player, const Vector3i a_PumpkinPos) const
43  {
44  // A golem can't form with a pumpkin below level 2 or above level 255:
45  if ((a_PumpkinPos.y < 2) || (a_PumpkinPos.y >= cChunkDef::Height))
46  {
47  return false;
48  }
49 
50  auto & World = *a_Player.GetWorld();
51 
52  // Decide which golem to try spawning based on the block below the placed pumpkin:
53  switch (World.GetBlock(a_PumpkinPos.addedY(-1)))
54  {
55  case E_BLOCK_SNOW_BLOCK: return TrySpawnSnowGolem(World, a_Player, a_PumpkinPos);
56  case E_BLOCK_IRON_BLOCK: return TrySpawnIronGolem(World, a_Player, a_PumpkinPos);
57  default:
58  {
59  // No golem here:
60  return false;
61  }
62  }
63  }
64 
65 
66 
67 
68 
72  bool TrySpawnSnowGolem(cWorld & a_World, cPlayer & a_Player, const Vector3i a_PumpkinPos) const
73  {
74  ASSERT(a_PumpkinPos.y > 1);
75  ASSERT(a_World.GetBlock(a_PumpkinPos.addedY(-1)) == E_BLOCK_SNOW_BLOCK);
76 
77  // Need one more snow block 2 blocks below the pumpkin:
78  if (a_World.GetBlock(a_PumpkinPos.addedY(-2)) != E_BLOCK_SNOW_BLOCK)
79  {
80  return false;
81  }
82 
83  // Try to place air blocks where the original recipe blocks were:
84  if (
85  !a_Player.PlaceBlocks(
86  {
87  { a_PumpkinPos, E_BLOCK_AIR, 0 }, // Head
88  { a_PumpkinPos.addedY(-1), E_BLOCK_AIR, 0 }, // Torso
89  { a_PumpkinPos.addedY(-2), E_BLOCK_AIR, 0 } // Legs
90  })
91  )
92  {
93  return false;
94  }
95 
96  // Spawn the golem:
97  auto GolemPos = Vector3d(a_PumpkinPos) + Vector3d(0.5, -2, 0.5);
98  a_World.SpawnMob(GolemPos.x, GolemPos.y, GolemPos.z, mtSnowGolem, false);
99  return true;
100  }
101 
102 
103 
104 
105 
109  bool TrySpawnIronGolem(cWorld & a_World, cPlayer & a_Player, const Vector3i a_PumpkinPos) const
110  {
111  ASSERT(a_PumpkinPos.y > 1);
112  ASSERT(a_World.GetBlock(a_PumpkinPos.addedY(-1)) == E_BLOCK_IRON_BLOCK);
113 
114  // Need one more iron block 2 blocks below the pumpkin:
115  if (a_World.GetBlock(a_PumpkinPos.addedY(-2)) != E_BLOCK_IRON_BLOCK)
116  {
117  return false;
118  }
119 
120  // Check the two arm directions (X, Z) using a loop over two sets of offset vectors:
121  auto BodyPos = a_PumpkinPos.addedY(-1);
122  static const Vector3i ArmOffsets[] =
123  {
124  {1, 0, 0},
125  {0, 0, 1},
126  };
127  for (size_t i = 0; i < ARRAYCOUNT(ArmOffsets); i++)
128  {
129  // If the arm blocks don't match, bail out of this loop repetition:
130  if (
131  (a_World.GetBlock(BodyPos + ArmOffsets[i]) != E_BLOCK_IRON_BLOCK) ||
132  (a_World.GetBlock(BodyPos - ArmOffsets[i]) != E_BLOCK_IRON_BLOCK)
133  )
134  {
135  continue;
136  }
137 
138  // Try to place air blocks where the original recipe blocks were:
139  if (
140  !a_Player.PlaceBlocks(
141  {
142  { a_PumpkinPos, E_BLOCK_AIR, 0 }, // Head
143  { BodyPos, E_BLOCK_AIR, 0 }, // Torso
144  { BodyPos.addedY(-1), E_BLOCK_AIR, 0 }, // Legs
145  { BodyPos + ArmOffsets[i], E_BLOCK_AIR, 0 }, // Arm
146  { BodyPos - ArmOffsets[i], E_BLOCK_AIR, 0 } // Arm
147  })
148  )
149  {
150  return false;
151  }
152 
153  // Spawn the golem:
154  auto GolemPos = Vector3d(a_PumpkinPos) + Vector3d(0.5, -2, 0.5);
155  a_World.SpawnMob(GolemPos.x, GolemPos.y, GolemPos.z, mtIronGolem, false);
156  return true;
157  } // for i - ArmOffsets[]
158 
159  // Neither arm offset matched, this thing is not a complete golem
160  return false;
161  }
162 };
@ E_BLOCK_AIR
Definition: BlockType.h:10
@ E_BLOCK_IRON_BLOCK
Definition: BlockType.h:52
@ E_BLOCK_SNOW_BLOCK
Definition: BlockType.h:94
@ E_BLOCK_PUMPKIN
Definition: BlockType.h:101
eBlockFace
Block face constants, used in PlayerDigging and PlayerBlockPlacement packets and bbox collision calc.
Definition: Defines.h:38
#define ARRAYCOUNT(X)
Evaluates to the number of elements in an array (compile-time!)
Definition: Globals.h:231
#define ASSERT(x)
Definition: Globals.h:276
@ mtSnowGolem
Definition: MonsterTypes.h:62
@ mtIronGolem
Definition: MonsterTypes.h:38
Vector3< double > Vector3d
Definition: Vector3.h:485
Utilities to allow casting a cWorld to one of its interfaces without including World....
Definition: OpaqueWorld.h:13
static NIBBLETYPE YawToMetaData(double a_Rotation)
Converts the rotation value as returned by cPlayer::GetYaw() to the appropriate metadata value for a ...
Definition: Mixins.h:172
static const int Height
Definition: ChunkDef.h:125
double GetYaw(void) const
Definition: Entity.h:198
cWorld * GetWorld(void) const
Definition: Entity.h:190
Definition: Player.h:29
bool PlaceBlocks(std::initializer_list< sSetBlock > a_Blocks)
Calls the block placement hooks and places the blocks in the world.
Definition: Player.cpp:2449
void SendBlocksAround(Vector3i a_BlockPos, int a_Range=1)
Sends the block in the specified range around the specified coord to the client as a block change pac...
Definition: Player.cpp:2325
bool PlaceBlock(Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
Attempts to place the block in the world with a call to PlaceBlocks.
Definition: Player.cpp:2440
Definition: Item.h:37
constexpr cItemHandler(int a_ItemType)
Definition: ItemHandler.h:37
bool TrySpawnGolem(cPlayer &a_Player, const Vector3i a_PumpkinPos) const
Spawns a snow / iron golem if the shape matches the recipe, supposing that the block placed at the sp...
Definition: ItemPumpkin.h:42
bool TrySpawnIronGolem(cWorld &a_World, cPlayer &a_Player, const Vector3i a_PumpkinPos) const
Spawns an iron golem if the shape matches the recipe, supposing that the block placed at the specifie...
Definition: ItemPumpkin.h:109
virtual bool CommitPlacement(cPlayer &a_Player, const cItem &a_HeldItem, const Vector3i a_PlacePosition, const eBlockFace a_ClickedBlockFace, const Vector3i a_CursorPosition) const override
Performs the actual placement of this placeable item.
Definition: ItemPumpkin.h:22
bool TrySpawnSnowGolem(cWorld &a_World, cPlayer &a_Player, const Vector3i a_PumpkinPos) const
Spawns a snow golem if the shape matches the recipe, supposing that the block placed at the specified...
Definition: ItemPumpkin.h:72
Vector3< T > addedY(T a_AddY) const
Returns a copy of this vector moved by the specified amount on the y axis.
Definition: Vector3.h:314
T y
Definition: Vector3.h:17
Definition: World.h:53
BLOCKTYPE GetBlock(Vector3i a_BlockPos) const
Returns the block type at the specified position.
Definition: World.h:363