+27
-7
src/main/java/leap/s3me/App.java
+27
-7
src/main/java/leap/s3me/App.java
···
1
package leap.s3me;
2
3
-
import gnu.classpath.java.util.zip.ZipInputStream;
4
-
import java.io.ByteArrayInputStream;
5
-
import gnu.classpath.java.util.zip.ZipEntry;
6
import java.io.InputStream;
7
-
import java.io.ByteArrayOutputStream;
8
import javax.microedition.io.Connector;
9
import javax.microedition.io.file.FileConnection;
10
import javax.microedition.lcdui.Display;
11
-
import javax.microedition.lcdui.Form;
12
-
import javax.microedition.lcdui.StringItem;
13
import javax.microedition.midlet.MIDlet;
14
15
import cc.nnproject.json.JSON;
···
86
byte[] buffer = null;
87
if ((buffer = Unzip.extractFileToBytes("project.json")) != null) {
88
JSONObject obj = JSON.getObject(new String(buffer));
89
-
Interpret.executor.registerHandlers();
90
Interpret.loadSprites(obj);
91
System.out.println("Project width: " + String.valueOf(Scratch.projectWidth));
92
System.out.println("Project height: " + String.valueOf(Scratch.projectHeight));
93
System.out.println("Project FPS: " + String.valueOf(Scratch.FPS));
94
}
95
mainLoop.start();
96
} catch (Exception e) {
97
e.printStackTrace();
98
} finally {
···
112
synchronized (this) {
113
Scratch.paused = true;
114
}
115
}
116
}
···
1
package leap.s3me;
2
3
+
import java.io.ByteArrayOutputStream;
4
import java.io.InputStream;
5
+
6
import javax.microedition.io.Connector;
7
import javax.microedition.io.file.FileConnection;
8
+
import javax.microedition.lcdui.Command;
9
+
import javax.microedition.lcdui.CommandListener;
10
import javax.microedition.lcdui.Display;
11
+
import javax.microedition.lcdui.Displayable;
12
+
import javax.microedition.lcdui.TextBox;
13
+
import javax.microedition.lcdui.TextField;
14
import javax.microedition.midlet.MIDlet;
15
16
import cc.nnproject.json.JSON;
···
87
byte[] buffer = null;
88
if ((buffer = Unzip.extractFileToBytes("project.json")) != null) {
89
JSONObject obj = JSON.getObject(new String(buffer));
90
Interpret.loadSprites(obj);
91
System.out.println("Project width: " + String.valueOf(Scratch.projectWidth));
92
System.out.println("Project height: " + String.valueOf(Scratch.projectHeight));
93
System.out.println("Project FPS: " + String.valueOf(Scratch.FPS));
94
}
95
mainLoop.start();
96
+
App.display.setCurrent(App.render);
97
} catch (Exception e) {
98
e.printStackTrace();
99
} finally {
···
113
synchronized (this) {
114
Scratch.paused = true;
115
}
116
+
}
117
+
118
+
public void showAskAndWaitInput() {
119
+
final TextBox inputField = new TextBox(Scratch.inputQuestion, "", -1, TextField.ANY);
120
+
Command okCommand = new Command("OK", Command.OK, 1);
121
+
122
+
inputField.addCommand(okCommand);
123
+
inputField.setCommandListener(new CommandListener() {
124
+
public void commandAction(Command c, Displayable d) {
125
+
synchronized(App.context) {
126
+
Interpret.answer = inputField.getString();
127
+
Scratch.awaitingUserInput = false;
128
+
display.setCurrent(render);
129
+
App.context.notifyAll();
130
+
}
131
+
}
132
+
});
133
+
134
+
display.setCurrent(inputField);
135
}
136
}
-3
src/main/java/leap/s3me/Image.java
-3
src/main/java/leap/s3me/Image.java
+12
-16
src/main/java/leap/s3me/Interpret.java
+12
-16
src/main/java/leap/s3me/Interpret.java
···
1
package leap.s3me;
2
3
-
import java.util.Vector;
4
import java.util.Enumeration;
5
import java.util.Hashtable;
6
7
-
import cc.nnproject.json.AbstractJSON;
8
import cc.nnproject.json.JSON;
9
import cc.nnproject.json.JSONArray;
10
import cc.nnproject.json.JSONObject;
···
19
import leap.s3me.scratch.Monitor;
20
import leap.s3me.scratch.ParsedField;
21
import leap.s3me.scratch.ParsedInput;
22
-
import leap.s3me.scratch.Sprite;
23
import leap.s3me.scratch.Sound;
24
import leap.s3me.scratch.Value;
25
import leap.s3me.scratch.Variable;
26
···
276
Block block = new Block();
277
block.id = id;
278
if (data.has("opcode")) {
279
-
block.opcode = data.getString("opcode", "");
280
if (block.opcode.equals("event_whenthisspriteclicked"))
281
sprite.shouldDoSpriteClick = true;
282
}
283
-
block.next = data.getString("next", null);
284
block.parent = data.getString("parent", "null");
285
if (data.has("fields")) {
286
JSONObject fields = data.getObject("fields");
···
331
block.topLevel = data.getBoolean("topLevel", false);
332
block.shadow = data.getBoolean("shadow", false);
333
if (data.has("mutation")) {
334
-
if (data.getObject("mutation").has("proccode"))
335
-
block.customBlockId = data.getObject("mutation").getString("proccode");
336
-
else
337
-
block.customBlockId = "";
338
}
339
340
sprite.blocks.put(id, block);
···
595
}
596
597
public static Block findBlock(String blockID) {
598
-
if (blockLookup.contains(blockID))
599
return (Block)blockLookup.get(blockID);
600
return null;
601
}
···
629
}
630
}
631
632
-
currentBlock = findBlock(currentBlock.next);
633
}
634
-
System.out.println(outID == null);
635
-
System.out.println(outID.toString() == null);
636
-
System.out.println(outID.toString().equals(""));
637
-
System.out.println(outID.toString().length() > 0);
638
-
System.out.println(outID.toString());
639
return blockChain;
640
}
641
···
1
package leap.s3me;
2
3
import java.util.Enumeration;
4
import java.util.Hashtable;
5
+
import java.util.Vector;
6
7
import cc.nnproject.json.JSON;
8
import cc.nnproject.json.JSONArray;
9
import cc.nnproject.json.JSONObject;
···
18
import leap.s3me.scratch.Monitor;
19
import leap.s3me.scratch.ParsedField;
20
import leap.s3me.scratch.ParsedInput;
21
import leap.s3me.scratch.Sound;
22
+
import leap.s3me.scratch.Sprite;
23
import leap.s3me.scratch.Value;
24
import leap.s3me.scratch.Variable;
25
···
275
Block block = new Block();
276
block.id = id;
277
if (data.has("opcode")) {
278
+
block.opcode = data.getString("opcode");
279
if (block.opcode.equals("event_whenthisspriteclicked"))
280
sprite.shouldDoSpriteClick = true;
281
}
282
+
if (data.has("next") && !data.isNull("next")) {
283
+
block.next = data.getString("next");
284
+
}
285
block.parent = data.getString("parent", "null");
286
if (data.has("fields")) {
287
JSONObject fields = data.getObject("fields");
···
332
block.topLevel = data.getBoolean("topLevel", false);
333
block.shadow = data.getBoolean("shadow", false);
334
if (data.has("mutation")) {
335
+
block.customBlockId = data.getObject("mutation").getString("proccode", "");
336
}
337
338
sprite.blocks.put(id, block);
···
593
}
594
595
public static Block findBlock(String blockID) {
596
+
if (blockLookup.containsKey(blockID))
597
return (Block)blockLookup.get(blockID);
598
return null;
599
}
···
627
}
628
}
629
630
+
if (currentBlock.next != null)
631
+
currentBlock = findBlock(currentBlock.next);
632
+
else
633
+
currentBlock = null;
634
}
635
return blockChain;
636
}
637
+2
-6
src/main/java/leap/s3me/Render.java
+2
-6
src/main/java/leap/s3me/Render.java
···
1
package leap.s3me;
2
3
-
import java.io.IOException;
4
import java.util.Hashtable;
5
import java.util.Vector;
6
7
import javax.microedition.lcdui.Canvas;
8
-
import javax.microedition.lcdui.Font;
9
import javax.microedition.lcdui.Graphics;
10
import javax.microedition.lcdui.Image;
11
import javax.microedition.lcdui.game.Sprite;
12
13
import leap.s3me.scratch.BlockExecutor;
14
import leap.s3me.scratch.Costume;
15
-
import leap.s3me.scratch.Monitor;
16
import leap.s3me.scratch.Input;
17
18
public class Render extends Canvas {
19
public int windowWidth;
20
public int windowHeight;
21
22
public Vector visibleVariables;
23
-
private Hashtable images = new Hashtable();
24
private Image penLayer;
25
26
public Render() {
···
97
currentSprite.rotationCenterX = (int)costume.rotationCenterX;
98
currentSprite.rotationCenterY = (int)costume.rotationCenterY;
99
100
-
// First, get the base image to determine its original dimensions
101
leap.s3me.Image baseImageWrapper = leap.s3me.Image.getImage(costume);
102
if (baseImageWrapper != null && baseImageWrapper.image != null) {
103
int imgWidth = baseImageWrapper.image.getWidth();
···
135
sprite.setTransform(transform);
136
sprite.setPosition(renderX, renderY);
137
sprite.paint(g);
138
-
139
} else {
140
g.setColor(0, 0, 0);
141
int x = (int)((currentSprite.xPosition * scale) + (windowWidth / 2));
···
1
package leap.s3me;
2
3
import java.util.Hashtable;
4
import java.util.Vector;
5
6
import javax.microedition.lcdui.Canvas;
7
import javax.microedition.lcdui.Graphics;
8
import javax.microedition.lcdui.Image;
9
import javax.microedition.lcdui.game.Sprite;
10
11
import leap.s3me.scratch.BlockExecutor;
12
import leap.s3me.scratch.Costume;
13
import leap.s3me.scratch.Input;
14
+
import leap.s3me.scratch.Monitor;
15
16
public class Render extends Canvas {
17
public int windowWidth;
18
public int windowHeight;
19
20
public Vector visibleVariables;
21
+
public Hashtable images = new Hashtable();
22
private Image penLayer;
23
24
public Render() {
···
95
currentSprite.rotationCenterX = (int)costume.rotationCenterX;
96
currentSprite.rotationCenterY = (int)costume.rotationCenterY;
97
98
leap.s3me.Image baseImageWrapper = leap.s3me.Image.getImage(costume);
99
if (baseImageWrapper != null && baseImageWrapper.image != null) {
100
int imgWidth = baseImageWrapper.image.getWidth();
···
132
sprite.setTransform(transform);
133
sprite.setPosition(renderX, renderY);
134
sprite.paint(g);
135
} else {
136
g.setColor(0, 0, 0);
137
int x = (int)((currentSprite.xPosition * scale) + (windowWidth / 2));
+7
-2
src/main/java/leap/s3me/Scratch.java
+7
-2
src/main/java/leap/s3me/Scratch.java
···
17
public static boolean miscellaneousLimits = true;
18
public static boolean paused = false;
19
public static boolean shouldStop = false;
20
21
public static double counter = 0;
22
···
35
while (paused) {
36
App.context.wait();
37
}
38
}
39
40
Input.update();
41
BlockExecutor.runRepeatBlocks();
42
BlockExecutor.runBroadcasts();
43
App.render.repaint();
44
-
App.display.setCurrent(App.render);
45
46
-
//Thread.sleep(1000 / FPS);
47
} catch (Exception e) {
48
e.printStackTrace();
49
}
···
17
public static boolean miscellaneousLimits = true;
18
public static boolean paused = false;
19
public static boolean shouldStop = false;
20
+
public static boolean awaitingUserInput = false;
21
+
public static String inputQuestion = "";
22
23
public static double counter = 0;
24
···
37
while (paused) {
38
App.context.wait();
39
}
40
+
if (awaitingUserInput) {
41
+
App.context.showAskAndWaitInput();
42
+
App.context.wait();
43
+
}
44
}
45
46
Input.update();
47
BlockExecutor.runRepeatBlocks();
48
BlockExecutor.runBroadcasts();
49
App.render.repaint();
50
51
+
Thread.sleep(1000 / FPS);
52
} catch (Exception e) {
53
e.printStackTrace();
54
}
+30
-5
src/main/java/leap/s3me/scratch/BlockExecutor.java
+30
-5
src/main/java/leap/s3me/scratch/BlockExecutor.java
···
16
import leap.s3me.scratch.blocks.ControlBlocks;
17
import leap.s3me.scratch.blocks.DataBlocks;
18
import leap.s3me.scratch.blocks.OperatorBlocks;
19
import leap.s3me.scratch.blocks.ProcedureBlocks;
20
21
public class BlockExecutor {
···
40
registerHandlers();
41
}
42
43
-
public void registerHandlers() {
44
// motion
45
handlers.put("motion_movesteps", new MotionBlocks.MoveSteps());
46
handlers.put("motion_gotoxy", new MotionBlocks.GoToXY());
···
143
valueHandlers.put("data_lengthoflist", new DataBlocks.LengthOfList());
144
valueHandlers.put("data_listcontainsitem", new DataBlocks.ListContainsItem());
145
146
// procedures / arguments
147
handlers.put("procedures_call", new ProcedureBlocks.Call());
148
handlers.put("procedures_definition", new ProcedureBlocks.Definition());
149
valueHandlers.put("argument_reporter_string_number", new ProcedureBlocks.StringNumber());
150
valueHandlers.put("argument_reporter_boolean", new ProcedureBlocks.BooleanArgument());
151
}
152
153
public Vector runBlock(Block block, Sprite sprite, boolean[] withoutScreenRefresh, boolean fromRepeat) {
···
205
206
private int executeBlock(Block block, Sprite sprite, boolean[] withoutScreenRefresh, boolean fromRepeat) {
207
BlockHandler handler = (BlockHandler)handlers.get(block.opcode);
208
-
System.out.println("Handler: " + block.opcode);
209
if (handler != null) {
210
return handler.run(block, sprite, withoutScreenRefresh, fromRepeat);
211
}
···
215
public Value getBlockValue(Block block, Sprite sprite) {
216
if (block == null) return new Value();
217
ValueBlockHandler handler = (ValueBlockHandler)valueHandlers.get(block.opcode);
218
-
System.out.println("Value handler: " + block.opcode);
219
if (handler != null) {
220
return handler.run(block, sprite);
221
}
···
223
}
224
225
public static Vector runAllBlocksByOpcode(String opcodeToFind) {
226
-
System.out.println("Running all " + opcodeToFind + " blocks");
227
Vector blocksRun = new Vector();
228
for (int i = 0; i < Interpret.sprites.size(); i++) {
229
Sprite currentSprite = (Sprite)Interpret.sprites.elementAt(i);
···
562
}
563
564
public static boolean hasActiveRepeats(Sprite sprite, String blockChainID) {
565
-
if (sprite.blockChains.contains(blockChainID)) {
566
if (!((BlockChain)sprite.blockChains.get(blockChainID)).blocksToRepeat.isEmpty()) return true;
567
}
568
return false;
···
16
import leap.s3me.scratch.blocks.ControlBlocks;
17
import leap.s3me.scratch.blocks.DataBlocks;
18
import leap.s3me.scratch.blocks.OperatorBlocks;
19
+
import leap.s3me.scratch.blocks.SensingBlocks;
20
import leap.s3me.scratch.blocks.ProcedureBlocks;
21
22
public class BlockExecutor {
···
41
registerHandlers();
42
}
43
44
+
private void registerHandlers() {
45
// motion
46
handlers.put("motion_movesteps", new MotionBlocks.MoveSteps());
47
handlers.put("motion_gotoxy", new MotionBlocks.GoToXY());
···
144
valueHandlers.put("data_lengthoflist", new DataBlocks.LengthOfList());
145
valueHandlers.put("data_listcontainsitem", new DataBlocks.ListContainsItem());
146
147
+
// sensing
148
+
handlers.put("sensing_resettimer", new SensingBlocks.ResetTimer());
149
+
handlers.put("sensing_askandwait", new SensingBlocks.AskAndWait());
150
+
handlers.put("sensing_setdragmode", new SensingBlocks.SetDragMode());
151
+
valueHandlers.put("sensing_timer", new SensingBlocks.SensingTimer());
152
+
valueHandlers.put("sensing_of", new SensingBlocks.Of());
153
+
valueHandlers.put("sensing_mousex", new SensingBlocks.MouseX());
154
+
valueHandlers.put("sensing_mousey", new SensingBlocks.MouseY());
155
+
valueHandlers.put("sensing_distanceto", new SensingBlocks.DistanceTo());
156
+
valueHandlers.put("sensing_dayssince2000", new SensingBlocks.DaysSince2000());
157
+
valueHandlers.put("sensing_current", new SensingBlocks.Current());
158
+
valueHandlers.put("sensing_answer", new SensingBlocks.SensingAnswer());
159
+
valueHandlers.put("sensing_keypressed", new SensingBlocks.KeyPressed());
160
+
valueHandlers.put("sensing_touchingobject", new SensingBlocks.TouchingObject());
161
+
valueHandlers.put("sensing_mousedown", new SensingBlocks.MouseDown());
162
+
valueHandlers.put("sensing_username", new SensingBlocks.Username());
163
+
164
// procedures / arguments
165
handlers.put("procedures_call", new ProcedureBlocks.Call());
166
handlers.put("procedures_definition", new ProcedureBlocks.Definition());
167
valueHandlers.put("argument_reporter_string_number", new ProcedureBlocks.StringNumber());
168
valueHandlers.put("argument_reporter_boolean", new ProcedureBlocks.BooleanArgument());
169
+
170
+
// Other (Don't know where else to put these)
171
+
valueHandlers.put("matrix", new ValueBlockHandler() {
172
+
public Value run(Block block, Sprite sprite) {
173
+
return new Value(Scratch.getFieldValue(block, "MATRIX"));
174
+
}
175
+
});
176
}
177
178
public Vector runBlock(Block block, Sprite sprite, boolean[] withoutScreenRefresh, boolean fromRepeat) {
···
230
231
private int executeBlock(Block block, Sprite sprite, boolean[] withoutScreenRefresh, boolean fromRepeat) {
232
BlockHandler handler = (BlockHandler)handlers.get(block.opcode);
233
+
//System.out.println("Handler: " + block.opcode);
234
if (handler != null) {
235
return handler.run(block, sprite, withoutScreenRefresh, fromRepeat);
236
}
···
240
public Value getBlockValue(Block block, Sprite sprite) {
241
if (block == null) return new Value();
242
ValueBlockHandler handler = (ValueBlockHandler)valueHandlers.get(block.opcode);
243
+
//System.out.println("Value handler: " + block.opcode);
244
if (handler != null) {
245
return handler.run(block, sprite);
246
}
···
248
}
249
250
public static Vector runAllBlocksByOpcode(String opcodeToFind) {
251
+
//System.out.println("Running all " + opcodeToFind + " blocks");
252
Vector blocksRun = new Vector();
253
for (int i = 0; i < Interpret.sprites.size(); i++) {
254
Sprite currentSprite = (Sprite)Interpret.sprites.elementAt(i);
···
587
}
588
589
public static boolean hasActiveRepeats(Sprite sprite, String blockChainID) {
590
+
if (sprite.blockChains.containsKey(blockChainID)) {
591
if (!((BlockChain)sprite.blockChains.get(blockChainID)).blocksToRepeat.isEmpty()) return true;
592
}
593
return false;
+27
-6
src/main/java/leap/s3me/scratch/Sprite.java
+27
-6
src/main/java/leap/s3me/scratch/Sprite.java
···
4
import java.util.Hashtable;
5
import java.util.Map;
6
7
public class Sprite {
8
public String name;
9
public String id;
···
48
public Hashtable customBlocks = new Hashtable();
49
public Hashtable blockChains = new Hashtable();
50
51
public void clearAll() {
52
variables.clear();
53
blocks.clear();
···
63
64
public void copyFrom(Sprite other) {
65
this.name = other.name;
66
-
// Don't copy ID, clones get a new one
67
this.isStage = other.isStage;
68
this.draggable = other.draggable;
69
this.visible = other.visible;
···
79
this.brightnessEffect = other.brightnessEffect;
80
this.colorEffect = other.colorEffect;
81
82
-
// Deep copy collections to avoid shared state issues
83
this.variables = new Hashtable();
84
for (java.util.Enumeration e = other.variables.keys(); e.hasMoreElements();) {
85
-
String key = (String) e.nextElement();
86
-
// This assumes Variable has a copy constructor or similar method
87
-
// For now, we'll just share them, but this can be risky for non-global vars
88
-
this.variables.put(key, other.variables.get(key));
89
}
90
91
this.blocks = other.blocks;
···
96
this.broadcasts = other.broadcasts;
97
this.customBlocks = other.customBlocks;
98
this.blockChains = other.blockChains;
99
}
100
}
···
4
import java.util.Hashtable;
5
import java.util.Map;
6
7
+
import leap.s3me.Image;
8
+
9
public class Sprite {
10
public String name;
11
public String id;
···
50
public Hashtable customBlocks = new Hashtable();
51
public Hashtable blockChains = new Hashtable();
52
53
+
public Sprite() {}
54
+
55
+
public Sprite(Sprite other) {}
56
+
57
public void clearAll() {
58
variables.clear();
59
blocks.clear();
···
69
70
public void copyFrom(Sprite other) {
71
this.name = other.name;
72
this.isStage = other.isStage;
73
this.draggable = other.draggable;
74
this.visible = other.visible;
···
84
this.brightnessEffect = other.brightnessEffect;
85
this.colorEffect = other.colorEffect;
86
87
this.variables = new Hashtable();
88
for (java.util.Enumeration e = other.variables.keys(); e.hasMoreElements();) {
89
+
String key = (String)e.nextElement();
90
+
Variable originalVar = (Variable)other.variables.get(key);
91
+
this.variables.put(key, new Variable(originalVar));
92
}
93
94
this.blocks = other.blocks;
···
99
this.broadcasts = other.broadcasts;
100
this.customBlocks = other.customBlocks;
101
this.blockChains = other.blockChains;
102
+
}
103
+
104
+
public void loadCurrentCostume() {
105
+
if (costumes.isEmpty() || currentCostume >= costumes.size()) {
106
+
return;
107
+
}
108
+
109
+
Costume costume = (Costume)costumes.elementAt(currentCostume);
110
+
if (costume.id.equals(lastCostumeId)) {
111
+
return;
112
+
}
113
+
114
+
Image baseImageWrapper = Image.getImage(costume);
115
+
if (baseImageWrapper != null && baseImageWrapper.image != null) {
116
+
this.spriteWidth = baseImageWrapper.image.getWidth();
117
+
this.spriteHeight = baseImageWrapper.image.getHeight();
118
+
this.lastCostumeId = costume.id;
119
+
}
120
}
121
}
+15
src/main/java/leap/s3me/scratch/Value.java
+15
src/main/java/leap/s3me/scratch/Value.java
···
34
this.value = val;
35
}
36
37
+
/**
38
+
* Copy constructor for creating a deep copy of a Value object.
39
+
* This is crucial for cloning sprites to ensure variables are not shared.
40
+
* @param other The Value object to copy.
41
+
*/
42
+
public Value(Value other) {
43
+
if (other.value == null) {
44
+
this.value = null;
45
+
} else if (other.isColor()) {
46
+
this.value = new Color(((Color)other.value).hue, ((Color)other.value).saturation, ((Color)other.value).brightness);
47
+
} else {
48
+
this.value = other.value; // Immutable types (String, Integer, etc.) can be assigned directly.
49
+
}
50
+
}
51
+
52
public boolean isInteger() {
53
return value instanceof Integer;
54
}
+11
src/main/java/leap/s3me/scratch/Variable.java
+11
src/main/java/leap/s3me/scratch/Variable.java
···
4
public String id;
5
public String name;
6
public Value value;
7
+
8
+
public Variable() {}
9
+
10
+
/**
11
+
* Copy constructor for creating a deep copy of a Variable.
12
+
*/
13
+
public Variable(Variable other) {
14
+
this.id = other.id;
15
+
this.name = other.name;
16
+
this.value = new Value(other.value); // Use Value's copy constructor
17
+
}
18
}
+18
-18
src/main/java/leap/s3me/scratch/blocks/DataBlocks.java
+18
-18
src/main/java/leap/s3me/scratch/blocks/DataBlocks.java
···
109
110
Sprite targetSprite = null;
111
112
-
if (sprite.lists.contains(listID)) {
113
targetSprite = sprite;
114
} else {
115
for (int i = 0; i < Interpret.sprites.size(); i++) {
116
Sprite currentSprite = (Sprite)Interpret.sprites.elementAt(i);
117
-
if (currentSprite.isStage && sprite.lists.contains(listID)) {
118
targetSprite = currentSprite;
119
break;
120
}
···
134
135
Sprite targetSprite = null;
136
137
-
if (sprite.lists.contains(listID)) {
138
targetSprite = sprite;
139
} else {
140
for (int i = 0; i < Interpret.sprites.size(); i++) {
141
Sprite currentSprite = (Sprite)Interpret.sprites.elementAt(i);
142
-
if (currentSprite.isStage && sprite.lists.contains(listID)) {
143
targetSprite = currentSprite;
144
break;
145
}
···
181
182
Sprite targetSprite = null;
183
184
-
if (sprite.lists.contains(listID)) {
185
targetSprite = sprite;
186
} else {
187
for (int i = 0; i < Interpret.sprites.size(); i++) {
188
Sprite currentSprite = (Sprite)Interpret.sprites.elementAt(i);
189
-
if (currentSprite.isStage && sprite.lists.contains(listID)) {
190
targetSprite = currentSprite;
191
break;
192
}
···
209
210
Sprite targetSprite = null;
211
212
-
if (sprite.lists.contains(listID)) {
213
targetSprite = sprite;
214
} else {
215
for (int i = 0; i < Interpret.sprites.size(); i++) {
216
Sprite currentSprite = (Sprite)Interpret.sprites.elementAt(i);
217
-
if (currentSprite.isStage && sprite.lists.contains(listID)) {
218
targetSprite = currentSprite;
219
break;
220
}
···
257
258
Sprite targetSprite = null;
259
260
-
if (sprite.lists.contains(listID)) {
261
targetSprite = sprite;
262
} else {
263
for (int i = 0; i < Interpret.sprites.size(); i++) {
264
Sprite currentSprite = (Sprite)Interpret.sprites.elementAt(i);
265
-
if (currentSprite.isStage && sprite.lists.contains(listID)) {
266
targetSprite = currentSprite;
267
break;
268
}
···
305
306
Sprite targetSprite = null;
307
308
-
if (sprite.lists.contains(listID)) {
309
targetSprite = sprite;
310
} else {
311
for (int i = 0; i < Interpret.sprites.size(); i++) {
312
Sprite currentSprite = (Sprite)Interpret.sprites.elementAt(i);
313
-
if (currentSprite.isStage && sprite.lists.contains(listID)) {
314
targetSprite = currentSprite;
315
break;
316
}
···
344
345
Sprite targetSprite = null;
346
347
-
if (sprite.lists.contains(listID)) {
348
targetSprite = sprite;
349
} else {
350
for (int i = 0; i < Interpret.sprites.size(); i++) {
351
Sprite currentSprite = (Sprite)Interpret.sprites.elementAt(i);
352
-
if (currentSprite.isStage && sprite.lists.contains(listID)) {
353
targetSprite = currentSprite;
354
break;
355
}
···
376
377
Sprite targetSprite = null;
378
379
-
if (sprite.lists.contains(listID)) {
380
targetSprite = sprite;
381
} else {
382
for (int i = 0; i < Interpret.sprites.size(); i++) {
383
Sprite currentSprite = (Sprite)Interpret.sprites.elementAt(i);
384
-
if (currentSprite.isStage && sprite.lists.contains(listID)) {
385
targetSprite = currentSprite;
386
break;
387
}
···
403
404
Sprite targetSprite = null;
405
406
-
if (sprite.lists.contains(listID)) {
407
targetSprite = sprite;
408
} else {
409
for (int i = 0; i < Interpret.sprites.size(); i++) {
410
Sprite currentSprite = (Sprite)Interpret.sprites.elementAt(i);
411
-
if (currentSprite.isStage && sprite.lists.contains(listID)) {
412
targetSprite = currentSprite;
413
break;
414
}
···
109
110
Sprite targetSprite = null;
111
112
+
if (sprite.lists.containsKey(listID)) {
113
targetSprite = sprite;
114
} else {
115
for (int i = 0; i < Interpret.sprites.size(); i++) {
116
Sprite currentSprite = (Sprite)Interpret.sprites.elementAt(i);
117
+
if (currentSprite.isStage && sprite.lists.containsKey(listID)) {
118
targetSprite = currentSprite;
119
break;
120
}
···
134
135
Sprite targetSprite = null;
136
137
+
if (sprite.lists.containsKey(listID)) {
138
targetSprite = sprite;
139
} else {
140
for (int i = 0; i < Interpret.sprites.size(); i++) {
141
Sprite currentSprite = (Sprite)Interpret.sprites.elementAt(i);
142
+
if (currentSprite.isStage && sprite.lists.containsKey(listID)) {
143
targetSprite = currentSprite;
144
break;
145
}
···
181
182
Sprite targetSprite = null;
183
184
+
if (sprite.lists.containsKey(listID)) {
185
targetSprite = sprite;
186
} else {
187
for (int i = 0; i < Interpret.sprites.size(); i++) {
188
Sprite currentSprite = (Sprite)Interpret.sprites.elementAt(i);
189
+
if (currentSprite.isStage && sprite.lists.containsKey(listID)) {
190
targetSprite = currentSprite;
191
break;
192
}
···
209
210
Sprite targetSprite = null;
211
212
+
if (sprite.lists.containsKey(listID)) {
213
targetSprite = sprite;
214
} else {
215
for (int i = 0; i < Interpret.sprites.size(); i++) {
216
Sprite currentSprite = (Sprite)Interpret.sprites.elementAt(i);
217
+
if (currentSprite.isStage && sprite.lists.containsKey(listID)) {
218
targetSprite = currentSprite;
219
break;
220
}
···
257
258
Sprite targetSprite = null;
259
260
+
if (sprite.lists.containsKey(listID)) {
261
targetSprite = sprite;
262
} else {
263
for (int i = 0; i < Interpret.sprites.size(); i++) {
264
Sprite currentSprite = (Sprite)Interpret.sprites.elementAt(i);
265
+
if (currentSprite.isStage && sprite.lists.containsKey(listID)) {
266
targetSprite = currentSprite;
267
break;
268
}
···
305
306
Sprite targetSprite = null;
307
308
+
if (sprite.lists.containsKey(listID)) {
309
targetSprite = sprite;
310
} else {
311
for (int i = 0; i < Interpret.sprites.size(); i++) {
312
Sprite currentSprite = (Sprite)Interpret.sprites.elementAt(i);
313
+
if (currentSprite.isStage && sprite.lists.containsKey(listID)) {
314
targetSprite = currentSprite;
315
break;
316
}
···
344
345
Sprite targetSprite = null;
346
347
+
if (sprite.lists.containsKey(listID)) {
348
targetSprite = sprite;
349
} else {
350
for (int i = 0; i < Interpret.sprites.size(); i++) {
351
Sprite currentSprite = (Sprite)Interpret.sprites.elementAt(i);
352
+
if (currentSprite.isStage && sprite.lists.containsKey(listID)) {
353
targetSprite = currentSprite;
354
break;
355
}
···
376
377
Sprite targetSprite = null;
378
379
+
if (sprite.lists.containsKey(listID)) {
380
targetSprite = sprite;
381
} else {
382
for (int i = 0; i < Interpret.sprites.size(); i++) {
383
Sprite currentSprite = (Sprite)Interpret.sprites.elementAt(i);
384
+
if (currentSprite.isStage && sprite.lists.containsKey(listID)) {
385
targetSprite = currentSprite;
386
break;
387
}
···
403
404
Sprite targetSprite = null;
405
406
+
if (sprite.lists.containsKey(listID)) {
407
targetSprite = sprite;
408
} else {
409
for (int i = 0; i < Interpret.sprites.size(); i++) {
410
Sprite currentSprite = (Sprite)Interpret.sprites.elementAt(i);
411
+
if (currentSprite.isStage && sprite.lists.containsKey(listID)) {
412
targetSprite = currentSprite;
413
break;
414
}
+5
-5
src/main/java/leap/s3me/scratch/blocks/LooksBlocks.java
+5
-5
src/main/java/leap/s3me/scratch/blocks/LooksBlocks.java
···
16
public static class Show implements BlockExecutor.BlockHandler {
17
public int run(Block block, Sprite sprite, boolean[] withoutScreenRefresh, boolean fromRepeat) {
18
sprite.visible = true;
19
-
//Image.getImage((Costume)sprite.costumes.get(sprite.currentCostume));
20
return BlockExecutor.RESULT_CONTINUE;
21
}
22
}
···
59
}
60
}
61
62
-
//Image.getImage((Costume)sprite.costumes.get(sprite.currentCostume));
63
64
return BlockExecutor.RESULT_CONTINUE;
65
}
···
71
if (sprite.currentCostume >= sprite.costumes.size()) {
72
sprite.currentCostume = 0;
73
}
74
-
//Image.getImage((Costume)sprite.costumes.get(sprite.currentCostume));
75
return BlockExecutor.RESULT_CONTINUE;
76
}
77
}
···
111
}
112
}
113
114
-
//Image.getImage((Costume)currentSprite.costumes.get(currentSprite.currentCostume));
115
116
Enumeration e = currentSprite.blocks.keys();
117
while (e.hasMoreElements()) {
···
142
if (currentSprite.currentCostume >= currentSprite.costumes.size()) {
143
currentSprite.currentCostume = 0;
144
}
145
-
//Image.getImage((Costume)currentSprite.costumes.get(currentSprite.currentCostume));
146
147
Enumeration e = currentSprite.blocks.keys();
148
while (e.hasMoreElements()) {
···
16
public static class Show implements BlockExecutor.BlockHandler {
17
public int run(Block block, Sprite sprite, boolean[] withoutScreenRefresh, boolean fromRepeat) {
18
sprite.visible = true;
19
+
sprite.loadCurrentCostume();
20
return BlockExecutor.RESULT_CONTINUE;
21
}
22
}
···
59
}
60
}
61
62
+
sprite.loadCurrentCostume();
63
64
return BlockExecutor.RESULT_CONTINUE;
65
}
···
71
if (sprite.currentCostume >= sprite.costumes.size()) {
72
sprite.currentCostume = 0;
73
}
74
+
sprite.loadCurrentCostume();
75
return BlockExecutor.RESULT_CONTINUE;
76
}
77
}
···
111
}
112
}
113
114
+
currentSprite.loadCurrentCostume();
115
116
Enumeration e = currentSprite.blocks.keys();
117
while (e.hasMoreElements()) {
···
142
if (currentSprite.currentCostume >= currentSprite.costumes.size()) {
143
currentSprite.currentCostume = 0;
144
}
145
+
currentSprite.loadCurrentCostume();
146
147
Enumeration e = currentSprite.blocks.keys();
148
while (e.hasMoreElements()) {
+293
src/main/java/leap/s3me/scratch/blocks/SensingBlocks.java
+293
src/main/java/leap/s3me/scratch/blocks/SensingBlocks.java
···
···
1
+
package leap.s3me.scratch.blocks;
2
+
3
+
import java.util.Calendar;
4
+
import java.util.Enumeration;
5
+
import java.util.Vector;
6
+
7
+
import leap.s3me.App;
8
+
import leap.s3me.Interpret;
9
+
import leap.s3me.MathUtils;
10
+
import leap.s3me.Scratch;
11
+
import leap.s3me.scratch.Block;
12
+
import leap.s3me.scratch.BlockExecutor;
13
+
import leap.s3me.scratch.Costume;
14
+
import leap.s3me.scratch.Input;
15
+
import leap.s3me.scratch.Sprite;
16
+
import leap.s3me.scratch.Value;
17
+
import leap.s3me.scratch.Variable;
18
+
19
+
public class SensingBlocks {
20
+
public static class ProjectTimer {
21
+
private long startTime;
22
+
23
+
public ProjectTimer() {
24
+
startTime = System.currentTimeMillis();
25
+
}
26
+
27
+
public void start() {
28
+
startTime = System.currentTimeMillis();
29
+
}
30
+
31
+
public double getTimeMs() {
32
+
return System.currentTimeMillis() - startTime;
33
+
}
34
+
}
35
+
public static ProjectTimer projectTimer = new ProjectTimer();
36
+
37
+
public static class ResetTimer implements BlockExecutor.BlockHandler {
38
+
public int run(Block block, Sprite sprite, boolean[] withoutScreenRefresh, boolean fromRepeat) {
39
+
projectTimer.start();
40
+
return BlockExecutor.RESULT_CONTINUE;
41
+
}
42
+
}
43
+
44
+
public static class AskAndWait implements BlockExecutor.BlockHandler {
45
+
public int run(Block block, Sprite sprite, boolean[] withoutScreenRefresh, boolean fromRepeat) {
46
+
// This block is blocking, meaning script execution pauses until user input is received.
47
+
// We use Scratch.awaitingUserInput and Scratch.inputQuestion flags to signal the UI.
48
+
// The main loop in Scratch.startScratchProject() will wait until input is provided.
49
+
50
+
if (block.repeatTimes != -1 && !fromRepeat) {
51
+
block.repeatTimes = -1;
52
+
}
53
+
54
+
if (block.repeatTimes == -1) {
55
+
block.repeatTimes = -9; // Special code for ask and wait to indicate it's waiting for input
56
+
BlockExecutor.addToRepeatQueue(sprite, block);
57
+
58
+
Scratch.awaitingUserInput = true;
59
+
Scratch.inputQuestion = Scratch.getInputValue(block, "QUESTION", sprite).asString();
60
+
61
+
// Return RESULT_RETURN to pause this script's execution.
62
+
// The main loop will then handle displaying the input prompt and waiting.
63
+
return BlockExecutor.RESULT_RETURN;
64
+
}
65
+
66
+
// If we reach here, it means the user has provided input, and the block is resuming.
67
+
// Interpret.answer should have been set by the UI.
68
+
block.repeatTimes = -1; // Reset for next execution
69
+
BlockExecutor.removeFromRepeatQueue(sprite, block);
70
+
return BlockExecutor.RESULT_CONTINUE;
71
+
}
72
+
}
73
+
74
+
public static class SetDragMode implements BlockExecutor.BlockHandler {
75
+
public int run(Block block, Sprite sprite, boolean[] withoutScreenRefresh, boolean fromRepeat) {
76
+
String mode = Scratch.getFieldValue(block, "DRAG_MODE");
77
+
if (mode.equals("draggable")) {
78
+
sprite.draggable = true;
79
+
} else if (mode.equals("not draggable")) {
80
+
sprite.draggable = false;
81
+
}
82
+
return BlockExecutor.RESULT_CONTINUE;
83
+
}
84
+
}
85
+
86
+
public static class SensingTimer implements BlockExecutor.ValueBlockHandler {
87
+
public Value run(Block block, Sprite sprite) {
88
+
return new Value(projectTimer.getTimeMs() / 1000.0);
89
+
}
90
+
}
91
+
92
+
public static class Of implements BlockExecutor.ValueBlockHandler {
93
+
public Value run(Block block, Sprite sprite) {
94
+
String property = Scratch.getFieldValue(block, "PROPERTY");
95
+
String objectName;
96
+
97
+
// Get the target object name from the input. This can be "_stage_", "_myself_", or a sprite name.
98
+
Value objectValue = Scratch.getInputValue(block, "OBJECT", sprite);
99
+
objectName = objectValue.asString();
100
+
101
+
Sprite targetSprite = null;
102
+
103
+
if (objectName.equals("_stage_")) {
104
+
for (int i = 0; i < Interpret.sprites.size(); i++) {
105
+
Sprite s = (Sprite) Interpret.sprites.elementAt(i);
106
+
if (s.isStage) {
107
+
targetSprite = s;
108
+
break;
109
+
}
110
+
}
111
+
} else if (objectName.equals("_myself_")) {
112
+
targetSprite = sprite;
113
+
} else {
114
+
// Find sprite by name (non-clone)
115
+
for (int i = 0; i < Interpret.sprites.size(); i++) {
116
+
Sprite s = (Sprite) Interpret.sprites.elementAt(i);
117
+
if (s.name.equals(objectName) && !s.isClone) {
118
+
targetSprite = s;
119
+
break;
120
+
}
121
+
}
122
+
}
123
+
124
+
if (targetSprite == null) {
125
+
// If target sprite not found, return a default value (0 for numbers, empty string for names)
126
+
if (property.equals("costume name") || property.equals("backdrop name")) {
127
+
return new Value("");
128
+
}
129
+
return new Value(0);
130
+
}
131
+
132
+
if (property.equals("x position")) {
133
+
return new Value(targetSprite.xPosition);
134
+
} else if (property.equals("y position")) {
135
+
return new Value(targetSprite.yPosition);
136
+
} else if (property.equals("direction")) {
137
+
return new Value(targetSprite.rotation);
138
+
} else if (property.equals("costume #") || property.equals("backdrop #")) {
139
+
return new Value(targetSprite.currentCostume + 1);
140
+
} else if (property.equals("costume name") || property.equals("backdrop name")) {
141
+
if (targetSprite.costumes.isEmpty()) return new Value("");
142
+
return new Value(((Costume)targetSprite.costumes.elementAt(targetSprite.currentCostume)).name);
143
+
} else if (property.equals("size")) {
144
+
return new Value(targetSprite.size);
145
+
} else if (property.equals("volume")) {
146
+
return new Value(targetSprite.volume);
147
+
} else if (property.equals("timer")) {
148
+
return new Value(projectTimer.getTimeMs() / 1000.0);
149
+
}
150
+
151
+
// Check for variables of the target sprite by name
152
+
Enumeration varEnum = targetSprite.variables.elements();
153
+
while(varEnum.hasMoreElements()) {
154
+
Variable var = (Variable)varEnum.nextElement();
155
+
if (var.name.equals(property)) {
156
+
return var.value;
157
+
}
158
+
}
159
+
160
+
return new Value(0);
161
+
}
162
+
}
163
+
164
+
public static class MouseX implements BlockExecutor.ValueBlockHandler {
165
+
public Value run(Block block, Sprite sprite) {
166
+
return new Value(Input.mousePointer.x);
167
+
}
168
+
}
169
+
170
+
public static class MouseY implements BlockExecutor.ValueBlockHandler {
171
+
public Value run(Block block, Sprite sprite) {
172
+
return new Value(Input.mousePointer.y);
173
+
}
174
+
}
175
+
176
+
public static class DistanceTo implements BlockExecutor.ValueBlockHandler {
177
+
public Value run(Block block, Sprite sprite) {
178
+
Value targetValue = Scratch.getInputValue(block, "DISTANCETOMENU", sprite);
179
+
String objectName = targetValue.asString();
180
+
181
+
if (objectName.equals("_mouse_")) {
182
+
double dx = Input.mousePointer.x - sprite.xPosition;
183
+
double dy = Input.mousePointer.y - sprite.yPosition;
184
+
return new Value(Math.sqrt(dx * dx + dy * dy));
185
+
}
186
+
187
+
Sprite targetSprite = null;
188
+
// Find sprite by name (non-clone)
189
+
for (int i = 0; i < Interpret.sprites.size(); i++) {
190
+
Sprite s = (Sprite) Interpret.sprites.elementAt(i);
191
+
if (s.name.equals(objectName) && !s.isClone) {
192
+
targetSprite = s;
193
+
break;
194
+
}
195
+
}
196
+
197
+
if (targetSprite != null) {
198
+
double dx = targetSprite.xPosition - sprite.xPosition;
199
+
double dy = targetSprite.yPosition - sprite.yPosition;
200
+
return new Value(Math.sqrt(dx * dx + dy * dy));
201
+
}
202
+
203
+
return new Value(10000);
204
+
}
205
+
}
206
+
207
+
public static class DaysSince2000 implements BlockExecutor.ValueBlockHandler {
208
+
public Value run(Block block, Sprite sprite) {
209
+
Calendar cal = Calendar.getInstance();
210
+
//cal.set(2000, Calendar.JANUARY, 1, 0, 0, 0);
211
+
cal.set(Calendar.YEAR, 2000);
212
+
cal.set(Calendar.MONTH, Calendar.JANUARY);
213
+
cal.set(Calendar.DATE, 1);
214
+
cal.set(Calendar.HOUR_OF_DAY, 0);
215
+
cal.set(Calendar.MINUTE, 0);
216
+
cal.set(Calendar.SECOND, 0);
217
+
long millis2000 = cal.getTime().getTime();
218
+
long currentMillis = System.currentTimeMillis();
219
+
long diffMillis = currentMillis - millis2000;
220
+
double days = diffMillis / (1000.0 * 60 * 60 * 24);
221
+
return new Value(days);
222
+
}
223
+
}
224
+
225
+
public static class Current implements BlockExecutor.ValueBlockHandler {
226
+
public Value run(Block block, Sprite sprite) {
227
+
String unit = Scratch.getFieldValue(block, "CURRENTMENU");
228
+
Calendar cal = Calendar.getInstance(); // Current time
229
+
230
+
if (unit.equals("YEAR")) return new Value(cal.get(Calendar.YEAR));
231
+
if (unit.equals("MONTH")) return new Value(cal.get(Calendar.MONTH) + 1); // Calendar.MONTH is 0-indexed
232
+
if (unit.equals("DATE")) return new Value(cal.get(Calendar.DAY_OF_MONTH));
233
+
if (unit.equals("DAYOFWEEK")) {
234
+
// Scratch's day of week: Sunday=7, Monday=1, ..., Saturday=6
235
+
// Java's Calendar.DAY_OF_WEEK: Sunday=1, Monday=2, ..., Saturday=7
236
+
return new Value((cal.get(Calendar.DAY_OF_WEEK) + 5) % 7 + 1);
237
+
}
238
+
if (unit.equals("HOUR")) return new Value(cal.get(Calendar.HOUR_OF_DAY)); // 24-hour format
239
+
if (unit.equals("MINUTE")) return new Value(cal.get(Calendar.MINUTE));
240
+
if (unit.equals("SECOND")) return new Value(cal.get(Calendar.SECOND));
241
+
242
+
return new Value();
243
+
}
244
+
}
245
+
246
+
public static class SensingAnswer implements BlockExecutor.ValueBlockHandler {
247
+
public Value run(Block block, Sprite sprite) {
248
+
return new Value(Interpret.answer);
249
+
}
250
+
}
251
+
252
+
public static class KeyPressed implements BlockExecutor.ValueBlockHandler {
253
+
public Value run(Block block, Sprite sprite) {
254
+
Value keyOptionValue = Scratch.getInputValue(block, "KEY_OPTION", sprite);
255
+
String keyToCheck = keyOptionValue.asString();
256
+
return new Value(Input.isKeyPressed(keyToCheck));
257
+
}
258
+
}
259
+
260
+
public static class TouchingObject implements BlockExecutor.ValueBlockHandler {
261
+
public Value run(Block block, Sprite sprite) {
262
+
Value targetValue = Scratch.getInputValue(block, "TOUCHINGOBJECTMENU", sprite);
263
+
String objectName = targetValue.asString();
264
+
265
+
if (objectName.equals("_mouse_")) {
266
+
return new Value(Interpret.isColliding("mouse", sprite, null, null));
267
+
} else if (objectName.equals("_edge_")) {
268
+
return new Value(Interpret.isColliding("edge", sprite, null, null));
269
+
} else {
270
+
// Find sprite by name (non-clone)
271
+
for (int i = 0; i < Interpret.sprites.size(); i++) {
272
+
Sprite currentSprite = (Sprite) Interpret.sprites.elementAt(i);
273
+
if (currentSprite.name.equals(objectName) && !currentSprite.isClone) {
274
+
return new Value(Interpret.isColliding("sprite", sprite, currentSprite, objectName));
275
+
}
276
+
}
277
+
}
278
+
return new Value(false);
279
+
}
280
+
}
281
+
282
+
public static class MouseDown implements BlockExecutor.ValueBlockHandler {
283
+
public Value run(Block block, Sprite sprite) {
284
+
return new Value(Input.mousePointer.isPressed);
285
+
}
286
+
}
287
+
288
+
public static class Username implements BlockExecutor.ValueBlockHandler {
289
+
public Value run(Block block, Sprite sprite) {
290
+
return new Value(Input.getUsername());
291
+
}
292
+
}
293
+
}