Skip to content

Commit 597c4a0

Browse files
committed
Store values of edge-activated hats with multiple field values correctly
1 parent d8a3948 commit 597c4a0

File tree

4 files changed

+65
-10
lines changed

4 files changed

+65
-10
lines changed

src/engine/internal/engine.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -453,14 +453,26 @@ void Engine::step()
453453
// Processing the hats means running their predicates (if they didn't change their return value from false to true, remove the threads)
454454
for (auto thread : newThreads) {
455455
bool oldValue = false;
456+
auto hatBlock = thread->script()->topBlock();
457+
assert(hatBlock);
458+
assert(hatBlock->fieldAt(0)); // TODO: Edge-activated hats currently support only one field
459+
int fieldValueId = hatBlock->fieldAt(0)->specialValueId();
460+
assert(fieldValueId != -1);
456461
auto it = m_edgeActivatedHatValues.find(hatType);
457462

458-
if (it != m_edgeActivatedHatValues.cend())
459-
oldValue = it->second;
463+
if (it == m_edgeActivatedHatValues.cend()) {
464+
m_edgeActivatedHatValues[hatType] = {};
465+
} else {
466+
const std::unordered_map<int, bool> &values = it->second;
467+
auto fieldIt = values.find(fieldValueId);
468+
469+
if (fieldIt != values.cend())
470+
oldValue = fieldIt->second;
471+
}
460472

461473
bool newValue = thread->script()->runHatPredicate();
462474
bool edgeWasActivated = !oldValue && newValue; // changed from false true
463-
m_edgeActivatedHatValues[hatType] = newValue;
475+
m_edgeActivatedHatValues[hatType][fieldValueId] = newValue;
464476

465477
if (!edgeWasActivated)
466478
stopThread(thread.get());

src/engine/internal/engine.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ class Engine : public IEngine
248248

249249
std::unordered_map<Script *, std::unordered_map<HatField, int>> m_scriptHatFields; // HatField, field ID from the block implementation
250250

251-
std::unordered_map<HatType, bool> m_edgeActivatedHatValues; // edge-activated hats only run after the value changes from false to true
251+
std::unordered_map<HatType, std::unordered_map<int, bool>> m_edgeActivatedHatValues; // (field value, last value) edge-activated hats only run after the value changes from false to true
252252

253253
std::unique_ptr<ITimer> m_defaultTimer;
254254
ITimer *m_timer = nullptr;

test/engine/engine_test.cpp

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@
1414
#include <scratch/sound_p.h>
1515
#include <timermock.h>
1616
#include <clockmock.h>
17+
#include <audioinputmock.h>
1718
#include <audiooutputmock.h>
1819
#include <audioplayermock.h>
20+
#include <audioloudnessmock.h>
1921
#include <monitorhandlermock.h>
2022
#include <blocksectionmock.h>
2123
#include <thread>
@@ -27,6 +29,7 @@
2729
// TODO: Remove this
2830
#include "blocks/variableblocks.h"
2931
#include "blocks/listblocks.h"
32+
#include "blocks/eventblocks.h"
3033

3134
using namespace libscratchcpp;
3235

@@ -1936,24 +1939,64 @@ TEST(EngineTest, EdgeActivatedHats)
19361939
Stage *stage = engine->stage();
19371940
ASSERT_TRUE(stage);
19381941

1939-
ASSERT_VAR(stage, "test");
1940-
auto var = GET_VAR(stage, "test");
1941-
ASSERT_EQ(var->value().toInt(), 0);
1942+
ASSERT_VAR(stage, "test1");
1943+
auto var1 = GET_VAR(stage, "test1");
1944+
ASSERT_VAR(stage, "test2");
1945+
auto var2 = GET_VAR(stage, "test2");
1946+
1947+
ASSERT_EQ(var1->value().toInt(), 0);
1948+
ASSERT_EQ(var2->value().toInt(), 0);
19421949

19431950
TimerMock timer;
1951+
AudioInputMock audioInput;
19441952
engine->setTimer(&timer);
1953+
EventBlocks::audioInput = &audioInput;
1954+
auto audioLoudness = std::make_shared<AudioLoudnessMock>();
1955+
EXPECT_CALL(audioInput, audioLoudness()).WillRepeatedly(Return(audioLoudness));
19451956

19461957
EXPECT_CALL(timer, value()).WillOnce(Return(5));
1958+
EXPECT_CALL(*audioLoudness, getLoudness()).WillOnce(Return(1));
19471959
engine->step();
1948-
ASSERT_EQ(var->value().toInt(), 0);
1960+
ASSERT_EQ(var1->value().toInt(), 0);
1961+
ASSERT_EQ(var2->value().toInt(), 0);
19491962

19501963
EXPECT_CALL(timer, value()).WillOnce(Return(10));
1964+
EXPECT_CALL(*audioLoudness, getLoudness()).WillOnce(Return(9));
19511965
engine->step();
1952-
ASSERT_EQ(var->value().toInt(), 0);
1966+
ASSERT_EQ(var1->value().toInt(), 0);
1967+
ASSERT_EQ(var2->value().toInt(), 1);
19531968

19541969
EXPECT_CALL(timer, value()).WillOnce(Return(10.2));
1970+
EXPECT_CALL(*audioLoudness, getLoudness()).WillOnce(Return(10));
1971+
engine->step();
1972+
ASSERT_EQ(var1->value().toInt(), 1);
1973+
ASSERT_EQ(var2->value().toInt(), 1);
1974+
1975+
EXPECT_CALL(timer, value()).WillOnce(Return(15));
1976+
EXPECT_CALL(*audioLoudness, getLoudness()).WillOnce(Return(2));
19551977
engine->step();
1956-
ASSERT_EQ(var->value().toInt(), 1);
1978+
ASSERT_EQ(var1->value().toInt(), 1);
1979+
ASSERT_EQ(var2->value().toInt(), 1);
1980+
1981+
EXPECT_CALL(timer, value()).WillOnce(Return(12));
1982+
EXPECT_CALL(*audioLoudness, getLoudness()).WillOnce(Return(8));
1983+
engine->step();
1984+
ASSERT_EQ(var1->value().toInt(), 1);
1985+
ASSERT_EQ(var2->value().toInt(), 2);
1986+
1987+
EXPECT_CALL(timer, value()).WillOnce(Return(8));
1988+
EXPECT_CALL(*audioLoudness, getLoudness()).WillOnce(Return(3));
1989+
engine->step();
1990+
ASSERT_EQ(var1->value().toInt(), 1);
1991+
ASSERT_EQ(var2->value().toInt(), 2);
1992+
1993+
EXPECT_CALL(timer, value()).WillOnce(Return(11));
1994+
EXPECT_CALL(*audioLoudness, getLoudness()).WillOnce(Return(15));
1995+
engine->step();
1996+
ASSERT_EQ(var1->value().toInt(), 2);
1997+
ASSERT_EQ(var2->value().toInt(), 3);
1998+
1999+
EventBlocks::audioInput = nullptr;
19572000
}
19582001

19592002
TEST(EngineTest, UserAgent)

test/when_greater_than.sb3

181 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)