|
5 | 5 | #include <scratchcpp/compilerconstant.h>
|
6 | 6 | #include <scratchcpp/executioncontext.h>
|
7 | 7 | #include <scratchcpp/istacktimer.h>
|
| 8 | +#include <scratchcpp/irandomgenerator.h> |
8 | 9 | #include <scratchcpp/thread.h>
|
9 | 10 | #include <scratchcpp/sprite.h>
|
| 11 | +#include <scratchcpp/stage.h> |
| 12 | +#include <scratchcpp/costume.h> |
10 | 13 | #include <scratchcpp/stringptr.h>
|
11 | 14 | #include <scratchcpp/value.h>
|
12 | 15 | #include <scratchcpp/input.h>
|
@@ -50,6 +53,7 @@ void LooksBlocks::registerBlocks(IEngine *engine)
|
50 | 53 | engine->addCompileFunction(this, "looks_size", &compileSize);
|
51 | 54 | engine->addCompileFunction(this, "looks_switchcostumeto", &compileSwitchCostumeTo);
|
52 | 55 | engine->addCompileFunction(this, "looks_nextcostume", &compileNextCostume);
|
| 56 | + engine->addCompileFunction(this, "looks_switchbackdropto", &compileSwitchBackdropTo); |
53 | 57 | }
|
54 | 58 |
|
55 | 59 | void LooksBlocks::onInit(IEngine *engine)
|
@@ -218,6 +222,16 @@ CompilerValue *LooksBlocks::compileNextCostume(Compiler *compiler)
|
218 | 222 | return nullptr;
|
219 | 223 | }
|
220 | 224 |
|
| 225 | +CompilerValue *LooksBlocks::compileSwitchBackdropTo(Compiler *compiler) |
| 226 | +{ |
| 227 | + auto backdrop = compiler->addInput("BACKDROP"); |
| 228 | + auto wait = compiler->addConstValue(false); |
| 229 | + compiler->addFunctionCallWithCtx("looks_switchbackdropto", Compiler::StaticType::Void, { Compiler::StaticType::Unknown }, { backdrop }); |
| 230 | + compiler->addFunctionCallWithCtx("looks_start_backdrop_scripts", Compiler::StaticType::Void, { Compiler::StaticType::Bool }, { wait }); |
| 231 | + |
| 232 | + return nullptr; |
| 233 | +} |
| 234 | + |
221 | 235 | extern "C" void looks_start_stack_timer(ExecutionContext *ctx, double duration)
|
222 | 236 | {
|
223 | 237 | ctx->stackTimer()->start(duration);
|
@@ -324,6 +338,14 @@ extern "C" void looks_previouscostume(Target *target)
|
324 | 338 | looks_set_costume_by_index(target, target->costumeIndex() - 1);
|
325 | 339 | }
|
326 | 340 |
|
| 341 | +void looks_randomcostume(Target *target, IRandomGenerator *rng) |
| 342 | +{ |
| 343 | + size_t count = target->costumes().size(); |
| 344 | + |
| 345 | + if (count > 1) |
| 346 | + looks_set_costume_by_index(target, rng->randintExcept(0, count - 1, target->costumeIndex())); // exclude current costume |
| 347 | +} |
| 348 | + |
327 | 349 | extern "C" void looks_switchcostumeto(Target *target, const ValueData *costume)
|
328 | 350 | {
|
329 | 351 | // https://github.com/scratchfoundation/scratch-vm/blob/8dbcc1fc8f8d8c4f1e40629fe8a388149d6dfd1c/src/blocks/scratch3_looks.js#L389-L413
|
@@ -356,3 +378,50 @@ extern "C" void looks_switchcostumeto(Target *target, const ValueData *costume)
|
356 | 378 | looks_set_costume_by_index(target, value_toLong(costume) - 1);
|
357 | 379 | }
|
358 | 380 | }
|
| 381 | + |
| 382 | +extern "C" void looks_start_backdrop_scripts(ExecutionContext *ctx, bool wait) |
| 383 | +{ |
| 384 | + IEngine *engine = ctx->engine(); |
| 385 | + Stage *stage = engine->stage(); |
| 386 | + Costume *backdrop = stage->currentCostume().get(); |
| 387 | + |
| 388 | + if (backdrop) |
| 389 | + engine->startBackdropScripts(backdrop->broadcast(), ctx->thread(), wait); |
| 390 | +} |
| 391 | + |
| 392 | +extern "C" void looks_switchbackdropto(ExecutionContext *ctx, const ValueData *backdrop) |
| 393 | +{ |
| 394 | + Stage *stage = ctx->engine()->stage(); |
| 395 | + |
| 396 | + // https://github.com/scratchfoundation/scratch-vm/blob/8dbcc1fc8f8d8c4f1e40629fe8a388149d6dfd1c/src/blocks/scratch3_looks.js#L389-L413 |
| 397 | + if (!value_isString(backdrop)) { |
| 398 | + // Numbers should be treated as costume indices, always |
| 399 | + if (value_isNaN(backdrop) || value_isInfinity(backdrop) || value_isNegativeInfinity(backdrop)) |
| 400 | + stage->setCostumeIndex(0); |
| 401 | + else |
| 402 | + looks_set_costume_by_index(stage, value_toLong(backdrop) - 1); |
| 403 | + } else { |
| 404 | + // Strings should be treated as costume names, where possible |
| 405 | + // TODO: Use UTF-16 in Target |
| 406 | + // StringPtr *nameStr = value_toStringPtr(backdrop); |
| 407 | + std::string nameStr; |
| 408 | + value_toString(backdrop, &nameStr); |
| 409 | + const int costumeIndex = stage->findCostume(nameStr); |
| 410 | + |
| 411 | + auto it = std::find_if(nameStr.begin(), nameStr.end(), [](char c) { return !std::isspace(c); }); |
| 412 | + bool isWhiteSpace = (it == nameStr.end()); |
| 413 | + |
| 414 | + if (costumeIndex != -1) |
| 415 | + looks_set_costume_by_index(stage, costumeIndex); |
| 416 | + else if (nameStr == "next backdrop") |
| 417 | + looks_nextcostume(stage); |
| 418 | + else if (nameStr == "previous backdrop") |
| 419 | + looks_previouscostume(stage); |
| 420 | + else if (nameStr == "random backdrop") { |
| 421 | + looks_randomcostume(stage, ctx->rng()); |
| 422 | + // Try to cast the string to a number (and treat it as a costume index) |
| 423 | + // Pure whitespace should not be treated as a number |
| 424 | + } else if (value_isValidNumber(backdrop) && !isWhiteSpace) |
| 425 | + looks_set_costume_by_index(stage, value_toLong(backdrop) - 1); |
| 426 | + } |
| 427 | +} |
0 commit comments