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
|
#pragma once
#include "RedstoneHandler.h"
#include "../../BoundingBox.h"
#include "../../Entities/Pickup.h"
class cPressurePlateHandler final : public cRedstoneHandler
{
virtual unsigned char GetPowerDeliveredToPosition(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, Vector3i a_QueryPosition, BLOCKTYPE a_QueryBlockType, bool IsLinked) const override
{
UNUSED(a_BlockType);
UNUSED(a_QueryPosition);
UNUSED(a_QueryBlockType);
// Plates only link power blocks below
// Retrieve and return the cached power calculated by Update for performance:
return (IsLinked && (a_QueryPosition != (a_Position + OffsetYM))) ? 0 : DataForChunk(a_Chunk).GetCachedPowerData(a_Position).PowerLevel;
}
static unsigned char GetPowerLevel(const cChunk & Chunk, const Vector3i Position, const BLOCKTYPE BlockType)
{
unsigned NumberOfEntities = 0;
bool FoundPlayer = false;
Chunk.ForEachEntityInBox(cBoundingBox(Vector3d(0.5, 0, 0.5) + Position, 0.5, 0.5), [&](cEntity & Entity)
{
if (Entity.IsPlayer())
{
FoundPlayer = true;
}
if (Entity.IsPickup())
{
NumberOfEntities += static_cast<cPickup &>(Entity).GetItem().m_ItemCount;
return false;
}
NumberOfEntities++;
return false;
});
switch (BlockType)
{
case E_BLOCK_STONE_PRESSURE_PLATE:
{
return (FoundPlayer ? 15 : 0);
}
case E_BLOCK_WOODEN_PRESSURE_PLATE:
{
return (NumberOfEntities != 0 ? 15 : 0);
}
case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE:
{
return std::min(static_cast<unsigned char>(CeilC(NumberOfEntities / 10.f)), static_cast<unsigned char>(15));
}
case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE:
{
return std::min(static_cast<unsigned char>(NumberOfEntities), static_cast<unsigned char>(15));
}
default:
{
ASSERT(!"Unhandled/unimplemented block in pressure plate handler!");
return 0;
}
}
}
virtual void Update(cChunk & a_Chunk, cChunk & CurrentlyTicking, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override
{
// LOGD("Evaluating clicky the pressure plate (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
auto & ChunkData = DataForChunk(a_Chunk);
const auto PreviousPower = ChunkData.GetCachedPowerData(a_Position);
const auto Absolute = cChunkDef::RelativeToAbsolute(a_Position, a_Chunk.GetPos());
const auto Power = GetPowerLevel(a_Chunk, Absolute, a_BlockType); // Get the current power of the platey
const auto DelayInfo = ChunkData.GetMechanismDelayInfo(a_Position);
// Resting state?
if (DelayInfo == nullptr)
{
if (Power == 0)
{
// Nothing happened, back to rest
return;
}
// From rest, a player stepped on us
// Schedule a minimum 0.5 second delay before even thinking about releasing
ChunkData.m_MechanismDelays[a_Position] = std::make_pair(5, true);
a_Chunk.GetWorld()->BroadcastSoundEffect(GetClickOnSound(a_BlockType), Absolute, 0.5f, 0.6f);
// Update power
ChunkData.SetCachedPowerData(a_Position, PoweringData(a_BlockType, Power));
// Immediately depress plate
a_Chunk.SetMeta(a_Position, E_META_PRESSURE_PLATE_DEPRESSED);
UpdateAdjustedRelatives(a_Chunk, CurrentlyTicking, a_Position, RelativeAdjacents);
return;
}
// Not a resting state
int DelayTicks;
bool HasExitedMinimumOnDelayPhase;
std::tie(DelayTicks, HasExitedMinimumOnDelayPhase) = *DelayInfo;
// Are we waiting for the initial delay or subsequent release delay?
if (DelayTicks > 0)
{
// Nothing changes, if there is nothing on it anymore, because the state is locked.
if (Power == 0)
{
return;
}
// Yes. Are we waiting to release, and found that the player stepped on it again?
if (!HasExitedMinimumOnDelayPhase)
{
// Reset delay
*DelayInfo = std::make_pair(0, true);
}
// Did the power level change and is still above zero?
if (Power != PreviousPower.PowerLevel)
{
// Yes. Update power
ChunkData.SetCachedPowerData(a_Position, PoweringData(a_BlockType, Power));
UpdateAdjustedRelatives(a_Chunk, CurrentlyTicking, a_Position, RelativeAdjacents);
}
return;
}
// Not waiting for anything. Has the initial delay elapsed?
if (HasExitedMinimumOnDelayPhase)
{
// Yep, initial delay elapsed. Has the player gotten off?
if (Power == 0)
{
// Yes. Go into subsequent release delay, for a further 0.5 seconds
*DelayInfo = std::make_pair(5, false);
return;
}
// Did the power level change and is still above zero?
if (Power != PreviousPower.PowerLevel)
{
// Yes. Update power
ChunkData.SetCachedPowerData(a_Position, PoweringData(a_BlockType, Power));
UpdateAdjustedRelatives(a_Chunk, CurrentlyTicking, a_Position, RelativeAdjacents);
}
// Yes, but player's still on the plate, do nothing
return;
}
// Just got out of the subsequent release phase, reset everything and raise the plate
ChunkData.m_MechanismDelays.erase(a_Position);
a_Chunk.GetWorld()->BroadcastSoundEffect(GetClickOffSound(a_BlockType), Absolute, 0.5f, 0.5f);
ChunkData.SetCachedPowerData(a_Position, PoweringData(a_BlockType, Power));
a_Chunk.SetMeta(a_Position, E_META_PRESSURE_PLATE_RAISED);
UpdateAdjustedRelatives(a_Chunk, CurrentlyTicking, a_Position, RelativeAdjacents);
}
virtual void ForValidSourcePositions(const cChunk & a_Chunk, Vector3i a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, SourceCallback Callback) const override
{
UNUSED(a_Chunk);
UNUSED(a_Position);
UNUSED(a_BlockType);
UNUSED(a_Meta);
UNUSED(Callback);
}
private:
static const char * GetClickOnSound(BLOCKTYPE a_BlockType)
{
// manage on-sound
switch (a_BlockType)
{
case E_BLOCK_STONE_PRESSURE_PLATE: return "block.stone_pressureplate.click_on";
case E_BLOCK_WOODEN_PRESSURE_PLATE: return "block.wood_pressureplate.click_on";
case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE:
case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE: return "block.metal_pressureplate.click_on";
default:
{
ASSERT(!"No on sound for this one!");
return "";
}
}
}
static const char * GetClickOffSound(BLOCKTYPE a_BlockType)
{
// manage off-sound
switch (a_BlockType)
{
case E_BLOCK_STONE_PRESSURE_PLATE: return "block.stone_pressureplate.click_off";
case E_BLOCK_WOODEN_PRESSURE_PLATE: return "block.wood_pressureplate.click_off";
case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE:
case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE: return "block.metal_pressureplate.click_off";
default:
{
ASSERT(!"No off sound for this one!");
return "";
}
}
}
};
|