33#include < scratchcpp/iengine.h>
44#include < scratchcpp/compiler.h>
55#include < scratchcpp/sprite.h>
6+ #include < scratchcpp/stage.h>
7+ #include < scratchcpp/input.h>
8+ #include < scratchcpp/field.h>
9+ #include < scratchcpp/costume.h>
610
711#include " looksblocks.h"
12+ #include " ../engine/internal/randomgenerator.h"
813
914using namespace libscratchcpp ;
1015
16+ IRandomGenerator *LooksBlocks::rng = nullptr ;
17+
1118std::string LooksBlocks::name () const
1219{
1320 return " Looks" ;
@@ -21,10 +28,25 @@ void LooksBlocks::registerBlocks(IEngine *engine)
2128 engine->addCompileFunction (this , " looks_changesizeby" , &compileChangeSizeBy);
2229 engine->addCompileFunction (this , " looks_setsizeto" , &compileSetSizeTo);
2330 engine->addCompileFunction (this , " looks_size" , &compileSize);
31+ engine->addCompileFunction (this , " looks_switchcostumeto" , &compileSwitchCostumeTo);
32+ engine->addCompileFunction (this , " looks_nextcostume" , &compileNextCostume);
33+ engine->addCompileFunction (this , " looks_switchbackdropto" , &compileSwitchBackdropTo);
34+ engine->addCompileFunction (this , " looks_nextbackdrop" , &compileNextBackdrop);
35+ engine->addCompileFunction (this , " looks_costumenumbername" , &compileCostumeNumberName);
36+ engine->addCompileFunction (this , " looks_backdropnumbername" , &compileBackdropNumberName);
2437
2538 // Inputs
2639 engine->addInput (this , " CHANGE" , CHANGE);
2740 engine->addInput (this , " SIZE" , SIZE);
41+ engine->addInput (this , " COSTUME" , COSTUME);
42+ engine->addInput (this , " BACKDROP" , BACKDROP);
43+
44+ // Fields
45+ engine->addField (this , " NUMBER_NAME" , NUMBER_NAME);
46+
47+ // Field values
48+ engine->addFieldValue (this , " number" , Number);
49+ engine->addFieldValue (this , " name" , Name);
2850}
2951
3052void LooksBlocks::compileShow (Compiler *compiler)
@@ -54,6 +76,122 @@ void LooksBlocks::compileSize(Compiler *compiler)
5476 compiler->addFunctionCall (&size);
5577}
5678
79+ void LooksBlocks::compileSwitchCostumeTo (Compiler *compiler)
80+ {
81+ Target *target = compiler->target ();
82+
83+ if (!target)
84+ return ;
85+
86+ Input *input = compiler->input (COSTUME);
87+
88+ if (input->type () != Input::Type::ObscuredShadow) {
89+ assert (input->pointsToDropdownMenu ());
90+ std::string value = input->selectedMenuItem ();
91+ int index = target->findCostume (value);
92+
93+ if (index == -1 ) {
94+ if (value == " next costume" )
95+ compiler->addFunctionCall (&nextCostume);
96+ else if (value == " previous costume" )
97+ compiler->addFunctionCall (&previousCostume);
98+ else {
99+ Value v (value);
100+
101+ if (v.type () == Value::Type::Integer) {
102+ compiler->addConstValue (v.toLong () - 1 );
103+ compiler->addFunctionCall (&switchCostumeToByIndex);
104+ }
105+ }
106+ } else {
107+ compiler->addConstValue (index);
108+ compiler->addFunctionCall (&switchCostumeToByIndex);
109+ }
110+ } else {
111+ compiler->addInput (input);
112+ compiler->addFunctionCall (&switchCostumeTo);
113+ }
114+ }
115+
116+ void LooksBlocks::compileNextCostume (Compiler *compiler)
117+ {
118+ compiler->addFunctionCall (&nextCostume);
119+ }
120+
121+ void LooksBlocks::compileSwitchBackdropTo (Compiler *compiler)
122+ {
123+ Stage *stage = compiler->engine ()->stage ();
124+
125+ if (!stage)
126+ return ;
127+
128+ Input *input = compiler->input (BACKDROP);
129+
130+ if (input->type () != Input::Type::ObscuredShadow) {
131+ assert (input->pointsToDropdownMenu ());
132+ std::string value = input->selectedMenuItem ();
133+ int index = stage->findCostume (value);
134+
135+ if (index == -1 ) {
136+ if (value == " next backdrop" )
137+ compiler->addFunctionCall (&nextBackdrop);
138+ else if (value == " previous backdrop" )
139+ compiler->addFunctionCall (&previousBackdrop);
140+ else if (value == " random backdrop" )
141+ compiler->addFunctionCall (&randomBackdrop);
142+ else {
143+ Value v (value);
144+
145+ if (v.type () == Value::Type::Integer) {
146+ compiler->addConstValue (v.toLong () - 1 );
147+ compiler->addFunctionCall (&switchBackdropToByIndex);
148+ }
149+ }
150+ } else {
151+ compiler->addConstValue (index);
152+ compiler->addFunctionCall (&switchBackdropToByIndex);
153+ }
154+ } else {
155+ compiler->addInput (input);
156+ compiler->addFunctionCall (&switchBackdropTo);
157+ }
158+ }
159+
160+ void LooksBlocks::compileNextBackdrop (Compiler *compiler)
161+ {
162+ compiler->addFunctionCall (&nextBackdrop);
163+ }
164+
165+ void LooksBlocks::compileCostumeNumberName (Compiler *compiler)
166+ {
167+ int option = compiler->field (NUMBER_NAME)->specialValueId ();
168+
169+ switch (option) {
170+ case Number:
171+ compiler->addFunctionCall (&costumeNumber);
172+ break ;
173+
174+ case Name:
175+ compiler->addFunctionCall (&costumeName);
176+ break ;
177+ }
178+ }
179+
180+ void LooksBlocks::compileBackdropNumberName (Compiler *compiler)
181+ {
182+ int option = compiler->field (NUMBER_NAME)->specialValueId ();
183+
184+ switch (option) {
185+ case Number:
186+ compiler->addFunctionCall (&backdropNumber);
187+ break ;
188+
189+ case Name:
190+ compiler->addFunctionCall (&backdropName);
191+ break ;
192+ }
193+ }
194+
57195unsigned int LooksBlocks::show (VirtualMachine *vm)
58196{
59197 Sprite *sprite = dynamic_cast <Sprite *>(vm->target ());
@@ -105,3 +243,184 @@ unsigned int LooksBlocks::size(VirtualMachine *vm)
105243
106244 return 0 ;
107245}
246+
247+ void LooksBlocks::setCostumeByIndex (Target *target, long index)
248+ {
249+ // TODO: Remove this (#248)
250+ std::size_t costumeCount = target->costumes ().size ();
251+ if (index < 0 || index >= costumeCount) {
252+ if (index < 0 )
253+ index = std::fmod (costumeCount + std::fmod (index, -costumeCount), costumeCount);
254+ else
255+ index = std::fmod (index, costumeCount);
256+ }
257+
258+ target->setCurrentCostume (index + 1 );
259+ }
260+
261+ unsigned int LooksBlocks::switchCostumeToByIndex (VirtualMachine *vm)
262+ {
263+ if (Target *target = vm->target ())
264+ setCostumeByIndex (target, vm->getInput (0 , 1 )->toLong ());
265+
266+ return 1 ;
267+ }
268+
269+ unsigned int LooksBlocks::switchCostumeTo (VirtualMachine *vm)
270+ {
271+ Target *target = vm->target ();
272+
273+ if (!target)
274+ return 1 ;
275+
276+ const Value *name = vm->getInput (0 , 1 );
277+ std::string nameStr = name->toString ();
278+ int index = target->findCostume (nameStr);
279+
280+ if (index == -1 ) {
281+ if (nameStr == " next costume" )
282+ nextCostume (vm);
283+ else if (nameStr == " previous costume" )
284+ previousCostume (vm);
285+ else {
286+ if (name->type () == Value::Type::Integer)
287+ setCostumeByIndex (target, name->toLong () - 1 );
288+ }
289+ } else
290+ setCostumeByIndex (target, index);
291+
292+ return 1 ;
293+ }
294+
295+ unsigned int LooksBlocks::nextCostume (VirtualMachine *vm)
296+ {
297+ if (Target *target = vm->target ())
298+ setCostumeByIndex (target, target->currentCostume ());
299+
300+ return 0 ;
301+ }
302+
303+ unsigned int LooksBlocks::previousCostume (VirtualMachine *vm)
304+ {
305+ if (Target *target = vm->target ())
306+ setCostumeByIndex (target, target->currentCostume () - 2 );
307+
308+ return 0 ;
309+ }
310+
311+ unsigned int LooksBlocks::switchBackdropToByIndex (VirtualMachine *vm)
312+ {
313+ if (Stage *stage = vm->engine ()->stage ())
314+ setCostumeByIndex (stage, vm->getInput (0 , 1 )->toLong ());
315+
316+ return 1 ;
317+ }
318+
319+ unsigned int LooksBlocks::switchBackdropTo (VirtualMachine *vm)
320+ {
321+ Stage *stage = vm->engine ()->stage ();
322+
323+ if (!stage)
324+ return 1 ;
325+
326+ const Value *name = vm->getInput (0 , 1 );
327+ std::string nameStr = name->toString ();
328+ int index = stage->findCostume (nameStr);
329+
330+ if (index == -1 ) {
331+ if (nameStr == " next backdrop" )
332+ nextBackdrop (vm);
333+ else if (nameStr == " previous backdrop" )
334+ previousBackdrop (vm);
335+ else if (nameStr == " random backdrop" ) {
336+ randomBackdrop (vm);
337+ } else {
338+ if (name->type () == Value::Type::Integer)
339+ setCostumeByIndex (stage, name->toLong () - 1 );
340+ }
341+ } else
342+ setCostumeByIndex (stage, index);
343+
344+ return 1 ;
345+ }
346+
347+ unsigned int LooksBlocks::nextBackdrop (VirtualMachine *vm)
348+ {
349+ if (Stage *stage = vm->engine ()->stage ())
350+ setCostumeByIndex (stage, stage->currentCostume ());
351+
352+ return 0 ;
353+ }
354+
355+ unsigned int LooksBlocks::previousBackdrop (VirtualMachine *vm)
356+ {
357+ if (Stage *stage = vm->engine ()->stage ())
358+ setCostumeByIndex (stage, stage->currentCostume () - 2 );
359+
360+ return 0 ;
361+ }
362+
363+ unsigned int LooksBlocks::randomBackdrop (VirtualMachine *vm)
364+ {
365+ if (!rng)
366+ rng = RandomGenerator::instance ().get ();
367+
368+ if (Stage *stage = vm->engine ()->stage ()) {
369+ std::size_t count = stage->costumes ().size ();
370+
371+ if (count > 0 )
372+ stage->setCurrentCostume (rng->randint (1 , count));
373+ }
374+
375+ return 0 ;
376+ }
377+
378+ unsigned int LooksBlocks::costumeNumber (VirtualMachine *vm)
379+ {
380+ if (Target *target = vm->target ())
381+ vm->addReturnValue (target->currentCostume ());
382+ else
383+ vm->addReturnValue (0 );
384+
385+ return 0 ;
386+ }
387+
388+ unsigned int LooksBlocks::costumeName (VirtualMachine *vm)
389+ {
390+ if (Target *target = vm->target ()) {
391+ auto costume = target->costumeAt (target->currentCostume () - 1 );
392+
393+ if (costume)
394+ vm->addReturnValue (costume->name ());
395+ else
396+ vm->addReturnValue (" " );
397+ } else
398+ vm->addReturnValue (" " );
399+
400+ return 0 ;
401+ }
402+
403+ unsigned int LooksBlocks::backdropNumber (VirtualMachine *vm)
404+ {
405+ if (Stage *stage = vm->engine ()->stage ())
406+ vm->addReturnValue (stage->currentCostume ());
407+ else
408+ vm->addReturnValue (0 );
409+
410+ return 0 ;
411+ }
412+
413+ unsigned int LooksBlocks::backdropName (VirtualMachine *vm)
414+ {
415+ if (Stage *stage = vm->engine ()->stage ()) {
416+ auto costume = stage->costumeAt (stage->currentCostume () - 1 );
417+
418+ if (costume)
419+ vm->addReturnValue (costume->name ());
420+ else
421+ vm->addReturnValue (" " );
422+ } else
423+ vm->addReturnValue (" " );
424+
425+ return 0 ;
426+ }
0 commit comments