Skip to content

Commit f3924cc

Browse files
committed
Implement event_whengreaterthan predicate
1 parent 2ea6686 commit f3924cc

File tree

3 files changed

+121
-3
lines changed

3 files changed

+121
-3
lines changed

src/blocks/eventblocks.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,12 @@
1212
#include <scratchcpp/promise.h>
1313
#include <scratchcpp/stringptr.h>
1414
#include <scratchcpp/sprite.h>
15+
#include <scratchcpp/itimer.h>
1516
#include <utf8.h>
1617

1718
#include "eventblocks.h"
19+
#include "audio/audioinput.h"
20+
#include "audio/iaudioloudness.h"
1821

1922
using namespace libscratchcpp;
2023

@@ -49,6 +52,7 @@ void EventBlocks::registerBlocks(IEngine *engine)
4952

5053
// Hat predicates
5154
engine->addHatPredicateCompileFunction(this, "event_whentouchingobject", &compileWhenTouchingObjectPredicate);
55+
engine->addHatPredicateCompileFunction(this, "event_whengreaterthan", &compileWhenGreaterThanPredicate);
5256
}
5357

5458
CompilerValue *EventBlocks::compileWhenTouchingObject(Compiler *compiler)
@@ -120,6 +124,27 @@ CompilerValue *EventBlocks::compileWhenGreaterThan(Compiler *compiler)
120124
return nullptr;
121125
}
122126

127+
CompilerValue *EventBlocks::compileWhenGreaterThanPredicate(Compiler *compiler)
128+
{
129+
Field *field = compiler->field("WHENGREATERTHANMENU");
130+
std::string predicate;
131+
132+
if (field) {
133+
const std::string option = field->value().toString();
134+
135+
if (option == "LOUDNESS")
136+
predicate = "event_whengreaterthan_loudness_predicate";
137+
else if (option == "TIMER")
138+
predicate = "event_whengreaterthan_timer_predicate";
139+
else
140+
return compiler->addConstValue(false);
141+
} else
142+
return compiler->addConstValue(false);
143+
144+
CompilerValue *value = compiler->addInput("VALUE");
145+
return compiler->addFunctionCallWithCtx(predicate, Compiler::StaticType::Bool, { Compiler::StaticType::Number }, { value });
146+
}
147+
123148
CompilerValue *EventBlocks::compileBroadcast(Compiler *compiler)
124149
{
125150
auto input = compiler->addInput("BROADCAST_INPUT");
@@ -171,6 +196,20 @@ extern "C" bool event_whentouchingobject_predicate(Target *target, const StringP
171196
}
172197
}
173198

199+
extern "C" bool event_whengreaterthan_loudness_predicate(ExecutionContext *ctx, double value)
200+
{
201+
if (!EventBlocks::audioInput)
202+
EventBlocks::audioInput = AudioInput::instance().get();
203+
204+
auto audioLoudness = EventBlocks::audioInput->audioLoudness();
205+
return (audioLoudness->getLoudness() > value);
206+
}
207+
208+
extern "C" bool event_whengreaterthan_timer_predicate(ExecutionContext *ctx, double value)
209+
{
210+
return ctx->engine()->timer()->value() > value;
211+
}
212+
174213
extern "C" void event_broadcast(ExecutionContext *ctx, const StringPtr *name, bool wait)
175214
{
176215
Thread *thread = ctx->thread();

src/blocks/eventblocks.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
namespace libscratchcpp
88
{
99

10+
class IAudioInput;
11+
1012
class EventBlocks : public IExtension
1113
{
1214
public:
@@ -16,6 +18,8 @@ class EventBlocks : public IExtension
1618

1719
void registerBlocks(IEngine *engine) override;
1820

21+
static inline IAudioInput *audioInput = nullptr;
22+
1923
private:
2024
static CompilerValue *compileWhenTouchingObject(Compiler *compiler);
2125
static CompilerValue *compileWhenTouchingObjectPredicate(Compiler *compiler);
@@ -25,6 +29,7 @@ class EventBlocks : public IExtension
2529
static CompilerValue *compileWhenBroadcastReceived(Compiler *compiler);
2630
static CompilerValue *compileWhenBackdropSwitchesTo(Compiler *compiler);
2731
static CompilerValue *compileWhenGreaterThan(Compiler *compiler);
32+
static CompilerValue *compileWhenGreaterThanPredicate(Compiler *compiler);
2833
static CompilerValue *compileBroadcast(Compiler *compiler);
2934
static CompilerValue *compileBroadcastAndWait(Compiler *compiler);
3035
static CompilerValue *compileWhenKeyPressed(Compiler *compiler);

test/blocks/event_blocks_test.cpp

Lines changed: 77 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
#include <scratchcpp/executablecode.h>
1010
#include <enginemock.h>
1111
#include <targetmock.h>
12+
#include <audioinputmock.h>
13+
#include <audioloudnessmock.h>
14+
#include <timermock.h>
1215

1316
#include "../common.h"
1417
#include "blocks/eventblocks.h"
@@ -126,6 +129,24 @@ TEST_F(EventBlocksTest, WhenTouchingObjectPredicate)
126129
ASSERT_TRUE(thread.runPredicate());
127130
}
128131

132+
// "_stage_"
133+
{
134+
ScriptBuilder builder(m_extension.get(), m_engine, target, false);
135+
builder.addBlock("event_whentouchingobject");
136+
builder.addDropdownInput("TOUCHINGOBJECTMENU", "");
137+
auto block = builder.currentBlock();
138+
139+
Compiler compiler(&m_engineMock, target.get());
140+
auto code = compiler.compile(block, true);
141+
Script script(target.get(), block, &m_engineMock);
142+
script.setHatPredicateCode(code);
143+
Thread thread(target.get(), &m_engineMock, &script);
144+
145+
EXPECT_CALL(m_engineMock, findTarget("")).WillOnce(Return(-1));
146+
EXPECT_CALL(m_engineMock, targetAt(-1)).WillOnce(Return(nullptr));
147+
ASSERT_FALSE(thread.runPredicate());
148+
}
149+
129150
// ""
130151
{
131152
ScriptBuilder builder(m_extension.get(), m_engine, target, false);
@@ -215,12 +236,10 @@ TEST_F(EventBlocksTest, WhenBackdropSwitchesTo)
215236
compiler.compile(block);
216237
}
217238

218-
// TODO: Add test for when greater than hat predicate
219-
220239
TEST_F(EventBlocksTest, WhenGreaterThan)
221240
{
222241
auto target = std::make_shared<Sprite>();
223-
ScriptBuilder builder(m_extension.get(), m_engine, target);
242+
ScriptBuilder builder(m_extension.get(), m_engine, target, false);
224243

225244
builder.addBlock("event_whengreaterthan");
226245
builder.addDropdownField("WHENGREATERTHANMENU", "LOUDNESS");
@@ -232,6 +251,61 @@ TEST_F(EventBlocksTest, WhenGreaterThan)
232251
compiler.compile(block);
233252
}
234253

254+
TEST_F(EventBlocksTest, WhenGreaterThanPredicate)
255+
{
256+
auto target = std::make_shared<Sprite>();
257+
ScriptBuilder builder(m_extension.get(), m_engine, target, false);
258+
259+
const std::vector<Value> values = { 22.7, 23, 23.5 };
260+
const std::vector<bool> retValues = { true, false, false };
261+
262+
AudioInputMock audioInput;
263+
auto audioLoudness = std::make_shared<AudioLoudnessMock>();
264+
EventBlocks::audioInput = &audioInput;
265+
EXPECT_CALL(audioInput, audioLoudness()).Times(3).WillRepeatedly(Return(audioLoudness));
266+
EXPECT_CALL(*audioLoudness, getLoudness()).Times(3).WillRepeatedly(Return(23));
267+
268+
// when [loudness] > x
269+
for (int i = 0; i < values.size(); i++) {
270+
ScriptBuilder builder(m_extension.get(), m_engine, target, false);
271+
builder.addBlock("event_whengreaterthan");
272+
builder.addDropdownField("WHENGREATERTHANMENU", "LOUDNESS");
273+
builder.addValueInput("VALUE", values[i]);
274+
auto block = builder.currentBlock();
275+
276+
Compiler compiler(&m_engineMock, target.get());
277+
auto code = compiler.compile(block, true);
278+
Script script(target.get(), block, &m_engineMock);
279+
script.setHatPredicateCode(code);
280+
Thread thread(target.get(), &m_engineMock, &script);
281+
282+
ASSERT_EQ(thread.runPredicate(), retValues[i]);
283+
}
284+
285+
EventBlocks::audioInput = nullptr;
286+
287+
TimerMock timer;
288+
EXPECT_CALL(m_engineMock, timer()).Times(3).WillRepeatedly(Return(&timer));
289+
EXPECT_CALL(timer, value()).Times(3).WillRepeatedly(Return(23));
290+
291+
// when [timer] > x
292+
for (int i = 0; i < values.size(); i++) {
293+
ScriptBuilder builder(m_extension.get(), m_engine, target, false);
294+
builder.addBlock("event_whengreaterthan");
295+
builder.addDropdownField("WHENGREATERTHANMENU", "TIMER");
296+
builder.addValueInput("VALUE", values[i]);
297+
auto block = builder.currentBlock();
298+
299+
Compiler compiler(&m_engineMock, target.get());
300+
auto code = compiler.compile(block, true);
301+
Script script(target.get(), block, &m_engineMock);
302+
script.setHatPredicateCode(code);
303+
Thread thread(target.get(), &m_engineMock, &script);
304+
305+
ASSERT_EQ(thread.runPredicate(), retValues[i]);
306+
}
307+
}
308+
235309
TEST_F(EventBlocksTest, Broadcast)
236310
{
237311
auto broadcast = std::make_shared<Broadcast>("", "test");

0 commit comments

Comments
 (0)