Skip to content

Commit 86f1ce0

Browse files
committed
Implement sensing_of block
1 parent 34ce8b7 commit 86f1ce0

File tree

3 files changed

+1330
-1
lines changed

3 files changed

+1330
-1
lines changed

src/blocks/sensingblocks.cpp

Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@
1010
#include <scratchcpp/input.h>
1111
#include <scratchcpp/field.h>
1212
#include <scratchcpp/sprite.h>
13+
#include <scratchcpp/stage.h>
14+
#include <scratchcpp/costume.h>
1315
#include <scratchcpp/textbubble.h>
16+
#include <scratchcpp/variable.h>
1417
#include <scratchcpp/stringptr.h>
1518
#include <scratchcpp/string_functions.h>
1619
#include <scratchcpp/string_pool.h>
@@ -55,6 +58,7 @@ void SensingBlocks::registerBlocks(IEngine *engine)
5558
engine->addCompileFunction(this, "sensing_loud", &compileLoud);
5659
engine->addCompileFunction(this, "sensing_timer", &compileTimer);
5760
engine->addCompileFunction(this, "sensing_resettimer", &compileResetTimer);
61+
engine->addCompileFunction(this, "sensing_of", &compileOf);
5862
}
5963

6064
void SensingBlocks::onInit(IEngine *engine)
@@ -243,6 +247,101 @@ CompilerValue *SensingBlocks::compileResetTimer(Compiler *compiler)
243247
return nullptr;
244248
}
245249

250+
CompilerValue *SensingBlocks::compileOf(Compiler *compiler)
251+
{
252+
IEngine *engine = compiler->engine();
253+
Input *input = compiler->input("OBJECT");
254+
Field *field = compiler->field("PROPERTY");
255+
assert(input);
256+
assert(field);
257+
258+
std::string property = field->value().toString();
259+
260+
if (input->pointsToDropdownMenu()) {
261+
// Compile time
262+
std::string value = input->selectedMenuItem();
263+
Target *target = nullptr;
264+
CompilerValue *targetPtr = nullptr;
265+
266+
if (value == "_stage_") {
267+
// Stage properties
268+
target = engine->stage();
269+
targetPtr = compiler->addConstValue(target);
270+
271+
if (property == "backdrop #")
272+
return compiler->addFunctionCall("sensing_costume_number_of_target", Compiler::StaticType::Number, { Compiler::StaticType::Pointer }, { targetPtr });
273+
else if (property == "backdrop name")
274+
return compiler->addFunctionCall("sensing_costume_name_of_target", Compiler::StaticType::String, { Compiler::StaticType::Pointer }, { targetPtr });
275+
} else {
276+
// Sprite properties
277+
target = engine->targetAt(engine->findTarget(value));
278+
279+
if (target) {
280+
targetPtr = compiler->addConstValue(target);
281+
282+
if (property == "x position")
283+
return compiler->addFunctionCall("sensing_x_position_of_sprite", Compiler::StaticType::Number, { Compiler::StaticType::Pointer }, { targetPtr });
284+
else if (property == "y position")
285+
return compiler->addFunctionCall("sensing_y_position_of_sprite", Compiler::StaticType::Number, { Compiler::StaticType::Pointer }, { targetPtr });
286+
else if (property == "direction")
287+
return compiler->addFunctionCall("sensing_direction_of_sprite", Compiler::StaticType::Number, { Compiler::StaticType::Pointer }, { targetPtr });
288+
else if (property == "costume #")
289+
return compiler->addFunctionCall("sensing_costume_number_of_target", Compiler::StaticType::Number, { Compiler::StaticType::Pointer }, { targetPtr });
290+
else if (property == "costume name")
291+
return compiler->addFunctionCall("sensing_costume_name_of_target", Compiler::StaticType::String, { Compiler::StaticType::Pointer }, { targetPtr });
292+
else if (property == "size")
293+
return compiler->addFunctionCall("sensing_size_of_sprite", Compiler::StaticType::Number, { Compiler::StaticType::Pointer }, { targetPtr });
294+
}
295+
}
296+
297+
// Common properties
298+
if (target && targetPtr) {
299+
if (property == "volume")
300+
return compiler->addFunctionCall("sensing_volume_of_target", Compiler::StaticType::Number, { Compiler::StaticType::Pointer }, { targetPtr });
301+
else {
302+
auto var = target->variableAt(target->findVariable(property));
303+
304+
if (var)
305+
return compiler->addVariableValue(var.get());
306+
}
307+
}
308+
} else {
309+
// Runtime
310+
CompilerValue *targetName = compiler->addInput(input);
311+
CompilerValue *targetPtr = compiler->addFunctionCallWithCtx("sensing_get_target", Compiler::StaticType::Pointer, { Compiler::StaticType::String }, { targetName });
312+
313+
// Stage properties
314+
if (property == "backdrop #") {
315+
return compiler->addFunctionCall("sensing_backdrop_number_of_stage_with_check", Compiler::StaticType::Number, { Compiler::StaticType::Pointer }, { targetPtr });
316+
} else if (property == "backdrop name")
317+
return compiler->addFunctionCall("sensing_backdrop_name_of_stage_with_check", Compiler::StaticType::String, { Compiler::StaticType::Pointer }, { targetPtr });
318+
319+
// Sprite properties
320+
if (property == "x position")
321+
return compiler->addFunctionCall("sensing_x_position_of_sprite_with_check", Compiler::StaticType::Number, { Compiler::StaticType::Pointer }, { targetPtr });
322+
else if (property == "y position")
323+
return compiler->addFunctionCall("sensing_y_position_of_sprite_with_check", Compiler::StaticType::Number, { Compiler::StaticType::Pointer }, { targetPtr });
324+
else if (property == "direction")
325+
return compiler->addFunctionCall("sensing_direction_of_sprite_with_check", Compiler::StaticType::Number, { Compiler::StaticType::Pointer }, { targetPtr });
326+
else if (property == "costume #")
327+
return compiler->addFunctionCall("sensing_costume_number_of_sprite_with_check", Compiler::StaticType::Number, { Compiler::StaticType::Pointer }, { targetPtr });
328+
else if (property == "costume name")
329+
return compiler->addFunctionCall("sensing_costume_name_of_sprite_with_check", Compiler::StaticType::String, { Compiler::StaticType::Pointer }, { targetPtr });
330+
else if (property == "size")
331+
return compiler->addFunctionCall("sensing_size_of_sprite_with_check", Compiler::StaticType::Number, { Compiler::StaticType::Pointer }, { targetPtr });
332+
333+
// Common properties
334+
if (property == "volume")
335+
return compiler->addFunctionCall("sensing_volume_of_target_with_check", Compiler::StaticType::Number, { Compiler::StaticType::Pointer }, { targetPtr });
336+
else {
337+
CompilerValue *varName = compiler->addConstValue(property);
338+
return compiler->addFunctionCall("sensing_variable_of_target", Compiler::StaticType::Unknown, { Compiler::StaticType::Pointer, Compiler::StaticType::String }, { targetPtr, varName });
339+
}
340+
}
341+
342+
return compiler->addConstValue(0.0);
343+
}
344+
246345
void SensingBlocks::onAnswer(const std::string &answer)
247346
{
248347
// https://github.com/scratchfoundation/scratch-vm/blob/6055823f203a696165084b873e661713806583ec/src/blocks/scratch3_sensing.js#L99-L115
@@ -443,3 +542,162 @@ extern "C" void sensing_resettimer(ITimer *timer)
443542
{
444543
timer->reset();
445544
}
545+
546+
extern "C" double sensing_x_position_of_sprite(Sprite *sprite)
547+
{
548+
return sprite->x();
549+
}
550+
551+
extern "C" double sensing_y_position_of_sprite(Sprite *sprite)
552+
{
553+
return sprite->y();
554+
}
555+
556+
extern "C" double sensing_direction_of_sprite(Sprite *sprite)
557+
{
558+
return sprite->direction();
559+
}
560+
561+
extern "C" double sensing_costume_number_of_target(Target *target)
562+
{
563+
return target->costumeIndex() + 1;
564+
}
565+
566+
extern "C" StringPtr *sensing_costume_name_of_target(Target *target)
567+
{
568+
const std::string &name = target->currentCostume()->name();
569+
StringPtr *ret = string_pool_new();
570+
string_assign_cstring(ret, name.c_str());
571+
return ret;
572+
}
573+
574+
extern "C" double sensing_size_of_sprite(Sprite *sprite)
575+
{
576+
return sprite->size();
577+
}
578+
579+
extern "C" double sensing_volume_of_target(Target *target)
580+
{
581+
return target->volume();
582+
}
583+
584+
extern "C" Target *sensing_get_target(ExecutionContext *ctx, const StringPtr *name)
585+
{
586+
// TODO: Use UTF-16 in engine
587+
std::string u8name = utf8::utf16to8(std::u16string(name->data));
588+
IEngine *engine = ctx->engine();
589+
return engine->targetAt(engine->findTarget(u8name));
590+
}
591+
592+
extern "C" double sensing_x_position_of_sprite_with_check(Target *target)
593+
{
594+
if (target && !target->isStage()) {
595+
Sprite *sprite = static_cast<Sprite *>(target);
596+
return sprite->x();
597+
}
598+
599+
return 0.0;
600+
}
601+
602+
extern "C" double sensing_y_position_of_sprite_with_check(Target *target)
603+
{
604+
if (target && !target->isStage()) {
605+
Sprite *sprite = static_cast<Sprite *>(target);
606+
return sprite->y();
607+
}
608+
609+
return 0.0;
610+
}
611+
612+
extern "C" double sensing_direction_of_sprite_with_check(Target *target)
613+
{
614+
if (target && !target->isStage()) {
615+
Sprite *sprite = static_cast<Sprite *>(target);
616+
return sprite->direction();
617+
}
618+
619+
return 0.0;
620+
}
621+
622+
extern "C" double sensing_costume_number_of_sprite_with_check(Target *target)
623+
{
624+
if (target && !target->isStage())
625+
return target->costumeIndex() + 1;
626+
627+
return 0.0;
628+
}
629+
630+
extern "C" StringPtr *sensing_costume_name_of_sprite_with_check(Target *target)
631+
{
632+
StringPtr *ret = string_pool_new();
633+
634+
if (target && !target->isStage()) {
635+
const std::string &name = target->currentCostume()->name();
636+
string_assign_cstring(ret, name.c_str());
637+
} else
638+
string_assign_cstring(ret, "0");
639+
640+
return ret;
641+
}
642+
643+
extern "C" double sensing_size_of_sprite_with_check(Target *target)
644+
{
645+
if (target && !target->isStage()) {
646+
Sprite *sprite = static_cast<Sprite *>(target);
647+
return sprite->size();
648+
}
649+
650+
return 0.0;
651+
}
652+
653+
extern "C" double sensing_backdrop_number_of_stage_with_check(Target *target)
654+
{
655+
if (target && target->isStage())
656+
return target->costumeIndex() + 1;
657+
658+
return 0.0;
659+
}
660+
661+
extern "C" StringPtr *sensing_backdrop_name_of_stage_with_check(Target *target)
662+
{
663+
StringPtr *ret = string_pool_new();
664+
665+
if (target && target->isStage()) {
666+
const std::string &name = target->currentCostume()->name();
667+
string_assign_cstring(ret, name.c_str());
668+
} else
669+
string_assign_cstring(ret, "");
670+
671+
return ret;
672+
}
673+
674+
extern "C" double sensing_volume_of_target_with_check(Target *target)
675+
{
676+
if (target)
677+
return target->volume();
678+
679+
return 0.0;
680+
}
681+
682+
extern "C" ValueData sensing_variable_of_target(Target *target, const StringPtr *varName)
683+
{
684+
if (target) {
685+
// TODO: Use UTF-16 in... Target?
686+
std::string u8name = utf8::utf16to8(std::u16string(varName->data));
687+
int varIndex = target->findVariable(u8name);
688+
if (varIndex >= 0) {
689+
auto var = target->variableAt(varIndex);
690+
691+
if (var) {
692+
ValueData ret;
693+
value_init(&ret);
694+
value_assign_copy(&ret, &var->value().data());
695+
return ret;
696+
}
697+
}
698+
}
699+
700+
ValueData ret;
701+
value_init(&ret);
702+
return ret;
703+
}

src/blocks/sensingblocks.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ class SensingBlocks : public IExtension
6060
static CompilerValue *compileLoud(Compiler *compiler);
6161
static CompilerValue *compileTimer(Compiler *compiler);
6262
static CompilerValue *compileResetTimer(Compiler *compiler);
63+
static CompilerValue *compileOf(Compiler *compiler);
6364

6465
static void onAnswer(const std::string &answer);
6566
static void enqueueAsk(const std::string &question, Thread *thread);

0 commit comments

Comments
 (0)