diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ccc10b8..82b1cbb9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.14) -project(libscratchcpp VERSION 0.11.1 LANGUAGES C CXX) +project(libscratchcpp VERSION 0.11.2 LANGUAGES C CXX) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_CXX_STANDARD 17) diff --git a/src/blocks/controlblocks.cpp b/src/blocks/controlblocks.cpp index ca3c4884..ab5aab69 100644 --- a/src/blocks/controlblocks.cpp +++ b/src/blocks/controlblocks.cpp @@ -59,6 +59,7 @@ void ControlBlocks::registerBlocks(IEngine *engine) engine->addFieldValue(this, "all", StopAll); engine->addFieldValue(this, "this script", StopThisScript); engine->addFieldValue(this, "other scripts in sprite", StopOtherScriptsInSprite); + engine->addFieldValue(this, "other scripts in stage", StopOtherScriptsInSprite); } void ControlBlocks::compileRepeatForever(Compiler *compiler) diff --git a/src/engine/internal/engine.cpp b/src/engine/internal/engine.cpp index 6a15c9da..c970a68d 100644 --- a/src/engine/internal/engine.cpp +++ b/src/engine/internal/engine.cpp @@ -539,6 +539,7 @@ void Engine::step() // Resolve stopped broadcast scripts std::vector resolved; + std::vector resolvedThreads; for (const auto &[broadcast, senderThread] : m_broadcastSenders) { std::unordered_map> *broadcastMap = nullptr; @@ -566,13 +567,21 @@ void Engine::step() } } - if (!found) { + if (found) { + // If a broadcast with the same name but different case + // was considered stopped before, restore the promise. + if (std::find(resolvedThreads.begin(), resolvedThreads.end(), senderThread) != resolvedThreads.end()) { + senderThread->promise(); + resolvedThreads.erase(std::remove(resolvedThreads.begin(), resolvedThreads.end(), senderThread), resolvedThreads.end()); + } + } else { Thread *th = senderThread; if (std::find_if(m_threads.begin(), m_threads.end(), [th](std::shared_ptr thread) { return thread.get() == th; }) != m_threads.end()) th->resolvePromise(); resolved.push_back(broadcast); + resolvedThreads.push_back(th); } } diff --git a/src/scratch/target.cpp b/src/scratch/target.cpp index bb14bd97..7d01cebe 100644 --- a/src/scratch/target.cpp +++ b/src/scratch/target.cpp @@ -540,6 +540,9 @@ bool Target::touchingColor(const Value &color, const Value &mask) const /*! Returns the value of the given graphics effect. */ double Target::graphicsEffectValue(IGraphicsEffect *effect) const { + if (!effect) + return 0; + auto it = impl->graphicsEffects.find(effect); if (it == impl->graphicsEffects.cend()) @@ -551,8 +554,8 @@ double Target::graphicsEffectValue(IGraphicsEffect *effect) const /*! Sets the value of the given graphics effect. */ void Target::setGraphicsEffectValue(IGraphicsEffect *effect, double value) { - assert(effect); - impl->graphicsEffects[effect] = effect->clamp(value); + if (effect) + impl->graphicsEffects[effect] = effect->clamp(value); } /*! Sets the value of all graphics effects to 0 (clears them). */ diff --git a/test/blocks/control_blocks_test.cpp b/test/blocks/control_blocks_test.cpp index 6bb5e1ae..cee4029e 100644 --- a/test/blocks/control_blocks_test.cpp +++ b/test/blocks/control_blocks_test.cpp @@ -176,6 +176,7 @@ TEST_F(ControlBlocksTest, RegisterBlocks) EXPECT_CALL(m_engineMock, addFieldValue(m_extension.get(), "all", ControlBlocks::StopAll)); EXPECT_CALL(m_engineMock, addFieldValue(m_extension.get(), "this script", ControlBlocks::StopThisScript)); EXPECT_CALL(m_engineMock, addFieldValue(m_extension.get(), "other scripts in sprite", ControlBlocks::StopOtherScriptsInSprite)); + EXPECT_CALL(m_engineMock, addFieldValue(m_extension.get(), "other scripts in stage", ControlBlocks::StopOtherScriptsInSprite)); m_extension->registerBlocks(&m_engineMock); } diff --git a/test/engine/engine_test.cpp b/test/engine/engine_test.cpp index 3b22b0a2..304ce451 100644 --- a/test/engine/engine_test.cpp +++ b/test/engine/engine_test.cpp @@ -2249,3 +2249,20 @@ TEST(EngineTest, BroadcastStopsWaitBlocks) ASSERT_VAR(stage, "backdrop_passed"); ASSERT_TRUE(GET_VAR(stage, "backdrop_passed")->value().toBool()); } + +TEST(EngineTest, BroadcastAndWaitCaseInsensitive) +{ + // Regtest for #578 + Project p("regtest_projects/578_broadcast_and_wait_case_insensitive.sb3"); + ASSERT_TRUE(p.load()); + + auto engine = p.engine(); + + Stage *stage = engine->stage(); + ASSERT_TRUE(stage); + + engine->run(); + + ASSERT_VAR(stage, "passed"); + ASSERT_TRUE(GET_VAR(stage, "passed")->value().toBool()); +} diff --git a/test/regtest_projects/578_broadcast_and_wait_case_insensitive.sb3 b/test/regtest_projects/578_broadcast_and_wait_case_insensitive.sb3 new file mode 100644 index 00000000..ecc70bcf Binary files /dev/null and b/test/regtest_projects/578_broadcast_and_wait_case_insensitive.sb3 differ diff --git a/test/scratch_classes/stage_test.cpp b/test/scratch_classes/stage_test.cpp index d21156a9..53f0477d 100644 --- a/test/scratch_classes/stage_test.cpp +++ b/test/scratch_classes/stage_test.cpp @@ -219,7 +219,7 @@ TEST(StageTest, TouchingPoint) ASSERT_TRUE(stage.touchingPoint(-12.46, 120.72)); } -TEST(SpriteTest, TouchingColor) +TEST(StageTest, TouchingColor) { Stage stage; ASSERT_FALSE(stage.touchingColor(0)); diff --git a/test/scratch_classes/target_test.cpp b/test/scratch_classes/target_test.cpp index bc4d9d95..e9d02379 100644 --- a/test/scratch_classes/target_test.cpp +++ b/test/scratch_classes/target_test.cpp @@ -775,7 +775,7 @@ TEST(TargetTest, GraphicsEffects) ASSERT_EQ(target.graphicsEffectValue(&effect2), 0); } -TEST(SpriteTest, BubbleTypeRedraw) +TEST(TargetTest, BubbleTypeRedraw) { Target target; EngineMock engine; @@ -786,7 +786,7 @@ TEST(SpriteTest, BubbleTypeRedraw) target.bubble()->setType(TextBubble::Type::Think); } -TEST(SpriteTest, BubbleTextRedraw) +TEST(TaregtTest, BubbleTextRedraw) { Target target; EngineMock engine;