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 
6 
7 
8 
9 
11  public cItemHandler
12 {
14 
15 public:
17  super(E_BLOCK_PUMPKIN)
18  {
19  }
20 
21 
22  virtual bool OnPlayerPlace(
23  cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem,
24  int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
25  int a_CursorX, int a_CursorY, int a_CursorZ
26  ) override
27  {
28  // First try spawning a snow golem or an iron golem:
29  int PlacedBlockX = a_BlockX;
30  int PlacedBlockY = a_BlockY;
31  int PlacedBlockZ = a_BlockZ;
32  AddFaceDirection(PlacedBlockX, PlacedBlockY, PlacedBlockZ, a_BlockFace);
33  if (TrySpawnGolem(a_World, a_Player, PlacedBlockX, PlacedBlockY, PlacedBlockZ))
34  {
35  // The client thinks that they placed the pumpkin, let them know it's been replaced:
36  a_Player.SendBlocksAround(PlacedBlockX, PlacedBlockY, PlacedBlockZ);
37  return true;
38  }
39 
40  // No golem at these coords, place the block normally:
41  return super::OnPlayerPlace(a_World, a_Player, a_EquippedItem, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ);
42  }
43 
44 
47  bool TrySpawnGolem(cWorld & a_World, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ)
48  {
49  // A golem can't form with a pumpkin below level 2 or above level 255
50  if ((a_BlockY < 2) || (a_BlockY >= cChunkDef::Height))
51  {
52  return false;
53  }
54 
55  // Decide which golem to try spawning based on the block below the placed pumpkin:
56  switch (a_World.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ))
57  {
58  case E_BLOCK_SNOW_BLOCK: return TrySpawnSnowGolem(a_World, a_Player, a_BlockX, a_BlockY, a_BlockZ);
59  case E_BLOCK_IRON_BLOCK: return TrySpawnIronGolem(a_World, a_Player, a_BlockX, a_BlockY, a_BlockZ);
60  default:
61  {
62  // No golem here
63  return false;
64  }
65  }
66  }
67 
68 
72  bool TrySpawnSnowGolem(cWorld & a_World, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ)
73  {
74  // Need one more snow block 2 blocks below the pumpkin:
75  if (a_World.GetBlock(a_BlockX, a_BlockY - 2, a_BlockZ) != E_BLOCK_SNOW_BLOCK)
76  {
77  return false;
78  }
79 
80  // Try to place air blocks where the original recipe blocks were:
81  sSetBlockVector AirBlocks;
82  AirBlocks.emplace_back(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); // Head
83  AirBlocks.emplace_back(a_BlockX, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0); // Torso
84  AirBlocks.emplace_back(a_BlockX, a_BlockY - 2, a_BlockZ, E_BLOCK_AIR, 0); // Legs
85  if (!a_Player.PlaceBlocks(AirBlocks))
86  {
87  return false;
88  }
89 
90  // Spawn the golem:
91  a_World.SpawnMob(static_cast<double>(a_BlockX) + 0.5, a_BlockY - 2, static_cast<double>(a_BlockZ) + 0.5, mtSnowGolem, false);
92  return true;
93  }
94 
95 
99  bool TrySpawnIronGolem(cWorld & a_World, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ)
100  {
101  // Need one more iron block 2 blocks below the pumpkin:
102  if (a_World.GetBlock(a_BlockX, a_BlockY - 2, a_BlockZ) != E_BLOCK_IRON_BLOCK)
103  {
104  return false;
105  }
106 
107  // Check the two arm directions (X, Z) using a loop over two sets of offset vectors:
108  static const Vector3i ArmOffsets[] =
109  {
110  {1, 0, 0},
111  {0, 0, 1},
112  };
113  for (size_t i = 0; i < ARRAYCOUNT(ArmOffsets); i++)
114  {
115  // If the arm blocks don't match, bail out of this loop repetition:
116  if (
117  (a_World.GetBlock(a_BlockX + ArmOffsets[i].x, a_BlockY - 1, a_BlockZ + ArmOffsets[i].z) != E_BLOCK_IRON_BLOCK) ||
118  (a_World.GetBlock(a_BlockX - ArmOffsets[i].x, a_BlockY - 1, a_BlockZ - ArmOffsets[i].z) != E_BLOCK_IRON_BLOCK)
119  )
120  {
121  continue;
122  }
123 
124  // Try to place air blocks where the original recipe blocks were:
125  sSetBlockVector AirBlocks;
126  AirBlocks.emplace_back(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); // Head
127  AirBlocks.emplace_back(a_BlockX, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0); // Torso
128  AirBlocks.emplace_back(a_BlockX, a_BlockY - 2, a_BlockZ, E_BLOCK_AIR, 0); // Legs
129  AirBlocks.emplace_back(a_BlockX + ArmOffsets[i].x, a_BlockY - 1, a_BlockZ + ArmOffsets[i].z, E_BLOCK_AIR, 0); // Arm
130  AirBlocks.emplace_back(a_BlockX - ArmOffsets[i].x, a_BlockY - 1, a_BlockZ - ArmOffsets[i].z, E_BLOCK_AIR, 0); // Arm
131  if (!a_Player.PlaceBlocks(AirBlocks))
132  {
133  return false;
134  }
135 
136  // Spawn the golem:
137  a_World.SpawnMob(static_cast<double>(a_BlockX) + 0.5, a_BlockY - 2, static_cast<double>(a_BlockZ) + 0.5, mtIronGolem, false);
138  return true;
139  } // for i - ArmOffsets[]
140 
141  // Neither arm offset matched, this thing is not a complete golem
142  return false;
143  }
144 };
virtual UInt32 SpawnMob(double a_PosX, double a_PosY, double a_PosZ, eMonsterType a_MonsterType, bool a_Baby=false) override
Spawns a mob of the specified type.
Definition: World.cpp:3190
BLOCKTYPE GetBlock(Vector3i a_BlockPos)
Returns the block type at the specified position.
Definition: World.h:416
T x
Definition: Vector3.h:17
void SendBlocksAround(int a_BlockX, int a_BlockY, int a_BlockZ, 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:2681
Definition: Player.h:27
bool TrySpawnIronGolem(cWorld &a_World, cPlayer &a_Player, int a_BlockX, int a_BlockY, int a_BlockZ)
Spawns an iron golem if the shape matches the recipe, supposing that the block placed at the specifie...
Definition: ItemPumpkin.h:99
T z
Definition: Vector3.h:17
static const int Height
Definition: ChunkDef.h:135
bool PlaceBlocks(const sSetBlockVector &a_Blocks)
Calls the block placement hooks and places the blocks in the world.
Definition: Player.cpp:2788
void AddFaceDirection(int &a_BlockX, int &a_BlockY, int &a_BlockZ, eBlockFace a_BlockFace, bool a_bInverse=false)
Definition: Defines.h:859
Definition: World.h:65
virtual bool OnPlayerPlace(cWorld &a_World, cPlayer &a_Player, const cItem &a_EquippedItem, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override
Called when the player tries to place the item (right mouse button, IsPlaceable() == true)...
Definition: ItemPumpkin.h:22
bool TrySpawnSnowGolem(cWorld &a_World, cPlayer &a_Player, int a_BlockX, int a_BlockY, int a_BlockZ)
Spawns a snow golem if the shape matches the recipe, supposing that the block placed at the specified...
Definition: ItemPumpkin.h:72
virtual bool OnPlayerPlace(cWorld &a_World, cPlayer &a_Player, const cItem &a_EquippedItem, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ)
Called when the player tries to place the item (right mouse button, IsPlaceable() == true)...
eBlockFace
Block face constants, used in PlayerDigging and PlayerBlockPlacement packets and bbox collision calc...
Definition: Defines.h:29
bool TrySpawnGolem(cWorld &a_World, cPlayer &a_Player, int a_BlockX, int a_BlockY, int a_BlockZ)
Spawns a snow / iron golem if the shape matches the recipe, supposing that the block placed at the sp...
Definition: ItemPumpkin.h:47
cItemHandler super
Definition: ItemPumpkin.h:13
#define ARRAYCOUNT(X)
Evaluates to the number of elements in an array (compile-time!)
Definition: Globals.h:290
Definition: Item.h:36
std::vector< sSetBlock > sSetBlockVector
Definition: ChunkDef.h:564