Skip to content

Commit 5a67268

Browse files
committed
Implement control_wait
1 parent f6ee558 commit 5a67268

File tree

3 files changed

+99
-0
lines changed

3 files changed

+99
-0
lines changed

src/dev/blocks/controlblocks.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <scratchcpp/field.h>
99
#include <scratchcpp/dev/executioncontext.h>
1010
#include <scratchcpp/thread.h>
11+
#include <scratchcpp/istacktimer.h>
1112

1213
#include "controlblocks.h"
1314

@@ -30,6 +31,7 @@ void ControlBlocks::registerBlocks(IEngine *engine)
3031
engine->addCompileFunction(this, "control_if", &compileIf);
3132
engine->addCompileFunction(this, "control_if_else", &compileIfElse);
3233
engine->addCompileFunction(this, "control_stop", &compileStop);
34+
engine->addCompileFunction(this, "control_wait", &compileWait);
3335
}
3436

3537
CompilerValue *ControlBlocks::compileForever(Compiler *compiler)
@@ -80,6 +82,20 @@ CompilerValue *ControlBlocks::compileStop(Compiler *compiler)
8082
return nullptr;
8183
}
8284

85+
CompilerValue *ControlBlocks::compileWait(Compiler *compiler)
86+
{
87+
auto duration = compiler->addInput("DURATION");
88+
compiler->addFunctionCallWithCtx("control_start_stack_timer", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { duration });
89+
compiler->createYield();
90+
91+
compiler->beginLoopCondition();
92+
auto elapsed = compiler->addFunctionCallWithCtx("control_stack_timer_elapsed", Compiler::StaticType::Bool);
93+
compiler->beginRepeatUntilLoop(elapsed);
94+
compiler->endLoop();
95+
96+
return nullptr;
97+
}
98+
8399
extern "C" void control_stop_all(ExecutionContext *ctx)
84100
{
85101
ctx->engine()->stop();
@@ -90,3 +106,13 @@ extern "C" void control_stop_other_scripts_in_target(ExecutionContext *ctx)
90106
Thread *thread = ctx->thread();
91107
ctx->engine()->stopTarget(thread->target(), thread);
92108
}
109+
110+
extern "C" void control_start_stack_timer(ExecutionContext *ctx, double seconds)
111+
{
112+
ctx->stackTimer()->start(seconds);
113+
}
114+
115+
extern "C" bool control_stack_timer_elapsed(ExecutionContext *ctx)
116+
{
117+
return ctx->stackTimer()->elapsed();
118+
}

src/dev/blocks/controlblocks.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class ControlBlocks : public IExtension
2121
static CompilerValue *compileIf(Compiler *compiler);
2222
static CompilerValue *compileIfElse(Compiler *compiler);
2323
static CompilerValue *compileStop(Compiler *compiler);
24+
static CompilerValue *compileWait(Compiler *compiler);
2425
};
2526

2627
} // namespace libscratchcpp

test/dev/blocks/control_blocks_test.cpp

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@
66
#include <scratchcpp/input.h>
77
#include <scratchcpp/script.h>
88
#include <scratchcpp/thread.h>
9+
#include <scratchcpp/dev/executablecode.h>
10+
#include <scratchcpp/dev/executioncontext.h>
11+
912
#include <enginemock.h>
13+
#include <stacktimermock.h>
1014

1115
#include "../common.h"
1216
#include "dev/blocks/controlblocks.h"
@@ -15,6 +19,8 @@
1519
using namespace libscratchcpp;
1620
using namespace libscratchcpp::test;
1721

22+
using ::testing::Return;
23+
1824
class ControlBlocksTest : public testing::Test
1925
{
2026
public:
@@ -332,3 +338,69 @@ TEST_F(ControlBlocksTest, Stop)
332338
thread.run();
333339
}
334340
}
341+
342+
TEST_F(ControlBlocksTest, Wait)
343+
{
344+
auto target = std::make_shared<Sprite>();
345+
346+
{
347+
ScriptBuilder builder(m_extension.get(), m_engine, target);
348+
349+
builder.addBlock("control_wait");
350+
builder.addValueInput("DURATION", 2.5);
351+
auto block = builder.currentBlock();
352+
353+
Compiler compiler(&m_engineMock, target.get());
354+
auto code = compiler.compile(block);
355+
Script script(target.get(), block, &m_engineMock);
356+
script.setCode(code);
357+
Thread thread(target.get(), &m_engineMock, &script);
358+
auto ctx = code->createExecutionContext(&thread);
359+
StackTimerMock timer;
360+
ctx->setStackTimer(&timer);
361+
362+
EXPECT_CALL(timer, start(2.5));
363+
code->run(ctx.get());
364+
ASSERT_FALSE(code->isFinished(ctx.get()));
365+
366+
EXPECT_CALL(timer, elapsed()).WillOnce(Return(false));
367+
code->run(ctx.get());
368+
ASSERT_FALSE(code->isFinished(ctx.get()));
369+
370+
EXPECT_CALL(timer, elapsed()).WillOnce(Return(false));
371+
code->run(ctx.get());
372+
ASSERT_FALSE(code->isFinished(ctx.get()));
373+
374+
EXPECT_CALL(timer, elapsed()).WillOnce(Return(true));
375+
code->run(ctx.get());
376+
ASSERT_TRUE(code->isFinished(ctx.get()));
377+
}
378+
379+
m_engine->clear();
380+
target = std::make_shared<Sprite>();
381+
382+
{
383+
ScriptBuilder builder(m_extension.get(), m_engine, target);
384+
385+
builder.addBlock("control_wait");
386+
builder.addNullObscuredInput("DURATION");
387+
auto block = builder.currentBlock();
388+
389+
Compiler compiler(&m_engineMock, target.get());
390+
auto code = compiler.compile(block);
391+
Script script(target.get(), block, &m_engineMock);
392+
script.setCode(code);
393+
Thread thread(target.get(), &m_engineMock, &script);
394+
auto ctx = code->createExecutionContext(&thread);
395+
StackTimerMock timer;
396+
ctx->setStackTimer(&timer);
397+
398+
EXPECT_CALL(timer, start(0.0));
399+
code->run(ctx.get());
400+
ASSERT_FALSE(code->isFinished(ctx.get()));
401+
402+
EXPECT_CALL(timer, elapsed()).WillOnce(Return(true));
403+
code->run(ctx.get());
404+
ASSERT_TRUE(code->isFinished(ctx.get()));
405+
}
406+
}

0 commit comments

Comments
 (0)