From 9e339dcb6b6679cbac73c8074a10b28d43130b1d Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Sun, 15 May 2016 17:29:57 +1000 Subject: [PATCH 001/141] Dialog Boxes! --- src/Specs.as | 4 ++++ src/primitives/SensingPrims.as | 9 +++++++++ 2 files changed, 13 insertions(+) diff --git a/src/Specs.as b/src/Specs.as index 44dc01f63..869c10c5c 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -271,6 +271,8 @@ public class Specs { ["ask %s and wait", " ", 7, "doAsk", "What's your name?"], ["answer", "r", 7, "answer"], ["-"], + ["notify %s title %s", " ", 7, "notify:", "Hi!", "Hello!"], + ["-"], ["key %m.key pressed?", "b", 7, "keyPressed:", "space"], ["mouse down?", "b", 7, "mousePressed"], ["mouse x", "r", 7, "mouseX"], @@ -295,6 +297,8 @@ public class Specs { ["ask %s and wait", " ", 107, "doAsk", "What's your name?"], ["answer", "r", 107, "answer"], ["-"], + ["notify %s title %s", " ", 107, "notify:", "Hi!", "Hello!"], + ["-"], ["key %m.key pressed?", "b", 107, "keyPressed:", "space"], ["mouse down?", "b", 107, "mousePressed"], ["mouse x", "r", 107, "mouseX"], diff --git a/src/primitives/SensingPrims.as b/src/primitives/SensingPrims.as index ea119bcf1..6ddec198a 100644 --- a/src/primitives/SensingPrims.as +++ b/src/primitives/SensingPrims.as @@ -29,6 +29,7 @@ package primitives { import blocks.Block; import interpreter.*; import scratch.*; + import uiwidgets.DialogBox; public class SensingPrims { @@ -72,6 +73,14 @@ public class SensingPrims { primTable['hideVariable:'] = primHideWatcher; primTable['showList:'] = primShowListWatcher; primTable['hideList:'] = primHideListWatcher; + + // Sharp + primTable["notify:"] = primNotify; + } + + // Sharp + private function primNotify(b:Block):void{ + DialogBox.notify(interp.arg(b,1),interp.arg(b,0)); } // TODO: move to stage From 58dab288361b625cd7621a3d859dcea029fa41bb Mon Sep 17 00:00:00 2001 From: Alexander Liu Date: Sun, 15 May 2016 15:13:44 +0700 Subject: [PATCH 002/141] This seems nice for a markdown file --- TRADEMARK_POLICY => TRADEMARK_POLICY.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename TRADEMARK_POLICY => TRADEMARK_POLICY.md (100%) diff --git a/TRADEMARK_POLICY b/TRADEMARK_POLICY.md similarity index 100% rename from TRADEMARK_POLICY rename to TRADEMARK_POLICY.md From 438d1166499a31eac113dbeee43bf5d40b4fe091 Mon Sep 17 00:00:00 2001 From: Alexander Liu Date: Sun, 15 May 2016 15:20:01 +0700 Subject: [PATCH 003/141] The power of exponentiation! :zap: --- src/Specs.as | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Specs.as b/src/Specs.as index 869c10c5c..f4eae643d 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -343,6 +343,7 @@ public class Specs { ["round %n", "r", 8, "rounded", ""], ["-"], ["%m.mathOp of %n", "r", 8, "computeFunction:of:", "sqrt", 9], + ["%n ^ %n", "r", 8, "power:of:", "8", "2"], // variables ["set %m.var to %s", " ", 9, SET_VAR], From 1fe5b17bef86e29324fe1860d87676aad20f7c44 Mon Sep 17 00:00:00 2001 From: Alexander Liu Date: Sun, 15 May 2016 15:21:21 +0700 Subject: [PATCH 004/141] Power! --- src/primitives/Primitives.as | 1 + 1 file changed, 1 insertion(+) diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index 142abb69c..41d2c6000 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -58,6 +58,7 @@ public class Primitives { primTable["not"] = function(b:*):* { return !interp.arg(b, 0) }; primTable["abs"] = function(b:*):* { return Math.abs(interp.numarg(b, 0)) }; primTable["sqrt"] = function(b:*):* { return Math.sqrt(interp.numarg(b, 0)) }; + primTable["power:of:"] = function(b:*):* { return Math.pow(interp.numarg(b, 0), interp.numarg(b, 1)) }; primTable["concatenate:with:"] = function(b:*):* { return ("" + interp.arg(b, 0) + interp.arg(b, 1)).substr(0, 10240); }; primTable["letter:of:"] = primLetterOf; From e8a24124e473a42cfb933e41d0b8c03e58744701 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Sun, 15 May 2016 18:24:31 +1000 Subject: [PATCH 005/141] Welcome message and version string --- src/Scratch.as | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Scratch.as b/src/Scratch.as index 16b3e3c5e..286a4289a 100644 --- a/src/Scratch.as +++ b/src/Scratch.as @@ -74,7 +74,7 @@ import watchers.ListWatcher; public class Scratch extends Sprite { // Version - public static const versionString:String = 'v446'; + public static const versionString:String = 'Dev : Scratch v446'; public static var app:Scratch; // static reference to the app, used for debugging // Display modes @@ -162,7 +162,7 @@ public class Scratch extends Sprite { } protected function initialize():void { - isOffline = !URLUtil.isHttpURL(loaderInfo.url); + isOffline = (loaderInfo.parameters['asPlayer'] != 'true'); // !URLUtil.isHttpURL(loaderInfo.url) hostProtocol = URLUtil.getProtocol(loaderInfo.url); isExtensionDevMode = (loaderInfo.parameters['extensionDevMode'] == 'true'); @@ -221,6 +221,8 @@ public class Scratch extends Sprite { //Analyze.countMissingAssets(); handleStartupParameters(); + + DialogBox.notify("Welcome to Sharp!", "Website: http://SharpScratchMod.github.io\nGitHub: https://github.com/SharpScratchMod/Sharp\n\nCredits:\nDrKat123 - Developer, Owner\nMrcomputer1 - Developer, Owner"); } protected function handleStartupParameters():void { From 764f426bec8ba376ad867557b61944587f56b42c Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Sun, 15 May 2016 18:38:22 +1000 Subject: [PATCH 006/141] Rename README.md to README_Scratch.md --- README.md => README_Scratch.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename README.md => README_Scratch.md (100%) diff --git a/README.md b/README_Scratch.md similarity index 100% rename from README.md rename to README_Scratch.md From 437deb5a9d02699a25b69436992019f6647a496e Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Sun, 15 May 2016 18:40:41 +1000 Subject: [PATCH 007/141] Create README.md --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 000000000..89710f98f --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +# Sharp +Sharp Scratch Mod by DrKat123 and Mrcomputer1 + +[Try it!](https://sharpscratchmod.github.io/Sharp.swf) + +[Scratch topic](https://scratch.mit.edu/discuss/topic/199192/) + +Looking for the Scratch readme? https://github.com/SharpScratchMod/Sharp/blob/master/README_Scratch.md From 6e818ef386fdc8174b18869e1105c8af2a5f8f3b Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Sun, 15 May 2016 18:42:38 +1000 Subject: [PATCH 008/141] Update .travis.yml --- .travis.yml | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/.travis.yml b/.travis.yml index 37a8c62da..b11b79c42 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,14 +11,3 @@ install: script: - ./gradlew check -Ptarget=11.6 - ./gradlew check -Ptarget=10.2 -notifications: - slack: - secure: TFnMix3WLFecQLMgmSIsUrnZUV7s5U7mJlzkfLrGU02u0uztjLcJr9qekg65I0wFtqGuMGAOfPAZo4hf0l5djzJTSUobLdlTpEunIEWd53IUZlljKCJQsVT8hfJtbjpIXMraLRLyTzDkXcRO3v2xthU30vsSI75sxQYufBx5/sU= - format: text - hipchat: - rooms: - secure: RP6i3+3IPgwkCj78UAjISXCv67RIU8u84OOAAcLT64pRoJ2aZvNo4ITlU28AVnRojO8V9JoXo/UBiTSTnNZsiL6LIqh1BScIE8lfIHLZ4pEqrvrjSmx56jT9jf3kttjjp00qaQ2QlpV7v9Dyg4GOvLRfOYTOhTSQTKgfWN+/dJA= - template: - - '%{repository}#%{build_number} (%{branch} - %{commit} : %{author}): %{message} - (Details/Change view)' - format: html From 274b6434a97e88320d912fe476572e0afed356e6 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Sun, 15 May 2016 19:03:39 +1000 Subject: [PATCH 009/141] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 89710f98f..50b2254f0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # Sharp Sharp Scratch Mod by DrKat123 and Mrcomputer1 +[![Gitter](https://badges.gitter.im/SharpScratchMod/Sharp.svg)](https://gitter.im/SharpScratchMod/Sharp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=body_badge) + [Try it!](https://sharpscratchmod.github.io/Sharp.swf) [Scratch topic](https://scratch.mit.edu/discuss/topic/199192/) From 9052c5a4dbcefcda8edbca8e02e4f1f24eb655c7 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Sun, 15 May 2016 19:07:51 +1000 Subject: [PATCH 010/141] Moved power block to below the / block --- src/Specs.as | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Specs.as b/src/Specs.as index f4eae643d..9b550a9f2 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -324,6 +324,7 @@ public class Specs { ["%n - %n", "r", 8, "-", "", ""], ["%n * %n", "r", 8, "*", "", ""], ["%n / %n", "r", 8, "/", "", ""], + ["%n ^ %n", "r", 8, "power:of:", "8", "2"], ["-"], ["pick random %n to %n", "r", 8, "randomFrom:to:", 1, 10], ["-"], @@ -343,7 +344,6 @@ public class Specs { ["round %n", "r", 8, "rounded", ""], ["-"], ["%m.mathOp of %n", "r", 8, "computeFunction:of:", "sqrt", 9], - ["%n ^ %n", "r", 8, "power:of:", "8", "2"], // variables ["set %m.var to %s", " ", 9, SET_VAR], From 14759a29b6705f2109452592bce2b09430952c43 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Sun, 15 May 2016 21:50:15 +1000 Subject: [PATCH 011/141] Report a bug dialog --- src/Scratch.as | 40 ++++++++++++++++++++++++++++++++++++++ src/ui/parts/TopBarPart.as | 8 ++++++++ src/uiwidgets/DialogBox.as | 18 +++++++++++++++++ 3 files changed, 66 insertions(+) diff --git a/src/Scratch.as b/src/Scratch.as index 286a4289a..f90a4945a 100644 --- a/src/Scratch.as +++ b/src/Scratch.as @@ -42,6 +42,7 @@ import flash.net.LocalConnection; import flash.net.URLLoader; import flash.net.URLLoaderDataFormat; import flash.net.URLRequest; +import flash.net.navigateToURL; import flash.system.*; import flash.text.*; import flash.utils.*; @@ -1057,9 +1058,48 @@ public class Scratch extends Sprite { m.showOnStage(stage, b.x, topBarPart.bottom() - 1); } + public function showHelpMenu(b:*):void { + var m:Menu = new Menu(null, 'Help', CSS.topBarColor(), 28); + + addHelpMenuItems(b, m); + + m.showOnStage(stage, b.x, topBarPart.bottom() - 1); + } + public function stopVideo(b:*):void { runtime.stopVideo(); } + + protected function addHelpMenuItems(b:*, m:Menu):void { + function helpMenuItemCredits(){ + DialogBox.notify("Credits", "*Owner\n\nDrKat123*, Mrcomputer1*"); + } + function helpMenuItemReportBug(){ + DialogBox.reportBugDialog(); + } + function helpMenuItemAbout(){ + var aboutMsg:String = "Scratch\n" + + "Based on Scratch from the MIT Media Lab, 2.0 v446\n" + + "\n" + + "Scratch is developed by the Lifelong Kindergarten Group at the MIT Media Lab\n" + + "\n" + + "https://scratch.mit.edu - https://github.com/llk/scratch-flash\n" + + "\n" + + "\n" + + "--------------------" + + "\n" + + "\n" + + "Sharp\n" + + "Sharp Scratch mod by DrKat123 and Mrcomputer1\n" + + "https://sharpscratchmod.github.io\n" + + versionString; + DialogBox.notify("About Sharp", aboutMsg); + } + m.addItem('Report a bug', helpMenuItemReportBug); + m.addLine(); + m.addItem('Credits', helpMenuItemCredits); + m.addItem('About', helpMenuItemAbout); + } protected function addFileMenuItems(b:*, m:Menu):void { m.addItem('Load Project', runtime.selectProjectFile); diff --git a/src/ui/parts/TopBarPart.as b/src/ui/parts/TopBarPart.as index 4f2365963..ee9cb7706 100644 --- a/src/ui/parts/TopBarPart.as +++ b/src/ui/parts/TopBarPart.as @@ -43,6 +43,7 @@ public class TopBarPart extends UIPart { protected var fileMenu:IconButton; protected var editMenu:IconButton; + protected var helpMenu:IconButton; private var copyTool:IconButton; private var cutTool:IconButton; @@ -92,6 +93,7 @@ public class TopBarPart extends UIPart { if (Scratch.app) { Scratch.app.showFileMenu(Menu.dummyButton()); Scratch.app.showEditMenu(Menu.dummyButton()); + Scratch.app.showHelpMenu(Menu.dummyButton()); } return ['File', 'Edit', 'Tips', 'Duplicate', 'Delete', 'Grow', 'Shrink', 'Block help', 'Offline Editor']; } @@ -100,6 +102,7 @@ public class TopBarPart extends UIPart { if (fileMenu.parent) { removeChild(fileMenu); removeChild(editMenu); + removeChild(helpMenu); } } @@ -149,6 +152,10 @@ public class TopBarPart extends UIPart { editMenu.x = nextX; editMenu.y = buttonY; nextX += editMenu.width + buttonSpace; + + helpMenu.x = nextX; + helpMenu.y = buttonY; + nextX += helpMenu.width + buttonSpace; // cursor tool buttons var space:int = 3; @@ -208,6 +215,7 @@ public class TopBarPart extends UIPart { protected function addTextButtons():void { addChild(fileMenu = makeMenuButton('File', app.showFileMenu, true)); addChild(editMenu = makeMenuButton('Edit', app.showEditMenu, true)); + addChild(helpMenu = makeMenuButton('Help', app.showHelpMenu, true)); } private function addToolButtons():void { diff --git a/src/uiwidgets/DialogBox.as b/src/uiwidgets/DialogBox.as index 9ff92d1aa..3c7bd713b 100644 --- a/src/uiwidgets/DialogBox.as +++ b/src/uiwidgets/DialogBox.as @@ -23,6 +23,8 @@ package uiwidgets { import flash.filters.DropShadowFilter; import flash.text.*; import flash.utils.Dictionary; + import flash.net.URLRequest; + import flash.net.navigateToURL; import translation.Translator; import ui.parts.UIPart; @@ -88,6 +90,22 @@ public class DialogBox extends Sprite { d.showOnStage(stage ? stage : Scratch.app.stage); } + public static function reportBugDialog():void{ + var d:DialogBox = new DialogBox(done); + function done():void { + var request:URLRequest = new URLRequest("https://github.com/SharpScratchMod/Sharp/issues/new?title=" + d.fields['title'].text + "&body=" + d.fields["body"].text); + navigateToURL(request, "_blank"); + } + d.addTitle("Report a bug"); + d.addText("First box: Title"); + d.addField("title", 120, "", false); + d.addText("Second box: Content"); + d.addField("body", 120, "", false); + d.addButton("Report bug", d.accept); + d.addButton("Cancel", d.cancel); + d.showOnStage(Scratch.app.stage); + } + public static function close(title:String, msg:String = null, widget:DisplayObject = null, button:String = "OK", stage:Stage = null, okFunction:Function = null, cancelFunction:Function = null, context:Dictionary = null,inverted:Boolean = false):void { var d:DialogBox = new DialogBox(okFunction, cancelFunction); d.leftJustify = false; From 6a07c5d94fea7b6a77611c875302d21b1c0163e3 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Sun, 15 May 2016 22:07:29 +1000 Subject: [PATCH 012/141] Inline Comments! :D --- src/Specs.as | 4 ++++ src/primitives/Primitives.as | 2 ++ 2 files changed, 6 insertions(+) diff --git a/src/Specs.as b/src/Specs.as index 9b550a9f2..4a272b0b7 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -230,6 +230,8 @@ public class Specs { ["broadcast %m.broadcast and wait", " ", 5, "doBroadcastAndWait", ""], // control - sprite + ["// %s", " ", 6, "inlineComment:", "My comment"], + ["-"], ["wait %n secs", " ", 6, "wait:elapsed:from:", 1], ["-"], ["repeat %n", "c", 6, "doRepeat", 10], @@ -248,6 +250,8 @@ public class Specs { ["-"], // control - stage + ["// %s", " ", 106, "inlineComment:", "My comment"], + ["-"], ["wait %n secs", " ", 106, "wait:elapsed:from:", 1], ["-"], ["repeat %n", "c", 106, "doRepeat", 10], diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index 41d2c6000..95e4cc753 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -78,6 +78,8 @@ public class Primitives { primTable["COUNT"] = function(b:*):* { return counter }; primTable["INCR_COUNT"] = function(b:*):* { counter++ }; primTable["CLR_COUNT"] = function(b:*):* { counter = 0 }; + + primTable["inlineComment:"] = function(b:*):* {}; new LooksPrims(app, interp).addPrimsTo(primTable); new MotionAndPenPrims(app, interp).addPrimsTo(primTable); From 0f15a2a8f5c6cecc856e52b63c3fa9e640f45a8f Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Sun, 15 May 2016 22:23:27 +1000 Subject: [PATCH 013/141] Enabled for each, counter, incr counter and clear counter blocks --- src/Specs.as | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/Specs.as b/src/Specs.as index 4a272b0b7..9a0553da0 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -241,6 +241,7 @@ public class Specs { ["if %b then", "e", 6, "doIfElse"], ["wait until %b", " ", 6, "doWaitUntil"], ["repeat until %b", "c", 6, "doUntil"], + ["for each %m.var in %s", "c", 6, "doForLoop", "v", 10], ["-"], ["stop %m.stop", "f", 6, "stopScripts", "all"], ["-"], @@ -248,6 +249,9 @@ public class Specs { ["create clone of %m.spriteOnly", " ", 6, "createCloneOf"], ["delete this clone", "f", 6, "deleteClone"], ["-"], + ["counter", "r", 6, "COUNT"], + ["clear counter", " ", 6, "CLR_COUNT"], + ["incr counter", " ", 6, "INCR_COUNT"], // control - stage ["// %s", " ", 106, "inlineComment:", "My comment"], @@ -261,10 +265,15 @@ public class Specs { ["if %b then", "e", 106, "doIfElse"], ["wait until %b", " ", 106, "doWaitUntil"], ["repeat until %b", "c", 106, "doUntil"], + ["for each %m.var in %s", "c", 106, "doForLoop", "v", 10], ["-"], ["stop %m.stop", "f", 106, "stopScripts", "all"], ["-"], ["create clone of %m.spriteOnly", " ", 106, "createCloneOf"], + ["-"], + ["counter", "r", 106, "COUNT"], + ["clear counter", " ", 106, "CLR_COUNT"], + ["incr counter", " ", 106, "INCR_COUNT"], // sensing ["touching %m.touching?", "b", 7, "touching:", ""], @@ -385,9 +394,9 @@ public class Specs { // testing and experimental control prims ["noop", "r", 99, "COUNT"], - ["counter", "r", 99, "COUNT"], - ["clear counter", " ", 99, "CLR_COUNT"], - ["incr counter", " ", 99, "INCR_COUNT"], + //["counter", "r", 6, "COUNT"], + //["clear counter", " ", 6, "CLR_COUNT"], + //["incr counter", " ", 6, "INCR_COUNT"], ["for each %m.varName in %s", "c", 99, "doForLoop", "v", 10], ["while %b", "c", 99, "doWhile"], ["all at once", "c", 99, "warpSpeed"], From e8cd3e6d7245295623552f2051f39cb5e397e3ab Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Sun, 15 May 2016 23:00:41 +1000 Subject: [PATCH 014/141] Changed gradle to output Sharp.swf instead of Scratch.swf --- config.groovy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.groovy b/config.groovy index 7b99d3aff..29abead12 100644 --- a/config.groovy +++ b/config.groovy @@ -1,6 +1,6 @@ environments { '11.6' { - output = 'Scratch' + output = 'Sharp' playerVersion = '11.6' additionalCompilerOptions = [ "-swf-version=19", @@ -8,7 +8,7 @@ environments { ] } '10.2' { - output = 'ScratchFor10.2' + output = 'SharpFor10.2' playerVersion = '10.2' additionalCompilerOptions = [ "-swf-version=11", From 5a13e5f85dab052998a67c1acde9fc46ed0141b6 Mon Sep 17 00:00:00 2001 From: Scratchyone Date: Sun, 15 May 2016 20:55:17 -0400 Subject: [PATCH 015/141] Remove default value for exponent to be consistent --- src/Specs.as | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Specs.as b/src/Specs.as index 9a0553da0..ee17e222f 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -337,7 +337,7 @@ public class Specs { ["%n - %n", "r", 8, "-", "", ""], ["%n * %n", "r", 8, "*", "", ""], ["%n / %n", "r", 8, "/", "", ""], - ["%n ^ %n", "r", 8, "power:of:", "8", "2"], + ["%n ^ %n", "r", 8, "power:of:", "", ""], ["-"], ["pick random %n to %n", "r", 8, "randomFrom:to:", 1, 10], ["-"], From 6eea239e545d2fb358fd141e160073f913a42c2e Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Mon, 16 May 2016 12:17:51 +1000 Subject: [PATCH 016/141] Spec update --- src/Specs.as | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Specs.as b/src/Specs.as index 9a0553da0..cd505c82c 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -397,7 +397,7 @@ public class Specs { //["counter", "r", 6, "COUNT"], //["clear counter", " ", 6, "CLR_COUNT"], //["incr counter", " ", 6, "INCR_COUNT"], - ["for each %m.varName in %s", "c", 99, "doForLoop", "v", 10], + //["for each %m.varName in %s", "c", 99, "doForLoop", "v", 10], ["while %b", "c", 99, "doWhile"], ["all at once", "c", 99, "warpSpeed"], From bcd9c8e2c3c23954a6ce0d106b6d685e9f395363 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Mon, 16 May 2016 12:24:01 +1000 Subject: [PATCH 017/141] Added some blocks --- src/Specs.as | 10 ++++++++++ src/primitives/Primitives.as | 1 + 2 files changed, 11 insertions(+) diff --git a/src/Specs.as b/src/Specs.as index cd505c82c..9559d5e03 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -291,6 +291,11 @@ public class Specs { ["mouse x", "r", 7, "mouseX"], ["mouse y", "r", 7, "mouseY"], ["-"], + ["is in editor?", "b", 7, "isInEditor:"], + ["is in fullscreen?", "b", 7, "isInFullscreen:"], + ["using turbo mode?", "b", 7, "usingTurboMode:"], + ["Sharp version", "r", 7, "sharpVersion:"], + ["-"], ["loudness", "r", 7, "soundLevel"], ["-"], ["video %m.videoMotionType on %m.stageOrThis", "r", 7, "senseVideoMotion", "motion"], @@ -317,6 +322,11 @@ public class Specs { ["mouse x", "r", 107, "mouseX"], ["mouse y", "r", 107, "mouseY"], ["-"], + ["is in editor?", "b", 107, "isInEditor:"], + ["is in fullscreen?", "b", 107, "isInFullscreen:"], + ["using turbo mode?", "b", 107, "usingTurboMode:"], + ["Sharp version", "r", 107, "sharpVersion:"], + ["-"], ["loudness", "r", 107, "soundLevel"], ["-"], ["video %m.videoMotionType on %m.stageOrThis", "r", 107, "senseVideoMotion", "motion", "Stage"], diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index 95e4cc753..c219b46f6 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -79,6 +79,7 @@ public class Primitives { primTable["INCR_COUNT"] = function(b:*):* { counter++ }; primTable["CLR_COUNT"] = function(b:*):* { counter = 0 }; + // Sharp primTable["inlineComment:"] = function(b:*):* {}; new LooksPrims(app, interp).addPrimsTo(primTable); From ad57b4db7aca0dedaeae8be2ac7480a420cf65a1 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Mon, 16 May 2016 13:02:32 +1000 Subject: [PATCH 018/141] Added in editor?, in fullscreen?, Sharp version, using turbo mode? --- src/Scratch.as | 9 ++++++--- src/primitives/SensingPrims.as | 4 ++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Scratch.as b/src/Scratch.as index f90a4945a..8e1d71e88 100644 --- a/src/Scratch.as +++ b/src/Scratch.as @@ -91,6 +91,7 @@ public class Scratch extends Sprite { public var ignoreResize:Boolean = false; // If true, temporarily ignore resize events. public var isExtensionDevMode:Boolean = false; // If true, run in extension development mode (as on ScratchX) public var isMicroworld:Boolean = false; + public var isFullScreen:Boolean = false; public var presentationScale:Number; @@ -223,7 +224,7 @@ public class Scratch extends Sprite { handleStartupParameters(); - DialogBox.notify("Welcome to Sharp!", "Website: http://SharpScratchMod.github.io\nGitHub: https://github.com/SharpScratchMod/Sharp\n\nCredits:\nDrKat123 - Developer, Owner\nMrcomputer1 - Developer, Owner"); + DialogBox.notify("Welcome to Sharp!", "Website: http://SharpScratchMod.github.io\nGitHub: https://github.com/SharpScratchMod/Sharp\n\nCredits:\nDrKat123 - Developer, Owner\nMrcomputer1 - Developer, Owner\nscratchyone - Developer"); } protected function handleStartupParameters():void { @@ -637,11 +638,13 @@ public class Scratch extends Sprite { setEditMode(false); if (jsEnabled) externalCall('tip_bar_api.hide'); } + isFullScreen = true; } else { if (wasEditing) { setEditMode(true); if (jsEnabled) externalCall('tip_bar_api.show'); } + isFullScreen = false; } if (isOffline) { stage.displayState = enterPresentation ? StageDisplayState.FULL_SCREEN_INTERACTIVE : StageDisplayState.NORMAL; @@ -1072,7 +1075,7 @@ public class Scratch extends Sprite { protected function addHelpMenuItems(b:*, m:Menu):void { function helpMenuItemCredits(){ - DialogBox.notify("Credits", "*Owner\n\nDrKat123*, Mrcomputer1*"); + DialogBox.notify("Credits", "*Owner\n\nDrKat123*, Mrcomputer1*, scratchyone"); } function helpMenuItemReportBug(){ DialogBox.reportBugDialog(); @@ -1090,7 +1093,7 @@ public class Scratch extends Sprite { "\n" + "\n" + "Sharp\n" + - "Sharp Scratch mod by DrKat123 and Mrcomputer1\n" + + "Sharp Scratch mod by DrKat123, Mrcomputer1 and some others\n" + "https://sharpscratchmod.github.io\n" + versionString; DialogBox.notify("About Sharp", aboutMsg); diff --git a/src/primitives/SensingPrims.as b/src/primitives/SensingPrims.as index 6ddec198a..2f619ef6e 100644 --- a/src/primitives/SensingPrims.as +++ b/src/primitives/SensingPrims.as @@ -76,6 +76,10 @@ public class SensingPrims { // Sharp primTable["notify:"] = primNotify; + primTable["isInEditor:"] = function(b:*):* { return app.editMode }; + primTable["isInFullscreen:"] = function(b:*):* { return app.isFullScreen }; + primTable["usingTurboMode:"] = function(b:*):* { return interp.turboMode }; + primTable["sharpVersion:"] = function(b:*):* { return Scratch.versionString }; } // Sharp From 5d034eeb3f03b5ef9608ff83b58c7745ae6d3ab9 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Mon, 16 May 2016 13:36:42 +1000 Subject: [PATCH 019/141] Added settings GUI which will be used in the feture --- src/Scratch.as | 2 ++ src/uiwidgets/DialogBox.as | 22 ++++++++++++++++------ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/Scratch.as b/src/Scratch.as index 8e1d71e88..5989f4ff7 100644 --- a/src/Scratch.as +++ b/src/Scratch.as @@ -1119,6 +1119,8 @@ public class Scratch extends Sprite { m.addLine(); m.addItem('Revert', revertToOriginalProject); } + m.addLine(); + m.addItem("Settings (WIP)", DialogBox.settingsDialog); if (b.lastEvent.shiftKey) { m.addLine(); diff --git a/src/uiwidgets/DialogBox.as b/src/uiwidgets/DialogBox.as index 3c7bd713b..f55b63614 100644 --- a/src/uiwidgets/DialogBox.as +++ b/src/uiwidgets/DialogBox.as @@ -97,15 +97,23 @@ public class DialogBox extends Sprite { navigateToURL(request, "_blank"); } d.addTitle("Report a bug"); - d.addText("First box: Title"); - d.addField("title", 120, "", false); - d.addText("Second box: Content"); - d.addField("body", 120, "", false); + d.addField("title", 120, "", true, "Title"); + d.addField("body", 120, "", true, "Content"); d.addButton("Report bug", d.accept); d.addButton("Cancel", d.cancel); d.showOnStage(Scratch.app.stage); } + public static function settingsDialog():void{ + var d:DialogBox = new DialogBox(done); + function done():void { + + } + d.addTitle("Settings"); + d.addField("Test", 120, "", true, "Test"); + d.showOnStage(Scratch.app.stage); + } + public static function close(title:String, msg:String = null, widget:DisplayObject = null, button:String = "OK", stage:Stage = null, okFunction:Function = null, cancelFunction:Function = null, context:Dictionary = null,inverted:Boolean = false):void { var d:DialogBox = new DialogBox(okFunction, cancelFunction); d.leftJustify = false; @@ -154,10 +162,12 @@ public class DialogBox extends Sprite { addChild(o); } - public function addField(fieldName:String, width:int, defaultValue:* = null, showLabel:Boolean = true):void { + public function addField(fieldName:String, width:int, defaultValue:* = null, showLabel:Boolean = true, label:String = null):void { var l:TextField = null; if (showLabel) { - l = makeLabel(Translator.map(fieldName) + ':'); + //var labelStr:String = Translator.map(fieldName); + if(label == null) label = Translator.map(fieldName); + l = makeLabel(label + ':'); addChild(l); } var f:TextField = makeField(width); From 1879ff539fe081338bd0691524e4e75383f05465 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Mon, 16 May 2016 20:43:47 +1000 Subject: [PATCH 020/141] Added settings --- src/Scratch.as | 43 +++++++++- src/primitives/SoundPrims.as | 152 ++++++++++++++++++++--------------- src/uiwidgets/DialogBox.as | 18 ++++- 3 files changed, 144 insertions(+), 69 deletions(-) diff --git a/src/Scratch.as b/src/Scratch.as index 5989f4ff7..68c5d1caa 100644 --- a/src/Scratch.as +++ b/src/Scratch.as @@ -43,6 +43,7 @@ import flash.net.URLLoader; import flash.net.URLLoaderDataFormat; import flash.net.URLRequest; import flash.net.navigateToURL; +import flash.net.SharedObject; import flash.system.*; import flash.text.*; import flash.utils.*; @@ -77,6 +78,41 @@ public class Scratch extends Sprite { // Version public static const versionString:String = 'Dev : Scratch v446'; public static var app:Scratch; // static reference to the app, used for debugging + + // Sharp settings store + public var sharpSettings:SharedObject; + private var sharpSettingsVersion:int = 1; + private function initSettings():void{ + if(!sharpSettings.data.hasOwnProperty("_settingsVersion")){ + trace("Creating default setting values"); + sharpSettings.data._settingsVersion = sharpSettingsVersion; + sharpSettings.data.allowSound = true; + }else{ + + } + } + public function saveSettings():void{ + sharpSettings.flush(); + } + public function resetSettings():void{ + sharpSettings.clear(); + saveSettings(); + exitSharp(); + } + public function updateSettings():void{ + if(sharpSettings.data._settingsVersion != sharpSettingsVersion){ + /*if(sharpSettings.data._settingsVersion == (version to update from)){ + trace("Updating settings from " + sharpSettings.data._settingsVersion + " to (version to update to)"); + // do updates + }*/ + updateSettings(); //Runs to see if there are more updates + } + } + + // Tasks + public function exitSharp():void{ + fscommand("quit"); + } // Display modes public var hostProtocol:String = 'http'; @@ -172,6 +208,8 @@ public class Scratch extends Sprite { checkFlashVersion(); initServer(); + + sharpSettings = SharedObject.getLocal("SharpScratchModSettings"); stage.align = StageAlign.TOP_LEFT; stage.scaleMode = StageScaleMode.NO_SCALE; @@ -224,6 +262,7 @@ public class Scratch extends Sprite { handleStartupParameters(); + initSettings(); DialogBox.notify("Welcome to Sharp!", "Website: http://SharpScratchMod.github.io\nGitHub: https://github.com/SharpScratchMod/Sharp\n\nCredits:\nDrKat123 - Developer, Owner\nMrcomputer1 - Developer, Owner\nscratchyone - Developer"); } @@ -1104,6 +1143,8 @@ public class Scratch extends Sprite { m.addItem('About', helpMenuItemAbout); } + public var fullscreenEditor:Boolean = false; + protected function addFileMenuItems(b:*, m:Menu):void { m.addItem('Load Project', runtime.selectProjectFile); m.addItem('Save Project', exportProjectToFile); @@ -1120,7 +1161,7 @@ public class Scratch extends Sprite { m.addItem('Revert', revertToOriginalProject); } m.addLine(); - m.addItem("Settings (WIP)", DialogBox.settingsDialog); + m.addItem("Settings", DialogBox.settingsDialog); if (b.lastEvent.shiftKey) { m.addLine(); diff --git a/src/primitives/SoundPrims.as b/src/primitives/SoundPrims.as index 7bc70bda1..e25ad3d5b 100644 --- a/src/primitives/SoundPrims.as +++ b/src/primitives/SoundPrims.as @@ -68,87 +68,109 @@ public class SoundPrims { } private function primPlaySound(b:Block):void { - var snd:ScratchSound = interp.targetObj().findSound(interp.arg(b, 0)); - if (snd != null) playSound(snd, interp.targetObj()); + if(Scratch.app.sharpSettings.data.allowSound){ + var snd:ScratchSound = interp.targetObj().findSound(interp.arg(b, 0)); + if (snd != null) playSound(snd, interp.targetObj()); + } } private function primPlaySoundUntilDone(b:Block):void { - var activeThread:Thread = interp.activeThread; - if (activeThread.firstTime) { - var snd:ScratchSound = interp.targetObj().findSound(interp.arg(b, 0)); - if (snd == null) return; - activeThread.tmpObj = playSound(snd, interp.targetObj()); - activeThread.firstTime = false; - } - var player:ScratchSoundPlayer = ScratchSoundPlayer(activeThread.tmpObj); - if ((player == null) || (player.atEnd())) { // finished playing - activeThread.tmp = 0; - activeThread.firstTime = true; - } else { - interp.doYield(); + if(Scratch.app.sharpSettings.data.allowSound){ + var activeThread:Thread = interp.activeThread; + if (activeThread.firstTime) { + var snd:ScratchSound = interp.targetObj().findSound(interp.arg(b, 0)); + if (snd == null) return; + activeThread.tmpObj = playSound(snd, interp.targetObj()); + activeThread.firstTime = false; + } + var player:ScratchSoundPlayer = ScratchSoundPlayer(activeThread.tmpObj); + if ((player == null) || (player.atEnd())) { // finished playing + activeThread.tmp = 0; + activeThread.firstTime = true; + } else { + interp.doYield(); + } } } private function primPlayNote(b:Block):void { - var s:ScratchObj = interp.targetObj(); - if (s == null) return; - if (interp.activeThread.firstTime) { - var key:Number = interp.numarg(b, 0); - var secs:Number = beatsToSeconds(interp.numarg(b, 1)); - interp.activeThread.tmpObj = playNote(s.instrument, key, secs, s); - interp.startTimer(secs); - } else { - interp.checkTimer(); + if(Scratch.app.sharpSettings.data.allowSound){ + var s:ScratchObj = interp.targetObj(); + if (s == null) return; + if (interp.activeThread.firstTime) { + var key:Number = interp.numarg(b, 0); + var secs:Number = beatsToSeconds(interp.numarg(b, 1)); + interp.activeThread.tmpObj = playNote(s.instrument, key, secs, s); + interp.startTimer(secs); + } else { + interp.checkTimer(); + } } } private function primPlayDrum(b:Block):void { - var s:ScratchObj = interp.targetObj(); - if (s == null) return; - if (interp.activeThread.firstTime) { - var drum:int = Math.round(interp.numarg(b, 0)); - var isMIDI:Boolean = (b.op == 'drum:duration:elapsed:from:'); - var secs:Number = beatsToSeconds(interp.numarg(b, 1)); - playDrum(drum, isMIDI, 10, s); // always play entire drum sample - interp.startTimer(secs); - } else { - interp.checkTimer(); + if(Scratch.app.sharpSettings.data.allowSound){ + var s:ScratchObj = interp.targetObj(); + if (s == null) return; + if (interp.activeThread.firstTime) { + var drum:int = Math.round(interp.numarg(b, 0)); + var isMIDI:Boolean = (b.op == 'drum:duration:elapsed:from:'); + var secs:Number = beatsToSeconds(interp.numarg(b, 1)); + playDrum(drum, isMIDI, 10, s); // always play entire drum sample + interp.startTimer(secs); + } else { + interp.checkTimer(); + } } } private function playSound(s:ScratchSound, client:ScratchObj):ScratchSoundPlayer { - var player:ScratchSoundPlayer = s.sndplayer(); - player.client = client; - player.startPlaying(); - return player; + if(Scratch.app.sharpSettings.data.allowSound){ + var player:ScratchSoundPlayer = s.sndplayer(); + player.client = client; + player.startPlaying(); + return player; + }else{ + return null; + } } private function playDrum(drum:int, isMIDI:Boolean, secs:Number, client:ScratchObj):ScratchSoundPlayer { - var player:NotePlayer = SoundBank.getDrumPlayer(drum, isMIDI, secs); - if (player == null) return null; - player.client = client; - player.setDuration(secs); - player.startPlaying(); - return player; + if(Scratch.app.sharpSettings.data.allowSound){ + var player:NotePlayer = SoundBank.getDrumPlayer(drum, isMIDI, secs); + if (player == null) return null; + player.client = client; + player.setDuration(secs); + player.startPlaying(); + return player; + }else{ + return null; + } } private function playNote(instrument:int, midiKey:Number, secs:Number, client:ScratchObj):ScratchSoundPlayer { - var player:NotePlayer = SoundBank.getNotePlayer(instrument, midiKey); - if (player == null) return null; - player.client = client; - player.setNoteAndDuration(midiKey, secs); - player.startPlaying(); - return player; + if(Scratch.app.sharpSettings.data.allowSound){ + var player:NotePlayer = SoundBank.getNotePlayer(instrument, midiKey); + if (player == null) return null; + player.client = client; + player.setNoteAndDuration(midiKey, secs); + player.startPlaying(); + return player; + }else{ + return null; + } } private function primPlayRest(b:Block):void { - var s:ScratchObj = interp.targetObj(); - if (s == null) return; - if (interp.activeThread.firstTime) { - var secs:Number = beatsToSeconds(interp.numarg(b, 0)); - interp.startTimer(secs); - } else { - interp.checkTimer(); + if(Scratch.app.sharpSettings.data.allowSound){ + var s:ScratchObj = interp.targetObj(); + if (s == null) return; + if (interp.activeThread.firstTime) { + var secs:Number = beatsToSeconds(interp.numarg(b, 0)); + interp.startTimer(secs); + } else { + interp.checkTimer(); + } } } @@ -157,14 +179,16 @@ public class SoundPrims { } private function primSetInstrument(b:Block):void { - // Set Scratch 2.0 instrument. - var instr:int = interp.numarg(b, 0) - 1; - if (b.op == 'midiInstrument:') { - // map old to new instrument number - instr = instrumentMap[instr] - 1; // maps to -1 if out of range + if(Scratch.app.sharpSettings.data.allowSound){ + // Set Scratch 2.0 instrument. + var instr:int = interp.numarg(b, 0) - 1; + if (b.op == 'midiInstrument:') { + // map old to new instrument number + instr = instrumentMap[instr] - 1; // maps to -1 if out of range + } + instr = Math.max(0, Math.min(instr, SoundBank.instrumentNames.length - 1)); + if (interp.targetObj()) interp.targetObj().instrument = instr; } - instr = Math.max(0, Math.min(instr, SoundBank.instrumentNames.length - 1)); - if (interp.targetObj()) interp.targetObj().instrument = instr; } private function primChangeVolume(b:Block):void { diff --git a/src/uiwidgets/DialogBox.as b/src/uiwidgets/DialogBox.as index f55b63614..66a76b12a 100644 --- a/src/uiwidgets/DialogBox.as +++ b/src/uiwidgets/DialogBox.as @@ -18,6 +18,7 @@ */ package uiwidgets { + import flash.system.fscommand; import flash.display.*; import flash.events.*; import flash.filters.DropShadowFilter; @@ -107,10 +108,17 @@ public class DialogBox extends Sprite { public static function settingsDialog():void{ var d:DialogBox = new DialogBox(done); function done():void { - + Scratch.app.sharpSettings.data.allowSound = d.booleanFields['sound'].isOn(); + Scratch.app.saveSettings(); + } + function resetSettings():void { + DialogBox.confirm("Do you really want to reset settings?", null, function():*{ Scratch.app.resetSettings(); }); } d.addTitle("Settings"); - d.addField("Test", 120, "", true, "Test"); + d.addBoolean("sound", Scratch.app.sharpSettings.data.allowSound, false, "Allow sound"); + d.addButton("OK", d.accept); + d.addButton("Cancel", d.cancel); + d.addButton("Reset Settings", resetSettings) d.showOnStage(Scratch.app.stage); } @@ -177,8 +185,10 @@ public class DialogBox extends Sprite { labelsAndFields.push([l, f]); } - public function addBoolean(fieldName:String, defaultValue:Boolean = false, isRadioButton:Boolean = false):void { - var l:TextField = makeLabel(Translator.map(fieldName) + ':'); + public function addBoolean(fieldName:String, defaultValue:Boolean = false, isRadioButton:Boolean = false, label:String = null):void { + var l:TextField = null; + if(label == null) label = Translator.map(fieldName); + l = makeLabel(label + ':'); addChild(l); var f:IconButton = isRadioButton ? new IconButton(null, null, null, true) : From 239b74bff6d09128086389637b3e7c93fb71b1ff Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Tue, 17 May 2016 10:56:03 +1000 Subject: [PATCH 021/141] Turbo mode setting --- src/Scratch.as | 7 +++++++ src/uiwidgets/DialogBox.as | 4 +++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Scratch.as b/src/Scratch.as index 68c5d1caa..46fb0aeba 100644 --- a/src/Scratch.as +++ b/src/Scratch.as @@ -87,9 +87,16 @@ public class Scratch extends Sprite { trace("Creating default setting values"); sharpSettings.data._settingsVersion = sharpSettingsVersion; sharpSettings.data.allowSound = true; + sharpSettings.data.alwaysTurboMode = false; }else{ } + prepareSettings(); + } + private function prepareSettings():void{ + if(sharpSettings.data.alwaysTurboMode){ + toggleTurboMode(); + } } public function saveSettings():void{ sharpSettings.flush(); diff --git a/src/uiwidgets/DialogBox.as b/src/uiwidgets/DialogBox.as index 66a76b12a..e2882d6b8 100644 --- a/src/uiwidgets/DialogBox.as +++ b/src/uiwidgets/DialogBox.as @@ -52,7 +52,7 @@ public class DialogBox extends Sprite { private var acceptFunction:Function; // if not nil, called when menu interaction is accepted private var cancelFunction:Function; // if not nil, called when menu interaction is canceled - + public function DialogBox(acceptFunction:Function = null, cancelFunction:Function = null) { this.acceptFunction = acceptFunction; this.cancelFunction = cancelFunction; @@ -109,6 +109,7 @@ public class DialogBox extends Sprite { var d:DialogBox = new DialogBox(done); function done():void { Scratch.app.sharpSettings.data.allowSound = d.booleanFields['sound'].isOn(); + Scratch.app.sharpSettings.data.alwaysTurboMode = d.booleanFields['alwaysTurboMode'].isOn(); Scratch.app.toggleTurboMode(); Scratch.app.saveSettings(); } function resetSettings():void { @@ -116,6 +117,7 @@ public class DialogBox extends Sprite { } d.addTitle("Settings"); d.addBoolean("sound", Scratch.app.sharpSettings.data.allowSound, false, "Allow sound"); + d.addBoolean("alwaysTurboMode", Scratch.app.sharpSettings.data.alwaysTurboMode, false, "Always in turbo mode"); d.addButton("OK", d.accept); d.addButton("Cancel", d.cancel); d.addButton("Reset Settings", resetSettings) From 0a5fd334e4efe84ee561769e35cb79f7c655eabc Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Tue, 17 May 2016 12:56:50 +1000 Subject: [PATCH 022/141] added font --- src/assets/Resources.as | 3 ++- src/assets/fonts/Inconsolata-Regular.ttf | Bin 0 -> 80456 bytes src/svgeditor/DrawPropertyUI.as | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 src/assets/fonts/Inconsolata-Regular.ttf diff --git a/src/assets/Resources.as b/src/assets/Resources.as index 97dd66fd7..6360ac881 100644 --- a/src/assets/Resources.as +++ b/src/assets/Resources.as @@ -74,7 +74,8 @@ public class Resources { [Embed(source='fonts/MysteryQuest-Regular.ttf', fontName='Mystery', embedAsCFF = 'false', advancedAntiAliasing = 'true')] private static const Font4:Class; [Embed(source='fonts/PermanentMarker.ttf', fontName='Marker', embedAsCFF = 'false', advancedAntiAliasing = 'true')] private static const Font5:Class; [Embed(source='fonts/Scratch.ttf', fontName='Scratch', embedAsCFF = 'false', advancedAntiAliasing = 'true')] private static const Font6:Class; - + [Embed(source='fonts/Inconsolata-Regular.ttf', fontName='Inconsolata', embedAsCFF='false', advancedAntiAliasing='true')] private static const Font7:Class; + // Block Icons (2x resolution to look better when scaled) [Embed(source='blocks/flagIcon.png')] private static const flagIcon:Class; [Embed(source='blocks/stopIcon.png')] private static const stopIcon:Class; diff --git a/src/assets/fonts/Inconsolata-Regular.ttf b/src/assets/fonts/Inconsolata-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..bbc964755611ebc43842a70bfc07ecaf74dbe77f GIT binary patch literal 80456 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 literal 0 HcmV?d00001 diff --git a/src/svgeditor/DrawPropertyUI.as b/src/svgeditor/DrawPropertyUI.as index 8764889eb..8a98d940b 100644 --- a/src/svgeditor/DrawPropertyUI.as +++ b/src/svgeditor/DrawPropertyUI.as @@ -346,6 +346,7 @@ public class DrawPropertyUI extends Sprite { m.addItem('Marker'); m.addItem('Mystery'); m.addItem('Scratch'); + m.addItem('Inconsolata'); m.showOnStage(Scratch.app.stage); } function fontSelected(fontName:String):void { From 324cb1ad1a17f6d45682cbad2a4a71960cd90f63 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Tue, 17 May 2016 13:40:05 +1000 Subject: [PATCH 023/141] Push hack mode --- src/Scratch.as | 3 +++ src/uiwidgets/DialogBox.as | 5 ++++- src/uiwidgets/ScriptsPane.as | 4 ++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Scratch.as b/src/Scratch.as index 46fb0aeba..7b654633d 100644 --- a/src/Scratch.as +++ b/src/Scratch.as @@ -88,6 +88,7 @@ public class Scratch extends Sprite { sharpSettings.data._settingsVersion = sharpSettingsVersion; sharpSettings.data.allowSound = true; sharpSettings.data.alwaysTurboMode = false; + sharpSettings.data.hackMode = false; }else{ } @@ -117,6 +118,7 @@ public class Scratch extends Sprite { } // Tasks + public var turboModeIsActive:Boolean = false; public function exitSharp():void{ fscommand("quit"); } @@ -1333,6 +1335,7 @@ public class Scratch extends Sprite { public function toggleTurboMode():void { interp.turboMode = !interp.turboMode; + turboModeIsActive = !turboModeIsActive; stagePart.refresh(); } diff --git a/src/uiwidgets/DialogBox.as b/src/uiwidgets/DialogBox.as index e2882d6b8..4c30a7fbb 100644 --- a/src/uiwidgets/DialogBox.as +++ b/src/uiwidgets/DialogBox.as @@ -109,7 +109,9 @@ public class DialogBox extends Sprite { var d:DialogBox = new DialogBox(done); function done():void { Scratch.app.sharpSettings.data.allowSound = d.booleanFields['sound'].isOn(); - Scratch.app.sharpSettings.data.alwaysTurboMode = d.booleanFields['alwaysTurboMode'].isOn(); Scratch.app.toggleTurboMode(); + Scratch.app.sharpSettings.data.alwaysTurboMode = d.booleanFields['alwaysTurboMode'].isOn(); + if(d.booleanFields['alwaysTurboMode'].isOn() && !Scratch.app.turboModeIsActive) Scratch.app.toggleTurboMode(); + Scratch.app.sharpSettings.data.hackMode = d.booleanFields['hackMode'].isOn(); Scratch.app.saveSettings(); } function resetSettings():void { @@ -118,6 +120,7 @@ public class DialogBox extends Sprite { d.addTitle("Settings"); d.addBoolean("sound", Scratch.app.sharpSettings.data.allowSound, false, "Allow sound"); d.addBoolean("alwaysTurboMode", Scratch.app.sharpSettings.data.alwaysTurboMode, false, "Always in turbo mode"); + d.addBoolean("hackMode", Scratch.app.sharpSettings.data.hackMode, false, "Hack mode"); d.addButton("OK", d.accept); d.addButton("Cancel", d.cancel); d.addButton("Reset Settings", resetSettings) diff --git a/src/uiwidgets/ScriptsPane.as b/src/uiwidgets/ScriptsPane.as index 387d788c6..cf267c42d 100644 --- a/src/uiwidgets/ScriptsPane.as +++ b/src/uiwidgets/ScriptsPane.as @@ -366,6 +366,10 @@ return true; // xxx disable this check for now; it was causing confusion at Scra } private function dropCompatible(droppedBlock:Block, target:DisplayObject):Boolean { + if(app.sharpSettings.data.hackMode){ + return true; //Credit liam4: This line of code was taken from their mod + } + const menusThatAcceptReporters:Array = [ 'broadcast', 'costume', 'backdrop', 'scene', 'sound', 'spriteOnly', 'spriteOrMouse', 'location', 'spriteOrStage', 'touching']; From 8a9e81e1ddc1fa8ee4c9cb2ea0935509df4a29e2 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Tue, 17 May 2016 13:55:34 +1000 Subject: [PATCH 024/141] Clone limit setting --- src/Scratch.as | 1 + src/primitives/Primitives.as | 2 +- src/uiwidgets/DialogBox.as | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Scratch.as b/src/Scratch.as index 7b654633d..91d4eb8c3 100644 --- a/src/Scratch.as +++ b/src/Scratch.as @@ -89,6 +89,7 @@ public class Scratch extends Sprite { sharpSettings.data.allowSound = true; sharpSettings.data.alwaysTurboMode = false; sharpSettings.data.hackMode = false; + sharpSettings.data.cloneLimit = 300; }else{ } diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index c219b46f6..514954525 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -32,7 +32,7 @@ package primitives { public class Primitives { - private const MaxCloneCount:int = 300; + private const MaxCloneCount:int = Scratch.app.sharpSettings.data.cloneLimit; //Scratch default: 300 protected var app:Scratch; protected var interp:Interpreter; diff --git a/src/uiwidgets/DialogBox.as b/src/uiwidgets/DialogBox.as index 4c30a7fbb..618e6ccfc 100644 --- a/src/uiwidgets/DialogBox.as +++ b/src/uiwidgets/DialogBox.as @@ -112,6 +112,7 @@ public class DialogBox extends Sprite { Scratch.app.sharpSettings.data.alwaysTurboMode = d.booleanFields['alwaysTurboMode'].isOn(); if(d.booleanFields['alwaysTurboMode'].isOn() && !Scratch.app.turboModeIsActive) Scratch.app.toggleTurboMode(); Scratch.app.sharpSettings.data.hackMode = d.booleanFields['hackMode'].isOn(); + Scratch.app.sharpSettings.data.cloneLimit = d.fields['cloneLimit'].text; Scratch.app.saveSettings(); } function resetSettings():void { @@ -121,6 +122,7 @@ public class DialogBox extends Sprite { d.addBoolean("sound", Scratch.app.sharpSettings.data.allowSound, false, "Allow sound"); d.addBoolean("alwaysTurboMode", Scratch.app.sharpSettings.data.alwaysTurboMode, false, "Always in turbo mode"); d.addBoolean("hackMode", Scratch.app.sharpSettings.data.hackMode, false, "Hack mode"); + d.addField("cloneLimit", 120, Scratch.app.sharpSettings.data.cloneLimit, true, "Clone limit"); d.addButton("OK", d.accept); d.addButton("Cancel", d.cancel); d.addButton("Reset Settings", resetSettings) From 06020e8856d923d195bfef8314c68fb7c4229b46 Mon Sep 17 00:00:00 2001 From: Alexander Liu Date: Tue, 17 May 2016 13:39:34 +0700 Subject: [PATCH 025/141] testing travis ci --- src/Specs.as | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Specs.as b/src/Specs.as index 87a6aaa30..5ec96350b 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -22,8 +22,8 @@ // // This file defines the command blocks and categories. // To add a new command: -// a. add a specification for the new command to the commands array -// b. add a primitive for the new command to the interpreter +//a. add a specification for the new command to the commands array +//b. add a primitive for the new command to the interpreter package { import flash.display.Bitmap; From 995d0f6a3a4ddb4cf9febc18502c1871bcc4870b Mon Sep 17 00:00:00 2001 From: Alexander Liu Date: Tue, 17 May 2016 13:49:27 +0700 Subject: [PATCH 026/141] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 50b2254f0..442dadc93 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ Sharp Scratch Mod by DrKat123 and Mrcomputer1 [![Gitter](https://badges.gitter.im/SharpScratchMod/Sharp.svg)](https://gitter.im/SharpScratchMod/Sharp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=body_badge) +[![Build Status](https://travis-ci.org/SharpScratchMod/Sharp.svg?branch=master)](https://travis-ci.org/SharpScratchMod/Sharp) [Try it!](https://sharpscratchmod.github.io/Sharp.swf) From a7a7af4a3e5b139ef20052b81587e19b58b0c0a4 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Tue, 17 May 2016 16:55:25 +1000 Subject: [PATCH 027/141] Update --- src/Specs.as | 1 + src/assets/Resources.as | 1 + src/assets/blocks/rabbit.png | Bin 0 -> 664 bytes src/scratch/PaletteBuilder.as | 1 + src/ui/ProcedureSpecEditor.as | 2 ++ src/uiwidgets/DialogBox.as | 2 +- 6 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 src/assets/blocks/rabbit.png diff --git a/src/Specs.as b/src/Specs.as index 87a6aaa30..d453d966b 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -105,6 +105,7 @@ public class Specs { if (name == "stop") icon = Resources.createBmp('stopIcon'); if (name == "turnLeft") icon = Resources.createBmp('turnLeftIcon'); if (name == "turnRight") icon = Resources.createBmp('turnRightIcon'); + if (name == "rabbit") icon = Resources.createBmp('rabbit'); if (icon != null) icon.scaleX = icon.scaleY = 0.5; return icon; } diff --git a/src/assets/Resources.as b/src/assets/Resources.as index 6360ac881..7da4782e4 100644 --- a/src/assets/Resources.as +++ b/src/assets/Resources.as @@ -81,6 +81,7 @@ public class Resources { [Embed(source='blocks/stopIcon.png')] private static const stopIcon:Class; [Embed(source='blocks/turnLeftIcon.png')] private static const turnLeftIcon:Class; [Embed(source='blocks/turnRightIcon.png')] private static const turnRightIcon:Class; + [Embed(source='blocks/rabbit.png')] private static const rabbit:Class; // Cursors [Embed(source='cursors/copyCursor.png')] private static const copyCursor:Class; diff --git a/src/assets/blocks/rabbit.png b/src/assets/blocks/rabbit.png new file mode 100644 index 0000000000000000000000000000000000000000..95a20e5311416526168ac0393c4fe69cd7f11067 GIT binary patch literal 664 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=fpi84GcJBsWdmf0m$*ihgk+ZFq%s60CM9K-CdgpvvUK>h5s@i zvzYmUg;PaH*^0q;A-Br4@C)5n7cJ1=S(CedeN4a6(ksV5*yOXWGV#5>?)AI*#a2C? zx(T-$RWzRpEZDR0rr3%E=1CUM(;Ge=ON*Y8dXqigwKBOl_`yH*2~$!f#hrQ#bIKdu z|MtGHY~IxdH{L}WMIWY4ocFv^?|}J2dGW(DR8EGe@9H>Xadt<#^vio8X*_*jgVZfK zvL5NL+Vfw&;S>MYJ$o Date: Tue, 17 May 2016 22:18:48 +1000 Subject: [PATCH 028/141] Changed file format to .sharp (ScratchX/SharpX - .sharpx) --- src/Scratch.as | 2 +- src/scratch/ScratchRuntime.as | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Scratch.as b/src/Scratch.as index 91d4eb8c3..116c9c538 100644 --- a/src/Scratch.as +++ b/src/Scratch.as @@ -1289,7 +1289,7 @@ public class Scratch extends Sprite { public function exportProjectToFile(fromJS:Boolean = false, saveCallback:Function = null):void { function squeakSoundsConverted():void { scriptsPane.saveScripts(false); - var projectType:String = extensionManager.hasExperimentalExtensions() ? '.sbx' : '.sb2'; + var projectType:String = extensionManager.hasExperimentalExtensions() ? '.sharpx' : '.sharp'; var defaultName:String = StringUtil.trim(projectName()); defaultName = ((defaultName.length > 0) ? defaultName : 'project') + projectType; var zipData:ByteArray = projIO.encodeProjectAsZipFile(stagePane); diff --git a/src/scratch/ScratchRuntime.as b/src/scratch/ScratchRuntime.as index 8b4fd6f20..31c766320 100644 --- a/src/scratch/ScratchRuntime.as +++ b/src/scratch/ScratchRuntime.as @@ -794,10 +794,10 @@ public class ScratchRuntime { var filter:FileFilter; if (Scratch.app.isExtensionDevMode) { - filter = new FileFilter('ScratchX Project', '*.sbx;*.sb;*.sb2'); + filter = new FileFilter('SharpX Project', '*.sharpx;*.sharp;*.sb;*.sb2;*.sbx'); } else { - filter = new FileFilter('Scratch Project', '*.sb;*.sb2'); + filter = new FileFilter('Scratch Project', '*.sharp;*.sb;*.sb2'); } Scratch.loadSingleFile(fileLoadHandler, filter); } From a84223c70905f39c3ee653693c890d9c8876e2ad Mon Sep 17 00:00:00 2001 From: DrKat123 Date: Wed, 18 May 2016 11:55:59 +0700 Subject: [PATCH 029/141] Added filesystem to Sharp --- CONTRIBUTORS | 2 ++ src/Specs.as | 4 ++++ src/primitives/Primitives.as | 13 ++++++++++++- src/ui/PaletteSelector.as | 4 ++-- 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index d7a879bc7..e4414e3f3 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -5,3 +5,5 @@ http://scratch.mit.edu/info/credits/ Mitchel Resnick, Natalie Rusk, John Maloney, Paula Bonta, and Brian Silverman made up the core design team for the Scratch 2.0 editor, with contributions from Shane M. Clements and other members of the Scratch Team. John Maloney was the lead developer through Fall of 2013, after which Shane M. Clements took on that role. + +The credits for Sharp can be found on SharpScratchmod.github.io/credits \ No newline at end of file diff --git a/src/Specs.as b/src/Specs.as index e9362dc8f..a3149b9f1 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -72,6 +72,7 @@ public class Specs { [10, "More Blocks", procedureColor], [11, "Parameter", parameterColor], [12, "List", listColor], + [13, "Filesystem", 0xcdef32] [20, "Extension", extensionsColor], ]; @@ -389,6 +390,9 @@ public class Specs { ["show list %m.list", " ", 12, "showList:"], ["hide list %m.list", " ", 12, "hideList:"], + //Filesystem blocks + ["write %s to the file %s", " ", 13, "writeFile:"], + // obsolete blocks from Scratch 1.4 that may be used in older projects ["play drum %n for %n beats", " ", 98, "drum:duration:elapsed:from:", 1, 0.25], // Scratch 1.4 MIDI drum ["set instrument to %n", " ", 98, "midiInstrument:", 1], diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index 514954525..b0ca6b46c 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -29,6 +29,8 @@ package primitives { import interpreter.*; import scratch.ScratchSprite; import translation.Translator; + import flash.filesystem.FileStream; + import flash.filesystem.File; public class Primitives { @@ -58,7 +60,7 @@ public class Primitives { primTable["not"] = function(b:*):* { return !interp.arg(b, 0) }; primTable["abs"] = function(b:*):* { return Math.abs(interp.numarg(b, 0)) }; primTable["sqrt"] = function(b:*):* { return Math.sqrt(interp.numarg(b, 0)) }; - primTable["power:of:"] = function(b:*):* { return Math.pow(interp.numarg(b, 0), interp.numarg(b, 1)) }; + primTable["power:of:"] = function(b:*):* { return Math.pow(interp.numarg(b, 0), interp.numarg(b, 1)) }; primTable["concatenate:with:"] = function(b:*):* { return ("" + interp.arg(b, 0) + interp.arg(b, 1)).substr(0, 10240); }; primTable["letter:of:"] = primLetterOf; @@ -81,6 +83,7 @@ public class Primitives { // Sharp primTable["inlineComment:"] = function(b:*):* {}; + primTable["writeFile:"] = primWriteFile; new LooksPrims(app, interp).addPrimsTo(primTable); new MotionAndPenPrims(app, interp).addPrimsTo(primTable); @@ -209,4 +212,12 @@ public class Primitives { app.runtime.cloneCount--; } + private function primWriteFile(b:Block):void{ + var file:File = new File(OUTPUT_FILE_NAME); + var stream:FileStream = new FileStream(); + stream.open(interp.arg(b, 1), FileMode.WRITE); + stream.writeUTFBytes(interp.arg(b, 0)); + stream.close(); + } + }} diff --git a/src/ui/PaletteSelector.as b/src/ui/PaletteSelector.as index ce0830b5c..46dc36fe2 100644 --- a/src/ui/PaletteSelector.as +++ b/src/ui/PaletteSelector.as @@ -32,7 +32,7 @@ package ui { public class PaletteSelector extends Sprite { private static const categories:Array = [ - 'Motion', 'Looks', 'Sound', 'Pen', 'Data', // column 1 + 'Motion', 'Looks', 'Sound', 'Pen', 'Data', 'Filesystem' // column 1 'Events', 'Control', 'Sensing', 'Operators', 'More Blocks']; // column 2 public var selectedCategory:int = 0; @@ -61,7 +61,7 @@ public class PaletteSelector extends Sprite { } private function initCategories():void { - const numberOfRows:int = 5; + const numberOfRows:int = 6; const w:int = 208; const startY:int = 3; var itemH:int; From a1d56645ee8675340631aa7a2c9b048a238dc531 Mon Sep 17 00:00:00 2001 From: Alexander Liu Date: Wed, 18 May 2016 12:03:37 +0700 Subject: [PATCH 030/141] Found a bug, squashed it --- src/Specs.as | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Specs.as b/src/Specs.as index a3149b9f1..f4bb09ea1 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -72,7 +72,7 @@ public class Specs { [10, "More Blocks", procedureColor], [11, "Parameter", parameterColor], [12, "List", listColor], - [13, "Filesystem", 0xcdef32] + [13, "Filesystem", 0xcdef32], [20, "Extension", extensionsColor], ]; From cfb10a2fc11c989c80ba3c6cbb07b99f8635f004 Mon Sep 17 00:00:00 2001 From: Alexander Liu Date: Wed, 18 May 2016 12:07:21 +0700 Subject: [PATCH 031/141] Update Primitives.as --- src/primitives/Primitives.as | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index b0ca6b46c..3cf93034d 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -25,12 +25,11 @@ package primitives { import flash.utils.Dictionary; + import flash.filesystem.*; import blocks.*; import interpreter.*; import scratch.ScratchSprite; import translation.Translator; - import flash.filesystem.FileStream; - import flash.filesystem.File; public class Primitives { @@ -213,9 +212,9 @@ public class Primitives { } private function primWriteFile(b:Block):void{ - var file:File = new File(OUTPUT_FILE_NAME); - var stream:FileStream = new FileStream(); - stream.open(interp.arg(b, 1), FileMode.WRITE); + var file:File = new File(interp.arg(b, 1)); + var stream:FileStream = new FileStream(); + stream.open(file, FileMode.WRITE); stream.writeUTFBytes(interp.arg(b, 0)); stream.close(); } From a3a276893a22777b4c8ba0fceaa11c7015e9af9b Mon Sep 17 00:00:00 2001 From: Alexander Liu Date: Wed, 18 May 2016 12:13:32 +0700 Subject: [PATCH 032/141] Major bugfix :spider: --- src/ui/PaletteSelector.as | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/PaletteSelector.as b/src/ui/PaletteSelector.as index 46dc36fe2..b2d49f3ad 100644 --- a/src/ui/PaletteSelector.as +++ b/src/ui/PaletteSelector.as @@ -32,7 +32,7 @@ package ui { public class PaletteSelector extends Sprite { private static const categories:Array = [ - 'Motion', 'Looks', 'Sound', 'Pen', 'Data', 'Filesystem' // column 1 + 'Motion', 'Looks', 'Sound', 'Pen', 'Data', 'Filesystem', // column 1 'Events', 'Control', 'Sensing', 'Operators', 'More Blocks']; // column 2 public var selectedCategory:int = 0; From ee35516a8ac4d16dcb4cad6a0fab9cade554662c Mon Sep 17 00:00:00 2001 From: DrKat123 Date: Wed, 18 May 2016 12:54:51 +0700 Subject: [PATCH 033/141] Revert "Added filesystem to Sharp" This reverts commit a84223c70905f39c3ee653693c890d9c8876e2ad. --- CONTRIBUTORS | 2 -- src/Specs.as | 4 ---- src/primitives/Primitives.as | 13 +------------ src/ui/PaletteSelector.as | 4 ++-- 4 files changed, 3 insertions(+), 20 deletions(-) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index e4414e3f3..d7a879bc7 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -5,5 +5,3 @@ http://scratch.mit.edu/info/credits/ Mitchel Resnick, Natalie Rusk, John Maloney, Paula Bonta, and Brian Silverman made up the core design team for the Scratch 2.0 editor, with contributions from Shane M. Clements and other members of the Scratch Team. John Maloney was the lead developer through Fall of 2013, after which Shane M. Clements took on that role. - -The credits for Sharp can be found on SharpScratchmod.github.io/credits \ No newline at end of file diff --git a/src/Specs.as b/src/Specs.as index a3149b9f1..e9362dc8f 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -72,7 +72,6 @@ public class Specs { [10, "More Blocks", procedureColor], [11, "Parameter", parameterColor], [12, "List", listColor], - [13, "Filesystem", 0xcdef32] [20, "Extension", extensionsColor], ]; @@ -390,9 +389,6 @@ public class Specs { ["show list %m.list", " ", 12, "showList:"], ["hide list %m.list", " ", 12, "hideList:"], - //Filesystem blocks - ["write %s to the file %s", " ", 13, "writeFile:"], - // obsolete blocks from Scratch 1.4 that may be used in older projects ["play drum %n for %n beats", " ", 98, "drum:duration:elapsed:from:", 1, 0.25], // Scratch 1.4 MIDI drum ["set instrument to %n", " ", 98, "midiInstrument:", 1], diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index b0ca6b46c..514954525 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -29,8 +29,6 @@ package primitives { import interpreter.*; import scratch.ScratchSprite; import translation.Translator; - import flash.filesystem.FileStream; - import flash.filesystem.File; public class Primitives { @@ -60,7 +58,7 @@ public class Primitives { primTable["not"] = function(b:*):* { return !interp.arg(b, 0) }; primTable["abs"] = function(b:*):* { return Math.abs(interp.numarg(b, 0)) }; primTable["sqrt"] = function(b:*):* { return Math.sqrt(interp.numarg(b, 0)) }; - primTable["power:of:"] = function(b:*):* { return Math.pow(interp.numarg(b, 0), interp.numarg(b, 1)) }; + primTable["power:of:"] = function(b:*):* { return Math.pow(interp.numarg(b, 0), interp.numarg(b, 1)) }; primTable["concatenate:with:"] = function(b:*):* { return ("" + interp.arg(b, 0) + interp.arg(b, 1)).substr(0, 10240); }; primTable["letter:of:"] = primLetterOf; @@ -83,7 +81,6 @@ public class Primitives { // Sharp primTable["inlineComment:"] = function(b:*):* {}; - primTable["writeFile:"] = primWriteFile; new LooksPrims(app, interp).addPrimsTo(primTable); new MotionAndPenPrims(app, interp).addPrimsTo(primTable); @@ -212,12 +209,4 @@ public class Primitives { app.runtime.cloneCount--; } - private function primWriteFile(b:Block):void{ - var file:File = new File(OUTPUT_FILE_NAME); - var stream:FileStream = new FileStream(); - stream.open(interp.arg(b, 1), FileMode.WRITE); - stream.writeUTFBytes(interp.arg(b, 0)); - stream.close(); - } - }} diff --git a/src/ui/PaletteSelector.as b/src/ui/PaletteSelector.as index 46dc36fe2..ce0830b5c 100644 --- a/src/ui/PaletteSelector.as +++ b/src/ui/PaletteSelector.as @@ -32,7 +32,7 @@ package ui { public class PaletteSelector extends Sprite { private static const categories:Array = [ - 'Motion', 'Looks', 'Sound', 'Pen', 'Data', 'Filesystem' // column 1 + 'Motion', 'Looks', 'Sound', 'Pen', 'Data', // column 1 'Events', 'Control', 'Sensing', 'Operators', 'More Blocks']; // column 2 public var selectedCategory:int = 0; @@ -61,7 +61,7 @@ public class PaletteSelector extends Sprite { } private function initCategories():void { - const numberOfRows:int = 6; + const numberOfRows:int = 5; const w:int = 208; const startY:int = 3; var itemH:int; From d824642e560028f69ac739ec5c70d3b384269eac Mon Sep 17 00:00:00 2001 From: Alexander Liu Date: Wed, 18 May 2016 14:02:45 +0700 Subject: [PATCH 034/141] I hate bugs --- src/primitives/Primitives.as | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index 2383e0859..7a82f299d 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -210,8 +210,7 @@ public class Primitives { app.runtime.cloneCount--; } -<<<<<<< HEAD -======= + private function primWriteFile(b:Block):void{ var file:File = new File(interp.arg(b, 1)); var stream:FileStream = new FileStream(); @@ -220,5 +219,5 @@ public class Primitives { stream.close(); } ->>>>>>> origin/master + }} From a49da39d477ad11b5d755a43b2acd66e91c314fa Mon Sep 17 00:00:00 2001 From: Alexander Liu Date: Wed, 18 May 2016 14:03:50 +0700 Subject: [PATCH 035/141] Update Specs.as --- src/Specs.as | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Specs.as b/src/Specs.as index 68d4e06d9..25a3c1197 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -72,10 +72,7 @@ public class Specs { [10, "More Blocks", procedureColor], [11, "Parameter", parameterColor], [12, "List", listColor], -<<<<<<< HEAD -======= [13, "Filesystem", 0xcdef32], ->>>>>>> origin/master [20, "Extension", extensionsColor], ]; From 40c716fdbe3089cbb83ced1bc72d30992b27af35 Mon Sep 17 00:00:00 2001 From: Alexander Liu Date: Wed, 18 May 2016 14:04:55 +0700 Subject: [PATCH 036/141] Update PaletteSelector.as --- src/ui/PaletteSelector.as | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/ui/PaletteSelector.as b/src/ui/PaletteSelector.as index 7eaa74f82..ce0830b5c 100644 --- a/src/ui/PaletteSelector.as +++ b/src/ui/PaletteSelector.as @@ -32,11 +32,7 @@ package ui { public class PaletteSelector extends Sprite { private static const categories:Array = [ -<<<<<<< HEAD 'Motion', 'Looks', 'Sound', 'Pen', 'Data', // column 1 -======= - 'Motion', 'Looks', 'Sound', 'Pen', 'Data', 'Filesystem', // column 1 ->>>>>>> origin/master 'Events', 'Control', 'Sensing', 'Operators', 'More Blocks']; // column 2 public var selectedCategory:int = 0; From f35596e69e6720f35b718ee5b734c7481882b64d Mon Sep 17 00:00:00 2001 From: Alexander Liu Date: Wed, 18 May 2016 14:06:10 +0700 Subject: [PATCH 037/141] I hate bugs --- src/primitives/Primitives.as | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index 7a82f299d..86fab333e 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -25,7 +25,7 @@ package primitives { import flash.utils.Dictionary; - import flash.filesystem.*; + //import flash.filesystem.*; import blocks.*; import interpreter.*; import scratch.ScratchSprite; From 13cf0ab632e23f4944047f3b873caf22b27e7bcc Mon Sep 17 00:00:00 2001 From: Alexander Liu Date: Wed, 18 May 2016 14:13:46 +0700 Subject: [PATCH 038/141] I HATE BUGS! :angry: --- src/primitives/Primitives.as | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index 86fab333e..a1e722af4 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -211,13 +211,5 @@ public class Primitives { } - private function primWriteFile(b:Block):void{ - var file:File = new File(interp.arg(b, 1)); - var stream:FileStream = new FileStream(); - stream.open(file, FileMode.WRITE); - stream.writeUTFBytes(interp.arg(b, 0)); - stream.close(); - } - }} From b9d1498fe19659d0859158acf2827d2975934b31 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Wed, 18 May 2016 17:33:17 +1000 Subject: [PATCH 039/141] Delete all File I/O stuff :( --- src/Specs.as | 1 - src/primitives/Primitives.as | 1 - 2 files changed, 2 deletions(-) diff --git a/src/Specs.as b/src/Specs.as index 25a3c1197..e9362dc8f 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -72,7 +72,6 @@ public class Specs { [10, "More Blocks", procedureColor], [11, "Parameter", parameterColor], [12, "List", listColor], - [13, "Filesystem", 0xcdef32], [20, "Extension", extensionsColor], ]; diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index a1e722af4..15bebabc9 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -25,7 +25,6 @@ package primitives { import flash.utils.Dictionary; - //import flash.filesystem.*; import blocks.*; import interpreter.*; import scratch.ScratchSprite; From aa65d11693b3c3f9acd0486e7cffb5c8be6d4b13 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Wed, 18 May 2016 23:01:38 +1000 Subject: [PATCH 040/141] Work on Custom reporters and booleans - Not complete - Do not work with the custom reporters or booleans until done or help is needed --- src/Specs.as | 9 +++++++++ src/blocks/Block.as | 25 +++++++++++++++++++++++++ src/interpreter/Interpreter.as | 8 +++++--- src/interpreter/Thread.as | 4 ++-- src/primitives/Primitives.as | 3 +++ src/scratch/PaletteBuilder.as | 7 ++++++- src/ui/ProcedureSpecEditor.as | 33 +++++++++++++++++++++++++++++++++ 7 files changed, 83 insertions(+), 6 deletions(-) diff --git a/src/Specs.as b/src/Specs.as index e9362dc8f..501f0832f 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -246,6 +246,9 @@ public class Specs { ["-"], ["stop %m.stop", "f", 6, "stopScripts", "all"], ["-"], + ["return %s", "f", 6, "reportValue", ""], + ["return %b", "f", 6, "reportBoolean", ""], + ["-"], ["when I start as a clone", "h", 6, "whenCloned"], ["create clone of %m.spriteOnly", " ", 6, "createCloneOf"], ["delete this clone", "f", 6, "deleteClone"], @@ -270,6 +273,9 @@ public class Specs { ["-"], ["stop %m.stop", "f", 106, "stopScripts", "all"], ["-"], + ["return %s", "f", 106, "reportValue", ""], + ["return %b", "f", 106, "reportBoolean", ""], + ["-"], ["create clone of %m.spriteOnly", " ", 106, "createCloneOf"], ["-"], ["counter", "r", 106, "COUNT"], @@ -360,6 +366,9 @@ public class Specs { ["%b or %b", "b", 8, "|"], ["not %b", "b", 8, "not"], ["-"], + ["true", "b", 8, "true"], + ["false", "b", 8, "false"], + ["-"], ["join %s %s", "r", 8, "concatenate:with:", "hello ", "world"], ["letter %n of %s", "r", 8, "letter:of:", 1, "world"], ["length of %s", "r", 8, "stringLength:", "world"], diff --git a/src/blocks/Block.as b/src/blocks/Block.as index 085c557ee..2ef4f7d85 100644 --- a/src/blocks/Block.as +++ b/src/blocks/Block.as @@ -65,6 +65,11 @@ public class Block extends Sprite { public static var MenuHandlerFunction:Function; // optional function to handle block and blockArg menus + public var isCustomReporter:Boolean = false; + public var isCustomBoolean:Boolean = false; + + public var isReturnBlock:Boolean = false; + public var spec:String; public var type:String; public var op:String = ""; @@ -115,6 +120,7 @@ public class Block extends Sprite { this.spec = Translator.map(spec); this.type = type; this.op = op; + if(op == "call" && type == "r" || type == "b") isReturnBlock = true; if ((Specs.CALL == op) || (Specs.GET_LIST == op) || @@ -180,6 +186,25 @@ public class Block extends Sprite { addEventListener(FocusEvent.KEY_FOCUS_CHANGE, focusChange); } + + public static const CUSTOM_COMMAND:Number = 0; + public static const CUSTOM_REPORTER:Number = 1; + public static const CUSTOM_BOOLEAN:Number = 2; + + public function setCustomBlockType(bType:Number = CUSTOM_COMMAND):void{ + if(bType == CUSTOM_COMMAND){ + isCustomBoolean = false; + isCustomReporter = false; + }else if(bType == CUSTOM_REPORTER){ + isCustomBoolean = false; + isCustomReporter = true; + }else if(bType == CUSTOM_BOOLEAN){ + isCustomBoolean = true; + isCustomReporter = false; + }else{ + setCustomBlockType(CUSTOM_COMMAND); + } + } public function setSpec(newSpec:String, defaultArgs:Array = null):void { for each (var o:DisplayObject in labelsAndArgs) { diff --git a/src/interpreter/Interpreter.as b/src/interpreter/Interpreter.as index fc825aead..25c846c8b 100644 --- a/src/interpreter/Interpreter.as +++ b/src/interpreter/Interpreter.as @@ -70,6 +70,8 @@ import scratch.*; import sound.*; +import uiwidgets.DialogBox; + public class Interpreter { public var activeThread:Thread; // current thread @@ -318,7 +320,7 @@ public class Interpreter { // Debug code if(debugFunc != null) debugFunc(b); - + return b.opFunction(b); } @@ -389,7 +391,7 @@ public class Interpreter { return Number(n); } - private function startCmdList(b:Block, isLoop:Boolean = false, argList:Array = null):void { + private function startCmdList(b:Block, isLoop:Boolean = false, argList:Array = null):* { if (b == null) { if (isLoop) yield = true; return; @@ -633,7 +635,7 @@ public class Interpreter { // Procedure call/return - private function primCall(b:Block):void { + private function primCall(b:Block):* { // Call a procedure. Handle recursive calls and "warp" procedures. // The activeThread.firstTime flag is used to mark the first call // to a procedure running in warp mode. activeThread.firstTime is diff --git a/src/interpreter/Thread.as b/src/interpreter/Thread.as index 27fc769f4..8179c3a67 100644 --- a/src/interpreter/Thread.as +++ b/src/interpreter/Thread.as @@ -42,7 +42,7 @@ public class Thread { public var args:Array; // arguments to a user-defined procedure // the stack - private var stack:Vector.; + public var stack:Vector.; private var sp:int; public function Thread(b:Block, targetObj:*, startupDelay:int = 0) { @@ -142,7 +142,7 @@ import blocks.*; import interpreter.*; class StackFrame { - internal var block:Block; + public var block:Block; internal var isLoop:Boolean; internal var firstTime:Boolean; internal var tmp:int; diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index 15bebabc9..d2125aea0 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -81,6 +81,9 @@ public class Primitives { // Sharp primTable["inlineComment:"] = function(b:*):* {}; + primTable["true"] = function(b:*):* {return true}; + primTable["false"] = function(b:*):* {return false}; + primTable["reportValue"] = function(b:*):* { interp.arg(b, 0) }; new LooksPrims(app, interp).addPrimsTo(primTable); new MotionAndPenPrims(app, interp).addPrimsTo(primTable); diff --git a/src/scratch/PaletteBuilder.as b/src/scratch/PaletteBuilder.as index 3468bd111..24aceb480 100644 --- a/src/scratch/PaletteBuilder.as +++ b/src/scratch/PaletteBuilder.as @@ -132,7 +132,9 @@ public class PaletteBuilder { if (definitions.length > 0) { nextY += 5; for each (var proc:Block in definitions) { - var b:Block = new Block(proc.spec, ' ', Specs.procedureColor, Specs.CALL, proc.defaultArgValues); + if(!proc.isCustomReporter && !proc.isCustomBoolean) var b:Block = new Block(proc.spec, ' ', Specs.procedureColor, Specs.CALL, proc.defaultArgValues); + if(proc.isCustomReporter && !proc.isCustomBoolean) var b:Block = new Block(proc.spec, 'r', Specs.procedureColor, Specs.CALL, proc.defaultArgValues); + if(!proc.isCustomReporter && proc.isCustomBoolean) var b:Block = new Block(proc.spec, 'b', Specs.procedureColor, Specs.CALL, proc.defaultArgValues); addItem(b); } nextY += 5; @@ -254,6 +256,9 @@ public class PaletteBuilder { newHat.parameterNames = specEditor.inputNames(); newHat.defaultArgValues = specEditor.defaultArgValues(); newHat.warpProcFlag = specEditor.warpFlag(); + if(specEditor.returnValuesCheckbox.isOn() && !specEditor.returnBooleanCheckbox.isOn()) newHat.setCustomBlockType(Block.CUSTOM_REPORTER); + if(specEditor.returnValuesCheckbox.isOn() && specEditor.returnBooleanCheckbox.isOn()) newHat.setCustomBlockType(Block.CUSTOM_BOOLEAN); + if(!specEditor.returnValuesCheckbox.isOn() && !specEditor.returnBooleanCheckbox.isOn()) newHat.setCustomBlockType(Block.CUSTOM_COMMAND); newHat.setSpec(spec); newHat.x = 10 - app.scriptsPane.x + Math.random() * 100; newHat.y = 10 - app.scriptsPane.y + Math.random() * 100; diff --git a/src/ui/ProcedureSpecEditor.as b/src/ui/ProcedureSpecEditor.as index c10ada187..7c5e540d7 100644 --- a/src/ui/ProcedureSpecEditor.as +++ b/src/ui/ProcedureSpecEditor.as @@ -41,6 +41,11 @@ public class ProcedureSpecEditor extends Sprite { private var warpCheckbox:IconButton; private var warpLabel:TextField; + + public var returnValuesCheckbox:IconButton; + private var returnValuesLabel:TextField; + public var returnBooleanCheckbox:IconButton; + private var returnBooleanLabel:TextField; private var deleteButton:IconButton; private var focusItem:DisplayObject; @@ -212,6 +217,14 @@ public class ProcedureSpecEditor extends Sprite { addChild(warpCheckbox = new IconButton(null, 'checkbox')); warpCheckbox.disableMouseover(); addChild(warpLabel = makeLabel('Run without screen refresh', 14)); + + addChild(returnValuesCheckbox = new IconButton(null, 'checkbox')); + returnValuesCheckbox.disableMouseover(); + addChild(returnValuesLabel = makeLabel('Does this block return anything?', 14)); + + addChild(returnBooleanCheckbox = new IconButton(null, 'checkbox')); + returnBooleanCheckbox.disableMouseover(); + addChild(returnBooleanLabel = makeLabel('This block returns a boolean', 14)) } private function makeLabel(s:String, fontSize:int):TextField { @@ -249,11 +262,19 @@ public class ProcedureSpecEditor extends Sprite { for each (b in buttons) addChild(b); addChild(warpCheckbox); addChild(warpLabel); + addChild(returnBooleanCheckbox); + addChild(returnBooleanLabel); + addChild(returnValuesCheckbox); + addChild(returnValuesLabel); } else { for each (label in buttonLabels) if (label.parent) removeChild(label); for each (b in buttons) if (b.parent) removeChild(b); if (warpCheckbox.parent) removeChild(warpCheckbox); if (warpLabel.parent) removeChild(warpLabel); + if (returnBooleanCheckbox.parent) removeChild(returnBooleanCheckbox); + if (returnBooleanLabel.parent) removeChild(returnBooleanLabel); + if (returnValuesCheckbox.parent) removeChild(returnValuesCheckbox); + if (returnValuesLabel.parent) removeChild(returnValuesLabel); } moreButton.setOn(showParams); @@ -375,6 +396,18 @@ public class ProcedureSpecEditor extends Sprite { warpLabel.x = warpCheckbox.x + 18; warpLabel.y = warpCheckbox.y - 3; + rowY += 30; + + returnBooleanCheckbox.x = blockShape.x + 46; + returnBooleanCheckbox.y = rowY + 4; + returnBooleanLabel.x = returnBooleanCheckbox.x + 18; + returnBooleanLabel.y = returnBooleanCheckbox.y - 3; + rowY += 30; + + returnValuesCheckbox.x = blockShape.x + 46; + returnValuesCheckbox.y = rowY + 4; + returnValuesLabel.x = returnValuesCheckbox.x + 18; + returnValuesLabel.y = returnValuesCheckbox.y - 3; if (updateDelete) updateDeleteButton(); if (parent is DialogBox) DialogBox(parent).fixLayout(); From d1c2506c7a4225035c7709039fee9ee40b514ed8 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Thu, 19 May 2016 12:08:45 +1000 Subject: [PATCH 041/141] Changed file sort from Scratch Project to Sharp Project --- src/scratch/ScratchRuntime.as | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scratch/ScratchRuntime.as b/src/scratch/ScratchRuntime.as index 31c766320..89818709b 100644 --- a/src/scratch/ScratchRuntime.as +++ b/src/scratch/ScratchRuntime.as @@ -797,7 +797,7 @@ public class ScratchRuntime { filter = new FileFilter('SharpX Project', '*.sharpx;*.sharp;*.sb;*.sb2;*.sbx'); } else { - filter = new FileFilter('Scratch Project', '*.sharp;*.sb;*.sb2'); + filter = new FileFilter('Sharp Project', '*.sharp;*.sb;*.sb2'); } Scratch.loadSingleFile(fileLoadHandler, filter); } From d2b756b5a624e5c084ea6b25146dbdedc2acd83c Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Thu, 19 May 2016 22:08:19 +1000 Subject: [PATCH 042/141] Code sections --- src/Specs.as | 2 ++ src/interpreter/Interpreter.as | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/Specs.as b/src/Specs.as index 501f0832f..1a4759215 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -232,6 +232,7 @@ public class Specs { // control - sprite ["// %s", " ", 6, "inlineComment:", "My comment"], + ["%s", "c", 6, "codeSection", "My code section"], ["-"], ["wait %n secs", " ", 6, "wait:elapsed:from:", 1], ["-"], @@ -259,6 +260,7 @@ public class Specs { // control - stage ["// %s", " ", 106, "inlineComment:", "My comment"], + ["%s", "c", 106, "codeSection", "My code section"], ["-"], ["wait %n secs", " ", 106, "wait:elapsed:from:", 1], ["-"], diff --git a/src/interpreter/Interpreter.as b/src/interpreter/Interpreter.as index 25c846c8b..379214324 100644 --- a/src/interpreter/Interpreter.as +++ b/src/interpreter/Interpreter.as @@ -438,6 +438,7 @@ public class Interpreter { private function initPrims():void { primTable = new Dictionary(); // control + primTable["codeSection"] = primCodeSection; primTable["whenGreenFlag"] = primNoop; primTable["whenKeyPressed"] = primNoop; primTable["whenClicked"] = primNoop; @@ -558,6 +559,20 @@ public class Interpreter { activeThread.firstTime = true; } } + + private function primCodeSection(b:Block):void{ + if (activeThread.firstTime) { + var repeatCount:Number = 1; // clip to range: 0 to 2^31-1 + activeThread.tmp = repeatCount; + activeThread.firstTime = false; + } + if (activeThread.tmp > 0) { + activeThread.tmp--; // decrement count + startCmdList(b.subStack1, true); + } else { + activeThread.firstTime = true; + } + } private function primStop(b:Block):void { var type:String = arg(b, 0); From 602fa759f88a48ac9115e291ede34e0e54a21051 Mon Sep 17 00:00:00 2001 From: Alexander Liu Date: Fri, 20 May 2016 14:42:40 +0700 Subject: [PATCH 043/141] Update Specs.as --- src/Specs.as | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Specs.as b/src/Specs.as index 1a4759215..968df81ef 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -366,10 +366,10 @@ public class Specs { ["-"], ["%b and %b", "b", 8, "&"], ["%b or %b", "b", 8, "|"], - ["not %b", "b", 8, "not"], + ["not %b", "b", 8, "not"], ["-"], - ["true", "b", 8, "true"], - ["false", "b", 8, "false"], + ["true", "b", 8, "true"], + ["false", "b", 8, "false"], ["-"], ["join %s %s", "r", 8, "concatenate:with:", "hello ", "world"], ["letter %n of %s", "r", 8, "letter:of:", 1, "world"], @@ -379,6 +379,7 @@ public class Specs { ["round %n", "r", 8, "rounded", ""], ["-"], ["%m.mathOp of %n", "r", 8, "computeFunction:of:", "sqrt", 9], + ["reverse %s", "r", 8, "reverseString:", "hello"], // variables ["set %m.var to %s", " ", 9, SET_VAR], From 8534fbbf56346b4f9cccdad221b4aec92e520d02 Mon Sep 17 00:00:00 2001 From: Alexander Liu Date: Fri, 20 May 2016 14:58:05 +0700 Subject: [PATCH 044/141] Update Primitives.as --- src/primitives/Primitives.as | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index d2125aea0..9f17e2db3 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -49,7 +49,7 @@ public class Primitives { primTable["-"] = function(b:*):* { return interp.numarg(b, 0) - interp.numarg(b, 1) }; primTable["*"] = function(b:*):* { return interp.numarg(b, 0) * interp.numarg(b, 1) }; primTable["/"] = function(b:*):* { return interp.numarg(b, 0) / interp.numarg(b, 1) }; - primTable["randomFrom:to:"] = primRandom; + primTable["randomFrom:to:"] = primRandom; primTable["<"] = function(b:*):* { return compare(interp.arg(b, 0), interp.arg(b, 1)) < 0 }; primTable["="] = function(b:*):* { return compare(interp.arg(b, 0), interp.arg(b, 1)) == 0 }; primTable[">"] = function(b:*):* { return compare(interp.arg(b, 0), interp.arg(b, 1)) > 0 }; @@ -58,13 +58,14 @@ public class Primitives { primTable["not"] = function(b:*):* { return !interp.arg(b, 0) }; primTable["abs"] = function(b:*):* { return Math.abs(interp.numarg(b, 0)) }; primTable["sqrt"] = function(b:*):* { return Math.sqrt(interp.numarg(b, 0)) }; - primTable["power:of:"] = function(b:*):* { return Math.pow(interp.numarg(b, 0), interp.numarg(b, 1)) }; + primTable["power:of:"] = function(b:*):* { return Math.pow(interp.numarg(b, 0), interp.numarg(b, 1)) }; + primTable["reverseString:"] = primReverseString; - primTable["concatenate:with:"] = function(b:*):* { return ("" + interp.arg(b, 0) + interp.arg(b, 1)).substr(0, 10240); }; + primTable["concatenate:with:"] = function(b:*):* { return ("" + interp.arg(b, 0) + interp.arg(b, 1)).substr(0, 10240); }; primTable["letter:of:"] = primLetterOf; primTable["stringLength:"] = function(b:*):* { return String(interp.arg(b, 0)).length }; - primTable["%"] = primModulo; + primTable["%"] = primModulo; primTable["rounded"] = function(b:*):* { return Math.round(interp.numarg(b, 0)) }; primTable["computeFunction:of:"] = primMathFunction; @@ -74,16 +75,16 @@ public class Primitives { primTable["whenCloned"] = interp.primNoop; // testing (for development) - primTable["NOOP"] = interp.primNoop; - primTable["COUNT"] = function(b:*):* { return counter }; + primTable["NOOP"] = interp.primNoop; + primTable["COUNT"] = function(b:*):* { return counter }; primTable["INCR_COUNT"] = function(b:*):* { counter++ }; primTable["CLR_COUNT"] = function(b:*):* { counter = 0 }; // Sharp - primTable["inlineComment:"] = function(b:*):* {}; - primTable["true"] = function(b:*):* {return true}; - primTable["false"] = function(b:*):* {return false}; - primTable["reportValue"] = function(b:*):* { interp.arg(b, 0) }; + primTable["inlineComment:"] = function(b:*):* {}; + primTable["true"] = function(b:*):* {return true}; + primTable["false"] = function(b:*):* {return false}; + primTable["reportValue"] = function(b:*):* { interp.arg(b, 0) }; new LooksPrims(app, interp).addPrimsTo(primTable); new MotionAndPenPrims(app, interp).addPrimsTo(primTable); @@ -211,7 +212,14 @@ public class Primitives { app.interp.stopThreadsFor(clone); app.runtime.cloneCount--; } - + + private function primReverseString(b:Block):String { + var reverse:String = interp.arg(b, 0); + var output:String = ""; + for(var i:Number = reverse.length - 1; i < 0; i--) { + output += reverse.charAt(i); + } + return output; }} From 2d7a2ff3de558eb947e722e906f25c92084a14da Mon Sep 17 00:00:00 2001 From: Alexander Liu Date: Fri, 20 May 2016 15:02:38 +0700 Subject: [PATCH 045/141] Update Primitives.as --- src/primitives/Primitives.as | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index 9f17e2db3..1b940b0b5 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -221,5 +221,5 @@ public class Primitives { } return output; - + } }} From f105cbb62e838f664d2f99f501ec556bc10dfac3 Mon Sep 17 00:00:00 2001 From: Alexander Liu Date: Fri, 20 May 2016 15:29:01 +0700 Subject: [PATCH 046/141] Update Primitives.as --- src/primitives/Primitives.as | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index 1b940b0b5..c734d067f 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -215,8 +215,9 @@ public class Primitives { private function primReverseString(b:Block):String { var reverse:String = interp.arg(b, 0); - var output:String = ""; - for(var i:Number = reverse.length - 1; i < 0; i--) { + var output:String; + var i:int; + for(i = reverse.length - 1; i < 0; i--) { output += reverse.charAt(i); } return output; From 1d218153bcc965db9f257e9334cdc80d320de95f Mon Sep 17 00:00:00 2001 From: Alexander Liu Date: Fri, 20 May 2016 15:47:47 +0700 Subject: [PATCH 047/141] Update Primitives.as --- src/primitives/Primitives.as | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index c734d067f..13cbcfa8d 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -67,7 +67,7 @@ public class Primitives { primTable["%"] = primModulo; primTable["rounded"] = function(b:*):* { return Math.round(interp.numarg(b, 0)) }; - primTable["computeFunction:of:"] = primMathFunction; + primTable["computeFunction:of:"] = primMathFunction; // clone primTable["createCloneOf"] = primCreateCloneOf; @@ -215,12 +215,12 @@ public class Primitives { private function primReverseString(b:Block):String { var reverse:String = interp.arg(b, 0); - var output:String; + var result:String; var i:int; for(i = reverse.length - 1; i < 0; i--) { - output += reverse.charAt(i); + result += reverse.charAt(i); } - return output; + return result; } }} From 58a6cae3eaf5ba256999ff8cb20703427edbc29c Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Fri, 20 May 2016 19:10:31 +1000 Subject: [PATCH 048/141] Reverse strings fixed --- src/primitives/Primitives.as | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index 13cbcfa8d..7e969b8e6 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -215,10 +215,10 @@ public class Primitives { private function primReverseString(b:Block):String { var reverse:String = interp.arg(b, 0); - var result:String; + var result:String = ""; var i:int; - for(i = reverse.length - 1; i < 0; i--) { - result += reverse.charAt(i); + for(i = reverse.length; i > 0; i--) { + result += reverse.charAt(i-1); } return result; From d8f6c290246b668ff6478c1dd34f8bf135d40993 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Fri, 20 May 2016 21:48:51 +1000 Subject: [PATCH 049/141] Some updates that did nothing --- src/Scratch.as | 13 ++++++++++--- src/scratch/ScratchRuntime.as | 15 +++++++++++++++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/Scratch.as b/src/Scratch.as index 116c9c538..549ca94f7 100644 --- a/src/Scratch.as +++ b/src/Scratch.as @@ -262,8 +262,13 @@ public class Scratch extends Sprite { setEditMode(startInEditMode()); // install project before calling fixLayout() - if (editMode) runtime.installNewProject(); - else runtime.installEmptyProject(); + if(loaderInfo.parameters.hasOwnProperty("sharp_pid")){ + var p:* = loaderInfo.parameters; + runtime.loadProjectFromURL(p['sharp_domain'] + p['sharp_save_path'] + p['sharp_pid'] + p['sharp_save_format'], p); + }else{ + if (editMode) runtime.installNewProject(); + else runtime.installEmptyProject(); + } fixLayout(); //Analyze.collectAssets(0, 119110); @@ -273,7 +278,7 @@ public class Scratch extends Sprite { handleStartupParameters(); initSettings(); - DialogBox.notify("Welcome to Sharp!", "Website: http://SharpScratchMod.github.io\nGitHub: https://github.com/SharpScratchMod/Sharp\n\nCredits:\nDrKat123 - Developer, Owner\nMrcomputer1 - Developer, Owner\nscratchyone - Developer"); + if(isOffline) DialogBox.notify("Welcome to Sharp!", "Website: http://SharpScratchMod.github.io\nGitHub: https://github.com/SharpScratchMod/Sharp\n\nCredits:\nDrKat123 - Developer, Owner\nMrcomputer1 - Developer, Owner\nscratchyone - Developer"); } protected function handleStartupParameters():void { @@ -293,6 +298,8 @@ public class Scratch extends Sprite { addExternalCallback('ASloadGithubURL', loadGithubURL); addExternalCallback('ASloadBase64SBX', loadBase64SBX); addExternalCallback('ASsetModalOverlay', setModalOverlay); + }else{ + addExternalCallback('ASloadGithubURL', loadGithubURL); } } diff --git a/src/scratch/ScratchRuntime.as b/src/scratch/ScratchRuntime.as index 89818709b..6d914f136 100644 --- a/src/scratch/ScratchRuntime.as +++ b/src/scratch/ScratchRuntime.as @@ -35,6 +35,7 @@ import flash.geom.Point; import flash.geom.Rectangle; import flash.media.*; import flash.net.*; +import flash.events.Event; import flash.system.System; import flash.text.TextField; import flash.utils.*; @@ -801,6 +802,20 @@ public class ScratchRuntime { } Scratch.loadSingleFile(fileLoadHandler, filter); } + + public function loadProjectFromURL(url:String, p:*):void { + function doInstall(e:Event):void { + installProjectFromFile(p['sharp_pid'], ByteArray(e.target.data)); + } + stopAll(); + + var req:URLRequest = new URLRequest(url); + req.method = "get"; + var loader:URLLoader = new URLLoader(); + loader.addEventListener(Event.COMPLETE, doInstall); + loader.dataFormat = URLLoaderDataFormat.BINARY; + loader.load(req); + } public function installProjectFromFile(fileName:String, data:ByteArray):void { // Install a project from a file with the given name and contents. From 88bb41f4426ad601137a6d64d638cbeb108c6553 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Sat, 21 May 2016 18:00:14 +1000 Subject: [PATCH 050/141] HTTP --- src/Specs.as | 8 ++++++++ src/primitives/Primitives.as | 25 ++++++++++++++++++++++++- src/scratch/BlockMenus.as | 9 +++++++++ src/ui/PaletteSelector.as | 4 ++-- 4 files changed, 43 insertions(+), 3 deletions(-) diff --git a/src/Specs.as b/src/Specs.as index 968df81ef..ebd0e81d2 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -72,6 +72,7 @@ public class Specs { [10, "More Blocks", procedureColor], [11, "Parameter", parameterColor], [12, "List", listColor], + [13, "HTTP", 0x55af40], [20, "Extension", extensionsColor], ]; @@ -400,6 +401,13 @@ public class Specs { ["-"], ["show list %m.list", " ", 12, "showList:"], ["hide list %m.list", " ", 12, "hideList:"], + + // Sharp + // --HTTP-- + ["%m.httpMethod %s", " ", 13, "httpBlock:", "GET", "https://api.scratch.mit.edu"], + ["http return", "r", 13, "httpReturn:"], + + // Scratch // obsolete blocks from Scratch 1.4 that may be used in older projects ["play drum %n for %n beats", " ", 98, "drum:duration:elapsed:from:", 1, 0.25], // Scratch 1.4 MIDI drum diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index 7e969b8e6..675cd0678 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -29,6 +29,9 @@ package primitives { import interpreter.*; import scratch.ScratchSprite; import translation.Translator; + + import flash.net.*; + import flash.events.Event; public class Primitives { @@ -37,6 +40,7 @@ public class Primitives { protected var app:Scratch; protected var interp:Interpreter; private var counter:int; + private var httpReturn:String = ""; public function Primitives(app:Scratch, interpreter:Interpreter) { this.app = app; @@ -85,7 +89,10 @@ public class Primitives { primTable["true"] = function(b:*):* {return true}; primTable["false"] = function(b:*):* {return false}; primTable["reportValue"] = function(b:*):* { interp.arg(b, 0) }; - + // Sharp -- HTTP + primTable["httpBlock:"] = primHttp; + primTable["httpReturn:"] = function(b:*):* {return httpReturn}; + new LooksPrims(app, interp).addPrimsTo(primTable); new MotionAndPenPrims(app, interp).addPrimsTo(primTable); new SoundPrims(app, interp).addPrimsTo(primTable); @@ -223,4 +230,20 @@ public class Primitives { return result; } + + // Sharp --- HTTP + private function primHttp(b:Block):void { + var url:String = interp.arg(b, 1); + var req:URLRequest = new URLRequest(url); + req.method = URLRequestMethod.GET; + + var loader:URLLoader = new URLLoader(); + loader.addEventListener(Event.COMPLETE, onComplete); + loader.dataFormat = URLLoaderDataFormat.TEXT; + loader.load(req); + + function onComplete(e:Event){ + httpReturn = e.target.data; + } + } }} diff --git a/src/scratch/BlockMenus.as b/src/scratch/BlockMenus.as index e61a95da6..abcf4cb5c 100644 --- a/src/scratch/BlockMenus.as +++ b/src/scratch/BlockMenus.as @@ -101,6 +101,7 @@ public class BlockMenus implements DragClient { if (menuName == 'var') menuHandler.varMenu(evt); if (menuName == 'videoMotionType') menuHandler.videoMotionTypeMenu(evt); if (menuName == 'videoState') menuHandler.videoStateMenu(evt); + if (menuName == 'httpMethod') menuHandler.httpMethodMenu(evt); } public static function strings():Array { @@ -849,5 +850,13 @@ public class BlockMenus implements DragClient { } showMenu(m); } + + /////////SHARP///////// + + private function httpMethodMenu(evt:MouseEvent):void { + var m:Menu = new Menu(setBlockArg, 'httpMethod'); + m.addItem('GET'); + showMenu(m); + } }} diff --git a/src/ui/PaletteSelector.as b/src/ui/PaletteSelector.as index ce0830b5c..945148225 100644 --- a/src/ui/PaletteSelector.as +++ b/src/ui/PaletteSelector.as @@ -32,7 +32,7 @@ package ui { public class PaletteSelector extends Sprite { private static const categories:Array = [ - 'Motion', 'Looks', 'Sound', 'Pen', 'Data', // column 1 + 'Motion', 'Looks', 'Sound', 'Pen', 'Data', 'HTTP', // column 1 'Events', 'Control', 'Sensing', 'Operators', 'More Blocks']; // column 2 public var selectedCategory:int = 0; @@ -61,7 +61,7 @@ public class PaletteSelector extends Sprite { } private function initCategories():void { - const numberOfRows:int = 5; + const numberOfRows:int = 6; const w:int = 208; const startY:int = 3; var itemH:int; From 35b6d4811e8a109eccde79be95bd08880ab04e35 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Sat, 21 May 2016 20:19:41 +1000 Subject: [PATCH 051/141] Removed some work on custom block system to make add a better one --- src/Specs.as | 6 ------ src/primitives/Primitives.as | 1 - src/ui/ProcedureSpecEditor.as | 28 ++++++++++++++-------------- 3 files changed, 14 insertions(+), 21 deletions(-) diff --git a/src/Specs.as b/src/Specs.as index ebd0e81d2..2012c9546 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -248,9 +248,6 @@ public class Specs { ["-"], ["stop %m.stop", "f", 6, "stopScripts", "all"], ["-"], - ["return %s", "f", 6, "reportValue", ""], - ["return %b", "f", 6, "reportBoolean", ""], - ["-"], ["when I start as a clone", "h", 6, "whenCloned"], ["create clone of %m.spriteOnly", " ", 6, "createCloneOf"], ["delete this clone", "f", 6, "deleteClone"], @@ -276,9 +273,6 @@ public class Specs { ["-"], ["stop %m.stop", "f", 106, "stopScripts", "all"], ["-"], - ["return %s", "f", 106, "reportValue", ""], - ["return %b", "f", 106, "reportBoolean", ""], - ["-"], ["create clone of %m.spriteOnly", " ", 106, "createCloneOf"], ["-"], ["counter", "r", 106, "COUNT"], diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index 675cd0678..6b7c77330 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -88,7 +88,6 @@ public class Primitives { primTable["inlineComment:"] = function(b:*):* {}; primTable["true"] = function(b:*):* {return true}; primTable["false"] = function(b:*):* {return false}; - primTable["reportValue"] = function(b:*):* { interp.arg(b, 0) }; // Sharp -- HTTP primTable["httpBlock:"] = primHttp; primTable["httpReturn:"] = function(b:*):* {return httpReturn}; diff --git a/src/ui/ProcedureSpecEditor.as b/src/ui/ProcedureSpecEditor.as index 7c5e540d7..a2e00dd47 100644 --- a/src/ui/ProcedureSpecEditor.as +++ b/src/ui/ProcedureSpecEditor.as @@ -218,13 +218,13 @@ public class ProcedureSpecEditor extends Sprite { warpCheckbox.disableMouseover(); addChild(warpLabel = makeLabel('Run without screen refresh', 14)); - addChild(returnValuesCheckbox = new IconButton(null, 'checkbox')); - returnValuesCheckbox.disableMouseover(); - addChild(returnValuesLabel = makeLabel('Does this block return anything?', 14)); + //addChild(returnValuesCheckbox = new IconButton(null, 'checkbox')); + //returnValuesCheckbox.disableMouseover(); + //addChild(returnValuesLabel = makeLabel('Does this block return anything?', 14)); - addChild(returnBooleanCheckbox = new IconButton(null, 'checkbox')); - returnBooleanCheckbox.disableMouseover(); - addChild(returnBooleanLabel = makeLabel('This block returns a boolean', 14)) + //addChild(returnBooleanCheckbox = new IconButton(null, 'checkbox')); + //returnBooleanCheckbox.disableMouseover(); + //addChild(returnBooleanLabel = makeLabel('This block returns a boolean', 14)) } private function makeLabel(s:String, fontSize:int):TextField { @@ -264,8 +264,8 @@ public class ProcedureSpecEditor extends Sprite { addChild(warpLabel); addChild(returnBooleanCheckbox); addChild(returnBooleanLabel); - addChild(returnValuesCheckbox); - addChild(returnValuesLabel); + //addChild(returnValuesCheckbox); + //addChild(returnValuesLabel); } else { for each (label in buttonLabels) if (label.parent) removeChild(label); for each (b in buttons) if (b.parent) removeChild(b); @@ -273,8 +273,8 @@ public class ProcedureSpecEditor extends Sprite { if (warpLabel.parent) removeChild(warpLabel); if (returnBooleanCheckbox.parent) removeChild(returnBooleanCheckbox); if (returnBooleanLabel.parent) removeChild(returnBooleanLabel); - if (returnValuesCheckbox.parent) removeChild(returnValuesCheckbox); - if (returnValuesLabel.parent) removeChild(returnValuesLabel); + //if (returnValuesCheckbox.parent) removeChild(returnValuesCheckbox); + //if (returnValuesLabel.parent) removeChild(returnValuesLabel); } moreButton.setOn(showParams); @@ -404,10 +404,10 @@ public class ProcedureSpecEditor extends Sprite { returnBooleanLabel.y = returnBooleanCheckbox.y - 3; rowY += 30; - returnValuesCheckbox.x = blockShape.x + 46; - returnValuesCheckbox.y = rowY + 4; - returnValuesLabel.x = returnValuesCheckbox.x + 18; - returnValuesLabel.y = returnValuesCheckbox.y - 3; + //returnValuesCheckbox.x = blockShape.x + 46; + //returnValuesCheckbox.y = rowY + 4; + //returnValuesLabel.x = returnValuesCheckbox.x + 18; + //returnValuesLabel.y = returnValuesCheckbox.y - 3; if (updateDelete) updateDeleteButton(); if (parent is DialogBox) DialogBox(parent).fixLayout(); From ec137578a1a5798ef04ea48779debb7a11262024 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Wed, 25 May 2016 18:08:23 +1000 Subject: [PATCH 052/141] Update --- src/Scratch.as | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Scratch.as b/src/Scratch.as index 5c4cb5c9f..3da67c6e3 100644 --- a/src/Scratch.as +++ b/src/Scratch.as @@ -76,7 +76,7 @@ import watchers.ListWatcher; public class Scratch extends Sprite { // Version - public static const versionString:String = 'v447'; + public static const versionString:String = 'Dev (Alpha coming May 30) : Scratch v447'; public static var app:Scratch; // static reference to the app, used for debugging // Sharp settings store From 3b2d61aebf997a2bffafe9074d4e923d87c41e44 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Mon, 30 May 2016 19:25:41 +1000 Subject: [PATCH 053/141] Set alpha version string (#5) --- src/Scratch.as | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Scratch.as b/src/Scratch.as index 3da67c6e3..c59445eab 100644 --- a/src/Scratch.as +++ b/src/Scratch.as @@ -76,7 +76,7 @@ import watchers.ListWatcher; public class Scratch extends Sprite { // Version - public static const versionString:String = 'Dev (Alpha coming May 30) : Scratch v447'; + public static const versionString:String = 'Alpha 1.0.0 (Butterknife) : Scratch v447'; public static var app:Scratch; // static reference to the app, used for debugging // Sharp settings store From f79ca1b7a0dfe32e646ade9a0d6b1b146ffffa8f Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Tue, 31 May 2016 21:31:34 +1000 Subject: [PATCH 054/141] Fixed custom blocks GUI --- src/scratch/PaletteBuilder.as | 14 ++++++++------ src/ui/ProcedureSpecEditor.as | 35 ----------------------------------- 2 files changed, 8 insertions(+), 41 deletions(-) diff --git a/src/scratch/PaletteBuilder.as b/src/scratch/PaletteBuilder.as index 24aceb480..5890cec14 100644 --- a/src/scratch/PaletteBuilder.as +++ b/src/scratch/PaletteBuilder.as @@ -132,9 +132,10 @@ public class PaletteBuilder { if (definitions.length > 0) { nextY += 5; for each (var proc:Block in definitions) { - if(!proc.isCustomReporter && !proc.isCustomBoolean) var b:Block = new Block(proc.spec, ' ', Specs.procedureColor, Specs.CALL, proc.defaultArgValues); - if(proc.isCustomReporter && !proc.isCustomBoolean) var b:Block = new Block(proc.spec, 'r', Specs.procedureColor, Specs.CALL, proc.defaultArgValues); - if(!proc.isCustomReporter && proc.isCustomBoolean) var b:Block = new Block(proc.spec, 'b', Specs.procedureColor, Specs.CALL, proc.defaultArgValues); + //if(!proc.isCustomReporter && !proc.isCustomBoolean) var b:Block = new Block(proc.spec, ' ', Specs.procedureColor, Specs.CALL, proc.defaultArgValues); + //if(proc.isCustomReporter && !proc.isCustomBoolean) var b:Block = new Block(proc.spec, 'r', Specs.procedureColor, Specs.CALL, proc.defaultArgValues); + //if(!proc.isCustomReporter && proc.isCustomBoolean) var b:Block = new Block(proc.spec, 'b', Specs.procedureColor, Specs.CALL, proc.defaultArgValues); + var b:Block = new Block(proc.spec, ' ', Specs.procedureColor, Specs.CALL, proc.defaultArgValues); addItem(b); } nextY += 5; @@ -256,9 +257,10 @@ public class PaletteBuilder { newHat.parameterNames = specEditor.inputNames(); newHat.defaultArgValues = specEditor.defaultArgValues(); newHat.warpProcFlag = specEditor.warpFlag(); - if(specEditor.returnValuesCheckbox.isOn() && !specEditor.returnBooleanCheckbox.isOn()) newHat.setCustomBlockType(Block.CUSTOM_REPORTER); - if(specEditor.returnValuesCheckbox.isOn() && specEditor.returnBooleanCheckbox.isOn()) newHat.setCustomBlockType(Block.CUSTOM_BOOLEAN); - if(!specEditor.returnValuesCheckbox.isOn() && !specEditor.returnBooleanCheckbox.isOn()) newHat.setCustomBlockType(Block.CUSTOM_COMMAND); + //if(specEditor.returnValuesCheckbox.isOn() && !specEditor.returnBooleanCheckbox.isOn()) newHat.setCustomBlockType(Block.CUSTOM_REPORTER); + //if(specEditor.returnValuesCheckbox.isOn() && specEditor.returnBooleanCheckbox.isOn()) newHat.setCustomBlockType(Block.CUSTOM_BOOLEAN); + //if(!specEditor.returnValuesCheckbox.isOn() && !specEditor.returnBooleanCheckbox.isOn()) newHat.setCustomBlockType(Block.CUSTOM_COMMAND); + newHat.setCustomBlockType(Block.CUSTOM_COMMAND); newHat.setSpec(spec); newHat.x = 10 - app.scriptsPane.x + Math.random() * 100; newHat.y = 10 - app.scriptsPane.y + Math.random() * 100; diff --git a/src/ui/ProcedureSpecEditor.as b/src/ui/ProcedureSpecEditor.as index a2e00dd47..477e85120 100644 --- a/src/ui/ProcedureSpecEditor.as +++ b/src/ui/ProcedureSpecEditor.as @@ -41,11 +41,6 @@ public class ProcedureSpecEditor extends Sprite { private var warpCheckbox:IconButton; private var warpLabel:TextField; - - public var returnValuesCheckbox:IconButton; - private var returnValuesLabel:TextField; - public var returnBooleanCheckbox:IconButton; - private var returnBooleanLabel:TextField; private var deleteButton:IconButton; private var focusItem:DisplayObject; @@ -77,7 +72,6 @@ public class ProcedureSpecEditor extends Sprite { addEventListener(FocusEvent.FOCUS_OUT, focusChange); addEventListener(FocusEvent.FOCUS_IN, focusChange); - originalSpec = originalSpec.replace(/@rabbit/g, ""); addSpecElements(originalSpec, inputNames); warpCheckbox.setOn(warpFlag); showButtons(false); @@ -143,7 +137,6 @@ public class ProcedureSpecEditor extends Sprite { public function spec():String { var result:String = ''; - if(warpFlag()) result = '@rabbit '; for each (var o:* in row) { if (o is TextField) result += ReadStream.escape(TextField(o).text); if (o is BlockArg) result += '%' + BlockArg(o).type; @@ -217,14 +210,6 @@ public class ProcedureSpecEditor extends Sprite { addChild(warpCheckbox = new IconButton(null, 'checkbox')); warpCheckbox.disableMouseover(); addChild(warpLabel = makeLabel('Run without screen refresh', 14)); - - //addChild(returnValuesCheckbox = new IconButton(null, 'checkbox')); - //returnValuesCheckbox.disableMouseover(); - //addChild(returnValuesLabel = makeLabel('Does this block return anything?', 14)); - - //addChild(returnBooleanCheckbox = new IconButton(null, 'checkbox')); - //returnBooleanCheckbox.disableMouseover(); - //addChild(returnBooleanLabel = makeLabel('This block returns a boolean', 14)) } private function makeLabel(s:String, fontSize:int):TextField { @@ -262,19 +247,11 @@ public class ProcedureSpecEditor extends Sprite { for each (b in buttons) addChild(b); addChild(warpCheckbox); addChild(warpLabel); - addChild(returnBooleanCheckbox); - addChild(returnBooleanLabel); - //addChild(returnValuesCheckbox); - //addChild(returnValuesLabel); } else { for each (label in buttonLabels) if (label.parent) removeChild(label); for each (b in buttons) if (b.parent) removeChild(b); if (warpCheckbox.parent) removeChild(warpCheckbox); if (warpLabel.parent) removeChild(warpLabel); - if (returnBooleanCheckbox.parent) removeChild(returnBooleanCheckbox); - if (returnBooleanLabel.parent) removeChild(returnBooleanLabel); - //if (returnValuesCheckbox.parent) removeChild(returnValuesCheckbox); - //if (returnValuesLabel.parent) removeChild(returnValuesLabel); } moreButton.setOn(showParams); @@ -396,18 +373,6 @@ public class ProcedureSpecEditor extends Sprite { warpLabel.x = warpCheckbox.x + 18; warpLabel.y = warpCheckbox.y - 3; - rowY += 30; - - returnBooleanCheckbox.x = blockShape.x + 46; - returnBooleanCheckbox.y = rowY + 4; - returnBooleanLabel.x = returnBooleanCheckbox.x + 18; - returnBooleanLabel.y = returnBooleanCheckbox.y - 3; - rowY += 30; - - //returnValuesCheckbox.x = blockShape.x + 46; - //returnValuesCheckbox.y = rowY + 4; - //returnValuesLabel.x = returnValuesCheckbox.x + 18; - //returnValuesLabel.y = returnValuesCheckbox.y - 3; if (updateDelete) updateDeleteButton(); if (parent is DialogBox) DialogBox(parent).fixLayout(); From b33fb2745d520e9779d5b231608597d7ad7411d9 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Wed, 1 Jun 2016 17:38:38 +1000 Subject: [PATCH 055/141] Prevented more then 10 http requests blocks and 10 notify blocks to be active at 1 time --- src/primitives/Primitives.as | 4 ++++ src/primitives/SensingPrims.as | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index 6b7c77330..6e93d281c 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -41,6 +41,7 @@ public class Primitives { protected var interp:Interpreter; private var counter:int; private var httpReturn:String = ""; + private var httpRequestsAllowed:int = 10; private var httpRequestsActive:int = 0; // TODO: Add "hidden" setting for HTTP requests allowed public function Primitives(app:Scratch, interpreter:Interpreter) { this.app = app; @@ -232,6 +233,8 @@ public class Primitives { // Sharp --- HTTP private function primHttp(b:Block):void { + if(httpRequestsActive == httpRequestsAllowed) return; + httpRequestsActive++; var url:String = interp.arg(b, 1); var req:URLRequest = new URLRequest(url); req.method = URLRequestMethod.GET; @@ -243,6 +246,7 @@ public class Primitives { function onComplete(e:Event){ httpReturn = e.target.data; + httpRequestsActive--; } } }} diff --git a/src/primitives/SensingPrims.as b/src/primitives/SensingPrims.as index 2f619ef6e..70d9e4bef 100644 --- a/src/primitives/SensingPrims.as +++ b/src/primitives/SensingPrims.as @@ -35,6 +35,8 @@ public class SensingPrims { private var app:Scratch; private var interp:Interpreter; + + private var dialogBoxAllowed = 10; private var dialogBoxActive = 0; // TODO: Add hidden setting for dialog boxs allowed public function SensingPrims(app:Scratch, interpreter:Interpreter) { this.app = app; @@ -84,7 +86,9 @@ public class SensingPrims { // Sharp private function primNotify(b:Block):void{ - DialogBox.notify(interp.arg(b,1),interp.arg(b,0)); + if(dialogBoxActive == dialogBoxAllowed) return; + dialogBoxActive++; + DialogBox.notify(interp.arg(b,1),interp.arg(b,0),null,false, function(d:*):*{ dialogBoxActive--; }); } // TODO: move to stage From f76e574c97f1dc640dcbf6f41667c5161131af24 Mon Sep 17 00:00:00 2001 From: Alexander Liu Date: Fri, 3 Jun 2016 15:05:19 +0700 Subject: [PATCH 056/141] Add "the constant [ v]" blocks (#9) * Update Specs.as * Update Primitives.as * Update Specs.as * Update Specs.as * Update BlockMenus.as --- src/Specs.as | 1 + src/primitives/Primitives.as | 8 ++++++++ src/scratch/BlockMenus.as | 9 ++++++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/Specs.as b/src/Specs.as index 2012c9546..774180cc8 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -374,6 +374,7 @@ public class Specs { ["round %n", "r", 8, "rounded", ""], ["-"], ["%m.mathOp of %n", "r", 8, "computeFunction:of:", "sqrt", 9], + ["the constant %m.constantName", "r", 8, "chooseConstant:", "Pi"], ["reverse %s", "r", 8, "reverseString:", "hello"], // variables diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index 6e93d281c..4cc9ba7b4 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -73,6 +73,7 @@ public class Primitives { primTable["%"] = primModulo; primTable["rounded"] = function(b:*):* { return Math.round(interp.numarg(b, 0)) }; primTable["computeFunction:of:"] = primMathFunction; + primTable["chooseConstant:"] = primGetConstant; // clone primTable["createCloneOf"] = primCreateCloneOf; @@ -231,6 +232,13 @@ public class Primitives { } + private function primGetConstant(b:Block):Number { + var pickConstant:* = interp.arg(b, 0); + switch(pickConstant) { + case "Pi": return Math.PI; + } + return 0; + } // Sharp --- HTTP private function primHttp(b:Block):void { if(httpRequestsActive == httpRequestsAllowed) return; diff --git a/src/scratch/BlockMenus.as b/src/scratch/BlockMenus.as index abcf4cb5c..2726fea88 100644 --- a/src/scratch/BlockMenus.as +++ b/src/scratch/BlockMenus.as @@ -102,6 +102,7 @@ public class BlockMenus implements DragClient { if (menuName == 'videoMotionType') menuHandler.videoMotionTypeMenu(evt); if (menuName == 'videoState') menuHandler.videoStateMenu(evt); if (menuName == 'httpMethod') menuHandler.httpMethodMenu(evt); + if (menuName == 'constantName') menuHandler.constantMenu(evt); } public static function strings():Array { @@ -117,6 +118,7 @@ public class BlockMenus implements DragClient { handler.broadcastMenu(evt); handler.broadcastInfoMenu(evt); handler.costumeMenu(evt); + handler.constantMenu(evt); handler.dirMenu(evt); handler.drumMenu(evt); handler.effectMenu(evt); @@ -858,5 +860,10 @@ public class BlockMenus implements DragClient { m.addItem('GET'); showMenu(m); } - + + private function constantMenu(evt:MouseEvent):void { + var m:Menu = new Menu(setBlockArg, 'constantName'); + m.addItem('Pi'); + showMenu(m); + } }} From 9c2eed5144749983485aaf5b89b0cff78b30ea6d Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Mon, 6 Jun 2016 19:42:22 +1000 Subject: [PATCH 057/141] Update README.md --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index 442dadc93..b0425ee78 100644 --- a/README.md +++ b/README.md @@ -9,3 +9,14 @@ Sharp Scratch Mod by DrKat123 and Mrcomputer1 [Scratch topic](https://scratch.mit.edu/discuss/topic/199192/) Looking for the Scratch readme? https://github.com/SharpScratchMod/Sharp/blob/master/README_Scratch.md + +##Versions +WARNING: The listed dates are not final + +Version | Code Name | LTS | Released | Still supported | Supported until | Notes +------------------ | ---------------- | --- | -------- | --------------- | --------------- | ----------------------------- +1.0.0 (Release) | Katana | NO | NO | --NOT YET-- | --NOT YET-- | +1.0.0 Beta | Chainsaw | NO | NO | --NOT YET-- | --NOT YET-- | +1.1.0 Alpha | Sawtooth | NO | NO | --NOT YET-- | --NOT YET-- | +1.0.1 Alpha | Butterknife | NO | NO | --NOT YET-- | --NOT YET-- | Will replace 1.0.0 Alpha support +1.0.0 Alpha | Butterknife | NO | YES | YES | 30 Oct 2016 | From 62322dce9e99ee8f0980393e859c701c83c75d67 Mon Sep 17 00:00:00 2001 From: DrKat123 Date: Tue, 7 Jun 2016 17:00:43 +0700 Subject: [PATCH 058/141] Updates --- src/Specs.as | 9 +++++++-- src/primitives/Primitives.as | 1 + src/primitives/SensingPrims.as | 2 +- src/scratch/BlockMenus.as | 1 + 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Specs.as b/src/Specs.as index 774180cc8..e75bb7e82 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -313,7 +313,12 @@ public class Specs { ["-"], ["current %m.timeAndDate", "r", 7, "timeAndDate", "minute"], ["days since 2000", "r", 7, "timestamp"], - ["username", "r", 7, "getUserName"], + //["username", "r", 7, "getUserName"], + + //---- + //NOTE: + //The username block is disabled temporarily, until the sharp-www is released and is functioning properly + //---- // stage sensing ["ask %s and wait", " ", 107, "doAsk", "What's your name?"], @@ -374,7 +379,7 @@ public class Specs { ["round %n", "r", 8, "rounded", ""], ["-"], ["%m.mathOp of %n", "r", 8, "computeFunction:of:", "sqrt", 9], - ["the constant %m.constantName", "r", 8, "chooseConstant:", "Pi"], + ["the constant %m.constantName", "r", 8, "chooseConstant:", "Pi"], ["reverse %s", "r", 8, "reverseString:", "hello"], // variables diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index 4cc9ba7b4..65bd2b946 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -236,6 +236,7 @@ public class Primitives { var pickConstant:* = interp.arg(b, 0); switch(pickConstant) { case "Pi": return Math.PI; + case "E": return Math.E; } return 0; } diff --git a/src/primitives/SensingPrims.as b/src/primitives/SensingPrims.as index 70d9e4bef..a4ea745ff 100644 --- a/src/primitives/SensingPrims.as +++ b/src/primitives/SensingPrims.as @@ -64,7 +64,7 @@ public class SensingPrims { primTable['isLoud'] = function(b:*):* { return app.runtime.isLoud() }; primTable['timestamp'] = primTimestamp; primTable['timeAndDate'] = function(b:*):* { return app.runtime.getTimeString(interp.arg(b, 0)) }; - primTable['getUserName'] = function(b:*):* { return '' }; + //primTable['getUserName'] = function(b:*):* { return '' }; // sensor primTable['sensor:'] = function(b:*):* { return app.runtime.getSensor(interp.arg(b, 0)) }; diff --git a/src/scratch/BlockMenus.as b/src/scratch/BlockMenus.as index 2726fea88..bc5656c6d 100644 --- a/src/scratch/BlockMenus.as +++ b/src/scratch/BlockMenus.as @@ -864,6 +864,7 @@ public class BlockMenus implements DragClient { private function constantMenu(evt:MouseEvent):void { var m:Menu = new Menu(setBlockArg, 'constantName'); m.addItem('Pi'); + m.addItem('E'); showMenu(m); } }} From a5faeb518862a5f9e45dbfae040d5cba408d0ca0 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Wed, 8 Jun 2016 16:28:57 +1000 Subject: [PATCH 059/141] Set version to 1.0.1 ready for alpha 1.0.1 release --- src/Scratch.as | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Scratch.as b/src/Scratch.as index d5c2dac90..8ed44f2e4 100644 --- a/src/Scratch.as +++ b/src/Scratch.as @@ -76,7 +76,7 @@ import watchers.ListWatcher; public class Scratch extends Sprite { // Version - public static const versionString:String = 'Alpha 1.0.0 (Butterknife) : Scratch v447'; + public static const versionString:String = 'Alpha 1.0.1 (Butterknife) : Scratch v447'; public static var app:Scratch; // static reference to the app, used for debugging // Sharp settings store From cbbc56820b65fcc6b4355e5ff248d868717d0bde Mon Sep 17 00:00:00 2001 From: Alexander Liu Date: Sat, 11 Jun 2016 08:08:52 +0700 Subject: [PATCH 060/141] Update Specs.as --- src/Specs.as | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Specs.as b/src/Specs.as index 094a70139..059127699 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -380,7 +380,8 @@ public class Specs { ["-"], ["%m.mathOp of %n", "r", 8, "computeFunction:of:", "sqrt", 9], ["the constant %m.constantName", "r", 8, "chooseConstant:", "Pi"], - ["reverse %s", "r", 8, "reverseString:", "hello"], + ["reverse %s", "r", 8, "reverseString:", "hello"], + ["split %s from letter %n to %n", "r", 8, "splitStringFrom:", "Foobar", "1", "3"], // variables ["set %m.var to %s", " ", 9, SET_VAR], From 9c9d50dd1e2bf2d22dbe05e2f9066fdfb8e6131f Mon Sep 17 00:00:00 2001 From: NoMod-Programming Date: Fri, 10 Jun 2016 18:11:03 -0700 Subject: [PATCH 061/141] Fully Implemented Custom Reporters (#12) --- src/Specs.as | 5 + src/blocks/Block.as | 46 +--- src/blocks/BlockIO.as | 13 +- src/blocks/BlockShape.as | 22 +- src/extensions/ExtensionManager.as | 65 +++-- src/interpreter/Interpreter.as | 380 ++++++++++++++++------------ src/interpreter/Thread.as | 47 ++-- src/primitives/ListPrims.as | 51 ++-- src/primitives/LooksPrims.as | 101 ++++---- src/primitives/MotionAndPenPrims.as | 102 ++++---- src/primitives/Primitives.as | 103 ++++---- src/primitives/SensingPrims.as | 69 ++--- src/primitives/SoundPrims.as | 208 +++++++-------- src/primitives/VideoMotionPrims.as | 12 +- src/scratch/BlockMenus.as | 3 +- src/scratch/PaletteBuilder.as | 13 +- src/scratch/ScratchRuntime.as | 10 +- src/ui/ProcedureSpecEditor.as | 157 +++++++----- 18 files changed, 727 insertions(+), 680 deletions(-) diff --git a/src/Specs.as b/src/Specs.as index 059127699..a454b2485 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -36,6 +36,8 @@ public class Specs { public static const CHANGE_VAR:String = "changeVar:by:"; public static const GET_LIST:String = "contentsOfList:"; public static const CALL:String = "call"; + public static const CALL_BOOLEAN:String = "callb"; + public static const CALL_NUMBER:String = "callr"; public static const PROCEDURE_DEF:String = "procDef"; public static const GET_PARAM:String = "getParam"; @@ -403,6 +405,9 @@ public class Specs { ["show list %m.list", " ", 12, "showList:"], ["hide list %m.list", " ", 12, "hideList:"], + // custom blocks + ["report %s", "f", 10, "report", ""], + // Sharp // --HTTP-- ["%m.httpMethod %s", " ", 13, "httpBlock:", "GET", "https://api.scratch.mit.edu"], diff --git a/src/blocks/Block.as b/src/blocks/Block.as index 2ef4f7d85..03a31f5c5 100644 --- a/src/blocks/Block.as +++ b/src/blocks/Block.as @@ -64,21 +64,18 @@ public class Block extends Sprite { private static var useEmbeddedFont:Boolean = false; public static var MenuHandlerFunction:Function; // optional function to handle block and blockArg menus - - public var isCustomReporter:Boolean = false; - public var isCustomBoolean:Boolean = false; - - public var isReturnBlock:Boolean = false; public var spec:String; public var type:String; public var op:String = ""; public var opFunction:Function; + public var isSpecialOp:Boolean = false; public var args:Array = []; public var defaultArgValues:Array = []; public var parameterIndex:int = -1; // cache of parameter index, used by GET_PARAM block public var parameterNames:Array; // used by procedure definition hats; null for other blocks public var warpProcFlag:Boolean; // used by procedure definition hats to indicate warp speed + public var procedureType:String; // used by procedure definition hats; " ", "r", or "b" public var rightToLeft:Boolean; public var isHat:Boolean = false; @@ -120,7 +117,6 @@ public class Block extends Sprite { this.spec = Translator.map(spec); this.type = type; this.op = op; - if(op == "call" && type == "r" || type == "b") isReturnBlock = true; if ((Specs.CALL == op) || (Specs.GET_LIST == op) || @@ -137,14 +133,14 @@ public class Block extends Sprite { if ((type == " ") || (type == "") || (type == "w")) { base = new BlockShape(BlockShape.CmdShape, color); indentTop = 3; - } else if (type == "b") { - base = new BlockShape(BlockShape.BooleanShape, color); + } else if (type == "b" || type == "ob") { + base = new BlockShape(type == "ob" ? BlockShape.BooleanOutlineShape : BlockShape.BooleanShape, color); isReporter = true; indentLeft = 9; indentRight = 7; - } else if (type == "r" || type == "R") { + } else if (type == "r" || type == "R" || type == "or") { this.type = 'r'; - base = new BlockShape(BlockShape.NumberShape, color); + base = new BlockShape(type == "or" ? BlockShape.NumberOutlineShape : BlockShape.NumberShape, color); isReporter = true; forceAsync = (type == 'r') && Scratch.app.extensionManager.shouldForceAsync(op); isRequester = (type == 'R') || forceAsync; @@ -171,7 +167,7 @@ public class Block extends Sprite { base = new BlockShape(BlockShape.FinalCmdShape, color); isTerminal = true; indentTop = 5; - } else if (type == "o") { // cmd outline for proc definition + } else if (type == "o" || type == "o ") { // cmd outline for proc definition base = new BlockShape(BlockShape.CmdOutlineShape, color); base.filters = []; // no bezel indentTop = 3; @@ -187,25 +183,6 @@ public class Block extends Sprite { addEventListener(FocusEvent.KEY_FOCUS_CHANGE, focusChange); } - public static const CUSTOM_COMMAND:Number = 0; - public static const CUSTOM_REPORTER:Number = 1; - public static const CUSTOM_BOOLEAN:Number = 2; - - public function setCustomBlockType(bType:Number = CUSTOM_COMMAND):void{ - if(bType == CUSTOM_COMMAND){ - isCustomBoolean = false; - isCustomReporter = false; - }else if(bType == CUSTOM_REPORTER){ - isCustomBoolean = false; - isCustomReporter = true; - }else if(bType == CUSTOM_BOOLEAN){ - isCustomBoolean = true; - isCustomReporter = false; - }else{ - setCustomBlockType(CUSTOM_COMMAND); - } - } - public function setSpec(newSpec:String, defaultArgs:Array = null):void { for each (var o:DisplayObject in labelsAndArgs) { if (o.parent != null) o.parent.removeChild(o); @@ -305,7 +282,7 @@ public class Block extends Sprite { // Create a block representing a procedure declaration to be embedded in a // procedure definition header block. For each formal parameter, embed a // reporter for that parameter. - var b:Block = new Block(spec, "o", Specs.procedureColor, 'proc_declaration'); + var b:Block = new Block(spec, "o" + procedureType, Specs.procedureColor, 'proc_declaration'); if (!parameterNames) parameterNames = []; for (var i:int = 0; i < parameterNames.length; i++) { var argType:String = (typeof(defaultArgValues[i]) == 'boolean') ? 'b' : 'r'; @@ -512,7 +489,7 @@ public class Block extends Sprite { for (i = 0; i < labelsAndArgs.length; i++) { item = labelsAndArgs[i]; // Next line moves the argument of if and if-else blocks right slightly: - if ((i == 1) && !(argTypes[i] == 'label')) x = Math.max(x, 30); + if (!isReporter && i == 1 && !(argTypes[i] == 'label')) x = Math.max(x, 30); item.x = x; maxH = Math.max(maxH, item.height); x += item.width + 2; @@ -526,7 +503,7 @@ public class Block extends Sprite { if ((item is BlockArg) && (!BlockArg(item).numberType)) item.y += 1; } - if ([' ', '', 'o'].indexOf(type) >= 0) x = Math.max(x, minCommandWidth); // minimum width for command blocks + if ([' ', '', 'o ', 'o'].indexOf(type) >= 0) x = Math.max(x, minCommandWidth); // minimum width for command blocks if (['c', 'cf', 'e'].indexOf(type) >= 0) x = Math.max(x, minLoopWidth); // minimum width for C and E blocks if (['h'].indexOf(type) >= 0) x = Math.max(x, minHatWidth); // minimum width for hat blocks if (elseLabel) x = Math.max(x, indentLeft + elseLabel.width + 2); @@ -599,12 +576,13 @@ public class Block extends Sprite { public function duplicate(forClone:Boolean, forStage:Boolean = false):Block { var newSpec:String = spec; if (op == 'whenClicked') newSpec = forStage ? 'when Stage clicked' : 'when this sprite clicked'; - var dup:Block = new Block(newSpec, type, (int)(forClone ? -1 : base.color), op); + var dup:Block = new Block(newSpec, procedureType ? procedureType : type, (int)(forClone ? -1 : base.color), op); dup.isRequester = isRequester; dup.forceAsync = forceAsync; dup.parameterNames = parameterNames; dup.defaultArgValues = defaultArgValues; dup.warpProcFlag = warpProcFlag; + dup.procedureType = procedureType; if (forClone) { dup.copyArgsForClone(args); } else { diff --git a/src/blocks/BlockIO.as b/src/blocks/BlockIO.as index e79fe029f..d80848292 100644 --- a/src/blocks/BlockIO.as +++ b/src/blocks/BlockIO.as @@ -70,8 +70,12 @@ public class BlockIO { if (b.op == Specs.GET_LIST) return [Specs.GET_LIST, b.spec]; // list reporter if (b.op == Specs.GET_PARAM) return [Specs.GET_PARAM, b.spec, b.type]; // parameter reporter if (b.op == Specs.PROCEDURE_DEF) // procedure definition - return [Specs.PROCEDURE_DEF, b.spec, b.parameterNames, b.defaultArgValues, b.warpProcFlag]; - if (b.op == Specs.CALL) result = [Specs.CALL, b.spec]; // procedure call - arguments follow spec + return [Specs.PROCEDURE_DEF, b.spec, b.parameterNames, b.defaultArgValues, b.warpProcFlag, b.procedureType]; + if (b.op == Specs.CALL) { + // procedure call - arguments follow spec + // because procedures used to only be commands, they didn't store their type in the array format; to maintain backwards compatibility, we store the type by splitting Specs.CALL into separate selectors for each type + result = [b.type == 'b' ? Specs.CALL_BOOLEAN : b.type == 'r' ? Specs.CALL_NUMBER : Specs.CALL, b.spec]; + } for each (var a:* in b.normalizedArgs()) { // Note: arguments are always saved in normalized (i.e. left-to-right) order if (a is Block) result.push(blockToArray(a)); @@ -101,8 +105,8 @@ public class BlockIO { b = convertOldCmd(cmd); if (b) { b.fixArgLayout(); return b } - if (cmd[0] == Specs.CALL) { - b = new Block(cmd[1], '', Specs.procedureColor, Specs.CALL); + if (cmd[0] == Specs.CALL || cmd[0] == Specs.CALL_BOOLEAN || cmd[0] == Specs.CALL_NUMBER) { + b = new Block(cmd[1], cmd[0] == Specs.CALL_BOOLEAN ? 'b' : cmd[0] == Specs.CALL_NUMBER ? 'r' : '', Specs.procedureColor, Specs.CALL); cmd.splice(0, 1); } else { var spec:Array = specForCmd(cmd, undefinedBlockType); @@ -191,6 +195,7 @@ public class BlockIO { b.parameterNames = cmd[2]; b.defaultArgValues = cmd[3]; if (cmd.length > 4) b.warpProcFlag = cmd[4]; + if (cmd.length > 5) b.procedureType = cmd[5]; b.setSpec(cmd[1]); b.fixArgLayout(); return b; diff --git a/src/blocks/BlockShape.as b/src/blocks/BlockShape.as index 0aa3cd98a..d44a4019d 100644 --- a/src/blocks/BlockShape.as +++ b/src/blocks/BlockShape.as @@ -42,6 +42,8 @@ public class BlockShape extends Shape { public static const FinalLoopShape:int = 10; // E-shaped blocks public static const IfElseShape:int = 11; + public static const BooleanOutlineShape:int = 12; + public static const NumberOutlineShape:int = 13; // Geometry public static const NotchDepth:int = 3; @@ -187,6 +189,8 @@ public class BlockShape extends Shape { case CmdShape: case FinalCmdShape: drawFunction = drawCmdShape; break; case CmdOutlineShape: drawFunction = drawCmdOutlineShape; break; + case BooleanOutlineShape: drawFunction = drawBooleanOutlineShape; break; + case NumberOutlineShape: drawFunction = drawNumberOutlineShape; break; case LoopShape: case FinalLoopShape: drawFunction = drawLoopShape; break; case IfElseShape: drawFunction = drawIfElseShape; break; @@ -207,6 +211,13 @@ public class BlockShape extends Shape { g.lineTo(w - centerY, topH); } + private function drawBooleanOutlineShape(g:Graphics):void { + g.endFill(); + g.lineStyle(2, 0xFFFFFF, 0.2); + drawBooleanShape(g); + g.lineTo(topH / 2, topH); + } + private function drawNumberShape(g:Graphics):void { var centerY:int = topH / 2; g.moveTo(centerY, topH); @@ -217,6 +228,13 @@ public class BlockShape extends Shape { curve(w, centerY, w - centerY, topH); } + private function drawNumberOutlineShape(g:Graphics):void { + g.endFill(); + g.lineStyle(2, 0xFFFFFF, 0.2); + drawNumberShape(g); + g.lineTo(topH / 2, topH); + } + private function drawCmdShape(g:Graphics):void { drawTop(g); drawRightAndBottom(g, topH, (shape != FinalCmdShape)); @@ -335,7 +353,7 @@ public class BlockShape extends Shape { } private function curve(p1x:int, p1y:int, p2x:int, p2y:int, roundness:Number = 0.42):void { - // Compute the Bezier control point by following an orthogonal vector from the midpoint + // Compute the Bezier control point by following an orthogal vector from the midpoint // of the line between p1 and p2 scaled by roundness * dist(p1, p2). The default roundness // approximates a circular arc. Negative roundness gives a concave curve. @@ -346,4 +364,4 @@ public class BlockShape extends Shape { graphics.curveTo(cx, cy, p2x, p2y); } -}} +}} \ No newline at end of file diff --git a/src/extensions/ExtensionManager.as b/src/extensions/ExtensionManager.as index 5dfd07455..607400c81 100644 --- a/src/extensions/ExtensionManager.as +++ b/src/extensions/ExtensionManager.as @@ -391,18 +391,17 @@ public class ExtensionManager { // Execution //------------------------------ - public function primExtensionOp(b:Block):* { + public function primExtensionOp(args:Array):* { + var activeThread:Thread = app.interp.activeThread; + var b:Block = activeThread.block; var unpackedOp:Array = unpackExtensionAndOp(b.op); var extName:String = unpackedOp[0]; var ext:ScratchExtension = extensionDict[extName]; if (ext == null) return 0; // unknown extension var primOrVarName:String = unpackedOp[1]; - var args:Array = []; - for (var i:int = 0; i < b.args.length; i++) { - args.push(app.interp.arg(b, i)); - } var value:*; + if(b.isHat && b.isAsyncHat){ if(b.requestState == 0){ request(extName, primOrVarName, args, b); @@ -442,26 +441,22 @@ public class ExtensionManager { return; } else if (b.isReporter) { - if(b.isRequester) { - if(b.requestState == 2) { + if (b.isRequester) { + if (b.requestState == 2) { b.requestState = 0; - return b.response; - } - else if(b.requestState == 0) { + activeThread.popState(); + activeThread.values.push(b.response); + return; + } else if(b.requestState == 0) { request(extName, primOrVarName, args, b); } - - // Returns null if we just made a request or we're still waiting - return null; - } - else { + } else { var sensorName:String = primOrVarName; - if(ext.port > 0) { // we were checking ext.isInternal before, should we? + if (ext.port > 0) { // we were checking ext.isInternal before, should we? sensorName = encodeURIComponent(sensorName); for each (var a:* in args) sensorName += '/' + encodeURIComponent(a); // append menu args value = ext.stateVars[sensorName]; - } - else if(Scratch.app.jsEnabled) { + } else if(Scratch.app.jsEnabled) { // JavaScript if (Scratch.app.isOffline) { throw new IllegalOperationError("JS reporters must be requesters in Offline."); @@ -472,7 +467,9 @@ public class ExtensionManager { } if (value == undefined) value = 0; // default to zero if missing if ('b' == b.type) value = (ext.port>0 ? 'true' == value : true == value); // coerce value to a boolean - return value; + activeThread.popState(); + activeThread.values.push(value); + return } } else { if ('w' == b.type) { @@ -484,12 +481,13 @@ public class ExtensionManager { app.interp.doYield(); justStartedWait = true; - if(ext.port == 0) { + if (ext.port == 0) { activeThread.firstTime = false; - if(app.jsEnabled) + if (app.jsEnabled) { app.externalCall('ScratchExtensions.runAsync', null, ext.name, primOrVarName, args, id); - else + } else { ext.busy.pop(); + } return; } @@ -501,6 +499,10 @@ public class ExtensionManager { } else { activeThread.tmp = 0; activeThread.firstTime = true; + var block:Block = activeThread.block; + activeThread.popState(); + if (block.nextBlock) + activeThread.pushStateForBlock(block.nextBlock); } return; } @@ -514,22 +516,13 @@ public class ExtensionManager { if (ext == null) return; // unknown extension if (ext.port > 0) { var activeThread:Thread = app.interp.activeThread; - if(activeThread && op != 'reset_all') { - if(activeThread.firstTime) { - httpCall(ext, op, args); - activeThread.firstTime = false; - app.interp.doYield(); - } - else { - activeThread.firstTime = true; - } - } - else { httpCall(ext, op, args); - } + activeThread.firstTime = false; + app.interp.doYield(); } else { + if (op == 'reset_all') op = 'resetAll'; if (Scratch.app.jsEnabled) { - if (op == 'reset_all') { + if (op == 'resetAll') { app.externalCall('ScratchExtensions.stop', null, ext.name); } else { @@ -726,4 +719,4 @@ public class ExtensionManager { } return false; } -}} +}} \ No newline at end of file diff --git a/src/interpreter/Interpreter.as b/src/interpreter/Interpreter.as index 379214324..68823ac4b 100644 --- a/src/interpreter/Interpreter.as +++ b/src/interpreter/Interpreter.as @@ -80,6 +80,7 @@ public class Interpreter { private var app:Scratch; private var primTable:Dictionary; // maps opcodes to functions + private var specialTable:Dictionary; // blocks that require special op functions private var threads:Array = []; // all threads private var yield:Boolean; // set true to indicate that active thread should yield control private var startTime:int; // start time for stepThreads() @@ -95,6 +96,10 @@ public class Interpreter { protected var debugFunc:Function; + static private var yieldBlock:Block = new Block('', '', 0, 'yield'); + static private var returnBlock:Block = new Block('', '', 0, 'doReturn', [0]); + static private var report0Block:Block = new Block('%s', '', 0, 'report', [0]); + public function Interpreter(app:Scratch) { this.app = app; initPrims(); @@ -145,9 +150,9 @@ public class Interpreter { var reporter:Block = b; var interp:Interpreter = this; b = new Block("%s", "", -1); - b.opFunction = function(b:Block):void { + b.opFunction = function(b:Array):void { var p:Point = reporter.localToGlobal(new Point(0, 0)); - app.showBubble(String(interp.arg(b, 0)), p.x, p.y, reporter.getRect(app.stage).width); + app.showBubble(String(b[0]), p.x, p.y, reporter.getRect(app.stage).width); }; b.args[0] = reporter; } @@ -263,36 +268,21 @@ public class Interpreter { return; } } + yield = false; while (true) { if (activeThread == warpThread) currentMSecs = getTimer(); evalCmd(activeThread.block); - if (yield) { - if (activeThread == warpThread) { - if ((currentMSecs - startTime) > warpMSecs) return; - yield = false; - continue; - } else return; - } - - if (activeThread.block != null) - activeThread.block = activeThread.block.nextBlock; - - while (activeThread.block == null) { // end of block sequence - if (!activeThread.popState()) return; // end of script - if ((activeThread.block == warpBlock) && activeThread.firstTime) { // end of outer warp block - clearWarpBlock(); - activeThread.block = activeThread.block.nextBlock; - continue; - } - if (activeThread.isLoop) { - if (activeThread == warpThread) { - if ((currentMSecs - startTime) > warpMSecs) return; - } else return; - } else { - if (activeThread.block.op == Specs.CALL) activeThread.firstTime = true; // in case set false by call - activeThread.block = activeThread.block.nextBlock; + if (activeThread.block == null) { + //click on reporter shows value in log + if (activeThread.values.length) { + app.jsThrowError(activeThread.values[0]); } + return; + } + if (yield) { + if (activeThread != warpThread || currentMSecs - startTime > warpMSecs) return; + yield = false; } } } @@ -303,74 +293,75 @@ public class Interpreter { } /* Evaluation */ - public function evalCmd(b:Block):* { - if (!b) return 0; // arg() and friends can pass null if arg index is out of range + public function evalCmd(b:Block):void { + var op:String = b.op; if (b.opFunction == null) { - if (ExtensionManager.hasExtensionPrefix(op)) b.opFunction = app.extensionManager.primExtensionOp; - else b.opFunction = (primTable[op] == undefined) ? primNoop : primTable[op]; - } - - // TODO: Optimize this into a cached check if the args *could* block at all - if(b.args.length && checkBlockingArgs(b)) { - doYield(); - return null; + if (ExtensionManager.hasExtensionPrefix(op)) { + b.isSpecialOp = true; + b.opFunction = app.extensionManager.primExtensionOp; + } else if (specialTable[op]){ + b.isSpecialOp = true; + b.opFunction = specialTable[op]; + } + else { + b.opFunction = (primTable[op] == undefined) ? primNoop : primTable[op]; + } } // Debug code if(debugFunc != null) debugFunc(b); - - return b.opFunction(b); - } - // Returns true if the thread needs to yield while data is requested - public function checkBlockingArgs(b:Block):Boolean { - // Do any of the arguments request data? If so, start any requests and yield. - var shouldYield:Boolean = false; - var args:Array = b.args; - for(var i:uint=0; i 0) { activeThread.tmp--; // decrement count - startCmdList(b.subStack1, true); + startCmdList(block.subStack1, true); } else { + activeThread.popState(); activeThread.firstTime = true; + if (block.nextBlock) activeThread.pushStateForBlock(block.nextBlock); } } + - private function primCodeSection(b:Block):void{ - if (activeThread.firstTime) { - var repeatCount:Number = 1; // clip to range: 0 to 2^31-1 - activeThread.tmp = repeatCount; - activeThread.firstTime = false; - } - if (activeThread.tmp > 0) { - activeThread.tmp--; // decrement count - startCmdList(b.subStack1, true); - } else { - activeThread.firstTime = true; - } + private function primCodeSection(b:Array):void { + var block:Block = activeThread.block; + activeThread.popState(); + activeThread.firstTime = true; + if (block.nextBlock) activeThread.pushStateForBlock(block.nextBlock); + startCmdList(block.subStack1, false); } - private function primStop(b:Block):void { - var type:String = arg(b, 0); + private function primStop(b:Array):void { + var type:String = b[0]; if (type == 'all') { app.runtime.stopAll(); yield = true } - if (type == 'this script') primReturn(b); + if (type == 'this script') primReturn([0]); if (type == 'other scripts in sprite') stopThreadsFor(activeThread.target, true); if (type == 'other scripts in stage') stopThreadsFor(activeThread.target, true); } - private function primWait(b:Block):void { + private function primWait(b:Array):void { if (activeThread.firstTime) { - startTimer(numarg(b, 0)); + startTimer(numarg(b[0])); redraw(); } else checkTimer(); } @@ -650,47 +679,52 @@ public class Interpreter { // Procedure call/return - private function primCall(b:Block):* { + private function primCall(b:Array):void { // Call a procedure. Handle recursive calls and "warp" procedures. - // The activeThread.firstTime flag is used to mark the first call - // to a procedure running in warp mode. activeThread.firstTime is - // false for subsequent calls to warp mode procedures. + + var block:Block = activeThread.block; // Lookup the procedure and cache for future use var obj:ScratchObj = activeThread.target; - var spec:String = b.spec; + var insideLoop:* = null; + var spec:String = block.spec; var proc:Block = obj.procCache[spec]; if (!proc) { proc = obj.lookupProcedure(spec); obj.procCache[spec] = proc; } - if (!proc) return; + if (!proc) { + if (activeThread.block.type == 'o ') activeThread.values.push(0); + activeThread.popState(); + if (block.nextBlock) activeThread.pushStateForBlock(block.nextBlock); + return; + } if (warpThread) { - activeThread.firstTime = false; - if ((currentMSecs - startTime) > warpMSecs) yield = true; + if (currentMSecs - startTime > warpMSecs) yield = true; } else { if (proc.warpProcFlag) { // Start running in warp mode. - warpBlock = b; + warpBlock = block; warpThread = activeThread; - activeThread.firstTime = true; - } - else if (activeThread.isRecursiveCall(b, proc)) { + } else if (activeThread.isRecursiveCall(block, proc)) { yield = true; } } - var argCount:int = proc.parameterNames.length; - var argList:Array = []; - for (var i:int = 0; i < argCount; ++i) argList.push(arg(b, i)); - startCmdList(proc, false, argList); + activeThread.pushStateForBlock(report0Block); + activeThread.args = b; + startCmdList(proc); } - private function primReturn(b:Block):void { + private function primReturn(b:Array):void { // Return from the innermost procedure. If not in a procedure, stop the thread. - if (!activeThread.returnFromProcedure()) { + var call:Block = activeThread.returnFromProcedure(); + if (call) { + if (call.isReporter) { + activeThread.values.push(b[0]); + } + } else { activeThread.stop(); - yield = true; } } @@ -698,49 +732,59 @@ public class Interpreter { // Optimization: to avoid the cost of looking up the variable every time, // a reference to the Variable object is cached in the target object. - private function primVarGet(b:Block):* { - var target:ScratchObj = app.runtime.currentDoObj ? app.runtime.currentDoObj : activeThread.target; - - var v:Variable = target.varCache[b.spec]; + private function primVarGet(b:Array):void { + var block:Block = activeThread.block; + activeThread.popState(); + var v:Variable = activeThread.target.varCache[block.spec]; if (v == null) { - v = target.varCache[b.spec] = target.lookupOrCreateVar(b.spec); - if (v == null) return 0; + v = activeThread.target.varCache[block.spec] = activeThread.target.lookupOrCreateVar(block.spec); + if (v == null) { + activeThread.values.push(0); + return; + } } - // XXX: Do we need a get() for persistent variables here ? - return v.value; + activeThread.values.push(v.value); } - protected function primVarSet(b:Block):Variable { - var name:String = arg(b, 0); - var v:Variable = activeThread.target.varCache[name]; + protected function primVarSet(b:Array):Variable { + var v:Variable = activeThread.target.varCache[b[0]]; if (!v) { - v = activeThread.target.varCache[name] = activeThread.target.lookupOrCreateVar(name); + v = activeThread.target.varCache[b.spec] = activeThread.target.lookupOrCreateVar(b[0]); if (!v) return null; } var oldvalue:* = v.value; - v.value = arg(b, 1); + v.value = b[1]; return v; } - protected function primVarChange(b:Block):Variable { - var name:String = arg(b, 0); + protected function primVarChange(b:Array):Variable { + var name:String = b[0]; var v:Variable = activeThread.target.varCache[name]; if (!v) { v = activeThread.target.varCache[name] = activeThread.target.lookupOrCreateVar(name); if (!v) return null; } - v.value = Number(v.value) + numarg(b, 1); + v.value = Number(v.value) + b[1]; return v; } - private function primGetParam(b:Block):* { - if (b.parameterIndex < 0) { - var proc:Block = b.topBlock(); - if (proc.parameterNames) b.parameterIndex = proc.parameterNames.indexOf(b.spec); - if (b.parameterIndex < 0) return 0; + private function primGetParam(b:Array):* { + var block:Block = activeThread.block; + activeThread.popState(); + if (!block.isReporter) return; + if (block.parameterIndex < 0) { + var proc:Block = block.topBlock(); + if (proc.parameterNames) block.parameterIndex = proc.parameterNames.indexOf(block.spec); + if (block.parameterIndex < 0) { + activeThread.values.push(0); + return; + } + } + if (activeThread.args == null || block.parameterIndex >= activeThread.args.length) { + activeThread.values.push(0); + return; } - if ((activeThread.args == null) || (b.parameterIndex >= activeThread.args.length)) return 0; - return activeThread.args[b.parameterIndex]; + activeThread.values.push(activeThread.args[block.parameterIndex]); } }} diff --git a/src/interpreter/Thread.as b/src/interpreter/Thread.as index 8179c3a67..3aee1e321 100644 --- a/src/interpreter/Thread.as +++ b/src/interpreter/Thread.as @@ -36,13 +36,13 @@ public class Thread { // the following state is pushed and popped when running substacks public var block:Block; - public var isLoop:Boolean; public var firstTime:Boolean; // used by certain control structures public var tmp:int; // used by repeat and wait + public var values:Array; // the evaluated inputs public var args:Array; // arguments to a user-defined procedure // the stack - public var stack:Vector.; + private var stack:Vector.; private var sp:int; public function Thread(b:Block, targetObj:*, startupDelay:int = 0) { @@ -51,34 +51,35 @@ public class Thread { topBlock = b; startDelayCount = startupDelay; // initForBlock - block = b; - isLoop = false; + block = null; firstTime = true; tmp = 0; + values = []; + pushStateForBlock(b); } public function pushStateForBlock(b:Block):void { if (sp >= (stack.length - 1)) growStack(); var old:StackFrame = stack[sp++]; old.block = block; - old.isLoop = isLoop; old.firstTime = firstTime; old.tmp = tmp; + old.values = values; old.args = args; // initForBlock block = b; - isLoop = false; firstTime = true; tmp = 0; + values = []; } public function popState():Boolean { if (sp == 0) return false; var old:StackFrame = stack[--sp]; block = old.block; - isLoop = old.isLoop; firstTime = old.firstTime; tmp = old.tmp; + values = old.values; args = old.args; return true; } @@ -87,6 +88,7 @@ public class Thread { public function stop():void { block = null; + values = []; stack = new Vector.(4); stack[0] = new StackFrame(); stack[1] = new StackFrame(); @@ -99,7 +101,7 @@ public class Thread { var callCount:int = 5; // maximum number of enclosing procedure calls to examine for (var i:int = sp - 1; i >= 0; i--) { var b:Block = stack[i].block; - if (b.op == Specs.CALL) { + if (b && b.op == Specs.CALL) { if (procCall == b) return true; if (procHat == target.procCache[b.spec]) return true; } @@ -108,26 +110,33 @@ public class Thread { return false; } - public function returnFromProcedure():Boolean { + public function returnFromProcedure():Block { + if (block && block.op == Specs.CALL) { + var b:Block = block; + popState(); + if (b.nextBlock) pushStateForBlock(b.nextBlock); + return block; + } for (var i:int = sp - 1; i >= 0; i--) { - if (stack[i].block.op == Specs.CALL) { - sp = i + 1; // 'hack' the stack pointer, but don't do the final popState here - block = null; // make it do the final popState through the usual stepActiveThread mechanism - return true; + b = stack[i].block; + if (b && b.op == Specs.CALL) { + sp = i; + popState(); + if (b.nextBlock) pushStateForBlock(b.nextBlock); + return b; } } - return false; + return null; } private function initForBlock(b:Block):void { block = b; - isLoop = false; firstTime = true; tmp = 0; } private function growStack():void { - // The stack is an array of Thread instances, pre-allocated for efficiency. + // The stack is an array of StackFrame instances, pre-allocated for efficiency. // When growing, the current size is doubled. var s:int = stack.length; var n:int = s + s; @@ -142,9 +151,9 @@ import blocks.*; import interpreter.*; class StackFrame { - public var block:Block; - internal var isLoop:Boolean; + internal var block:Block; internal var firstTime:Boolean; internal var tmp:int; + internal var values:Array; internal var args:Array; -} +} \ No newline at end of file diff --git a/src/primitives/ListPrims.as b/src/primitives/ListPrims.as index 10a7675ab..20c68bde0 100644 --- a/src/primitives/ListPrims.as +++ b/src/primitives/ListPrims.as @@ -39,7 +39,7 @@ public class ListPrims { this.interp = interpreter; } - public function addPrimsTo(primTable:Dictionary):void { + public function addPrimsTo(primTable:Dictionary, specialTable:Dictionary):void { primTable[Specs.GET_LIST] = primContents; primTable['append:toList:'] = primAppend; primTable['deleteLine:ofList:'] = primDelete; @@ -50,7 +50,7 @@ public class ListPrims { primTable['list:contains:'] = primContains; } - private function primContents(b:Block):String { + private function primContents(b:Array):String { var list:ListWatcher = interp.targetObj().lookupOrCreateList(b.spec); if (!list) return ''; var allSingleLetters:Boolean = true; @@ -63,10 +63,10 @@ public class ListPrims { return (list.contents.join(allSingleLetters ? '' : ' ')); } - private function primAppend(b:Block):void { - var list:ListWatcher = listarg(b, 1); + private function primAppend(b:Array):void { + var list:ListWatcher = listarg(b[1]); if (!list) return; - listAppend(list, interp.arg(b, 0)); + listAppend(list, b[0]); if (list.visible) list.updateWatcher(list.contents.length, false, interp); } @@ -74,9 +74,9 @@ public class ListPrims { list.contents.push(item); } - private function primDelete(b:Block):void { - var which:* = interp.arg(b, 0); - var list:ListWatcher = listarg(b, 1); + private function primDelete(b:Array):void { + var which:* = b[0]; + var list:ListWatcher = listarg(b[1]); if (!list) return; var len:int = list.contents.length; if (which == 'all') { @@ -100,9 +100,9 @@ public class ListPrims { } private function primInsert(b:Block):void { - var val:* = interp.arg(b, 0); - var where:* = interp.arg(b, 1); - var list:ListWatcher = listarg(b, 2); + var val:* = b[0]; + var where:* = b[1]; + var list:ListWatcher = listarg(b[2]); if (!list) return; if (where == 'last') { listAppend(list, val); @@ -119,12 +119,12 @@ public class ListPrims { list.contents.splice(i - 1, 0, item); } - private function primReplace(b:Block):void { - var list:ListWatcher = listarg(b, 1); + private function primReplace(b:Array):void { + var list:ListWatcher = listarg(b[1]); if (!list) return; - var i:int = computeIndex(interp.arg(b, 0), list.contents.length); + var i:int = computeIndex(b[0], list.contents.length); if (i < 0) return; - listReplace(list, i, interp.arg(b, 2)); + listReplace(list, i, b[2]); if (list.visible) list.updateWatcher(i, false, interp); } @@ -132,25 +132,25 @@ public class ListPrims { list.contents[i - 1] = item; } - private function primGetItem(b:Block):* { - var list:ListWatcher = listarg(b, 1); + private function primGetItem(b:Array):* { + var list:ListWatcher = listarg(b[1]); if (!list) return ''; - var i:int = computeIndex(interp.arg(b, 0), list.contents.length); + var i:int = computeIndex(b[0], list.contents.length); if (i < 0) return ''; if (list.visible) list.updateWatcher(i, true, interp); return list.contents[i - 1]; } - private function primLength(b:Block):Number { - var list:ListWatcher = listarg(b, 0); + private function primLength(b:Array):Number { + var list:ListWatcher = listarg(b[0]); if (!list) return 0; return list.contents.length; } - private function primContains(b:Block):Boolean { - var list:ListWatcher = listarg(b, 0); + private function primContains(b:Array):Boolean { + var list:ListWatcher = listarg(b[0]); if (!list) return false; - var item:* = interp.arg(b, 1); + var item:* = b[1]; if (list.contents.indexOf(item) >= 0) return true; for each (var el:* in list.contents) { // use Scratch comparison operator (Scratch considers the string '123' equal to the number 123) @@ -159,8 +159,7 @@ public class ListPrims { return false; } - private function listarg(b:Block, i:int):ListWatcher { - var listName:String = interp.arg(b, i); + private function listarg(listName:String):ListWatcher { if (listName.length == 0) return null; var obj:ScratchObj = interp.targetObj(); var result:ListWatcher = obj.listCache[listName]; @@ -183,4 +182,4 @@ public class ListPrims { return i; } -}} +}} \ No newline at end of file diff --git a/src/primitives/LooksPrims.as b/src/primitives/LooksPrims.as index 75aadaf8f..d47471272 100644 --- a/src/primitives/LooksPrims.as +++ b/src/primitives/LooksPrims.as @@ -38,7 +38,7 @@ public class LooksPrims { this.interp = interpreter; } - public function addPrimsTo(primTable:Dictionary):void { + public function addPrimsTo(primTable:Dictionary, specialTable:Dictionary):void { primTable['lookLike:'] = primShowCostume; primTable['nextCostume'] = primNextCostume; primTable['costumeIndex'] = primCostumeIndex; @@ -49,12 +49,12 @@ public class LooksPrims { primTable['backgroundIndex'] = primSceneIndex; primTable['sceneName'] = primSceneName; primTable['nextScene'] = function(b:*):* { startScene('next backdrop', false) }; - primTable['startScene'] = function(b:*):* { startScene(interp.arg(b, 0), false) }; - primTable['startSceneAndWait'] = function(b:*):* { startScene(interp.arg(b, 0), true) }; + primTable['startScene'] = function(b:*):* { startScene(b[0], false) }; + primTable['startSceneAndWait'] = function(b:*):* { startScene(b[0], true) }; - primTable['say:duration:elapsed:from:'] = function(b:*):* { showBubbleAndWait(b, 'talk') }; + specialTable['say:duration:elapsed:from:'] = function(b:*):* { showBubbleAndWait(b, 'talk') }; primTable['say:'] = function(b:*):* { showBubble(b, 'talk') }; - primTable['think:duration:elapsed:from:'] = function(b:*):* { showBubbleAndWait(b, 'think') }; + specialTable['think:duration:elapsed:from:'] = function(b:*):* { showBubbleAndWait(b, 'think') }; primTable['think:'] = function(b:*):* { showBubble(b, 'think') }; primTable['changeGraphicEffect:by:'] = primChangeEffect; @@ -84,16 +84,16 @@ public class LooksPrims { primTable['setRotationStyle'] = primSetRotationStyle; } - private function primNextCostume(b:Block):void { + private function primNextCostume(b:Array):void { var s:ScratchObj = interp.targetObj(); if (s != null) s.showCostume(s.currentCostumeIndex + 1); if (s.visible) interp.redraw(); } - private function primShowCostume(b:Block):void { + private function primShowCostume(b:Array):void { var s:ScratchObj = interp.targetObj(); if (s == null) return; - var arg:* = interp.arg(b, 0); + var arg:* = b[0]; if (typeof(arg) == 'number') { s.showCostume(arg - 1); } else { @@ -113,21 +113,21 @@ public class LooksPrims { if (s.visible) interp.redraw(); } - private function primCostumeIndex(b:Block):Number { + private function primCostumeIndex(b:Array):Number { var s:ScratchObj = interp.targetObj(); return (s == null) ? 1 : s.costumeNumber(); } - private function primCostumeName(b:Block):String { + private function primCostumeName(b:Array):String { var s:ScratchObj = interp.targetObj(); return (s == null) ? '' : s.currentCostume().costumeName; } - private function primSceneIndex(b:Block):Number { + private function primSceneIndex(b:Array):Number { return app.stagePane.costumeNumber(); } - private function primSceneName(b:Block):String { + private function primSceneName(b:Array):String { return app.stagePane.currentCostume().costumeName; } @@ -149,14 +149,13 @@ public class LooksPrims { var costumes:Array = app.stagePane.costumes; return costumes[(i + costumes.length) % costumes.length].costumeName; } - - private function showBubbleAndWait(b:Block, type:String):void { + private function showBubbleAndWait(b:Array, type:String):void { var text:*, secs:Number; var s:ScratchSprite = interp.targetSprite(); if (s == null) return; if (interp.activeThread.firstTime) { - text = interp.arg(b, 0); - secs = interp.numarg(b, 1); + text = b[0]; + secs = interp.numarg(b[1]); s.showBubble(text, type, b); if (s.visible) interp.redraw(); interp.startTimer(secs); @@ -167,25 +166,25 @@ public class LooksPrims { } } - private function showBubble(b:Block, type:String = null):void { + private function showBubble(b:Array, type:String = null):void { var text:*, secs:Number; var s:ScratchSprite = interp.targetSprite(); if (s == null) return; if (type == null) { // combined talk/think/shout/whisper command - type = interp.arg(b, 0); - text = interp.arg(b, 1); + type = b[0]; + text = b[1]; } else { // talk or think command - text = interp.arg(b, 0); + text = b[0]; } s.showBubble(text, type, b); if (s.visible) interp.redraw(); } - private function primChangeEffect(b:Block):void { + private function primChangeEffect(b:Array):void { var s:ScratchObj = interp.targetObj(); if (s == null) return; - var filterName:String = interp.arg(b, 0); - var delta:Number = interp.numarg(b, 1); + var filterName:String = b[0]; + var delta:Number = interp.numarg(b[1]); if(delta == 0) return; var newValue:Number = s.filterPack.getFilterSetting(filterName) + delta; @@ -194,52 +193,52 @@ public class LooksPrims { if (s.visible || s == Scratch.app.stagePane) interp.redraw(); } - private function primSetEffect(b:Block):void { + private function primSetEffect(b:Array):void { var s:ScratchObj = interp.targetObj(); if (s == null) return; - var filterName:String = interp.arg(b, 0); - var newValue:Number = interp.numarg(b, 1); + var filterName:String = b[0]; + var newValue:Number = interp.numarg(b[1]); if(s.filterPack.setFilter(filterName, newValue)) s.applyFilters(); if (s.visible || s == Scratch.app.stagePane) interp.redraw(); } - private function primClearEffects(b:Block):void { + private function primClearEffects(b:Array):void { var s:ScratchObj = interp.targetObj(); s.clearFilters(); s.applyFilters(); if (s.visible || s == Scratch.app.stagePane) interp.redraw(); } - private function primChangeSize(b:Block):void { + private function primChangeSize(b:Array):void { var s:ScratchSprite = interp.targetSprite(); if (s == null) return; var oldScale:Number = s.scaleX; - s.setSize(s.getSize() + interp.numarg(b, 0)); + s.setSize(s.getSize() + interp.numarg(b[0])); if (s.visible && (s.scaleX != oldScale)) interp.redraw(); } - private function primSetRotationStyle(b:Block):void { + private function primSetRotationStyle(b:Array):void { var s:ScratchSprite = interp.targetSprite(); - var newStyle:String = interp.arg(b, 0) as String; + var newStyle:String = b[0] as String; if ((s == null) || (newStyle == null)) return; s.setRotationStyle(newStyle); } - private function primSetSize(b:Block):void { + private function primSetSize(b:Array):void { var s:ScratchSprite = interp.targetSprite(); if (s == null) return; - s.setSize(interp.numarg(b, 0)); + s.setSize(interp.numarg(b[0])); if (s.visible) interp.redraw(); } - private function primSize(b:Block):Number { + private function primSize(b:Array):Number { var s:ScratchSprite = interp.targetSprite(); if (s == null) return 100; return Math.round(s.getSize()); // reporter returns rounded size, as in Scratch 1.4 } - private function primShow(b:Block):void { + private function primShow(b:Array):void { var s:ScratchSprite = interp.targetSprite(); if (s == null) return; s.visible = true; @@ -248,7 +247,7 @@ public class LooksPrims { if (s.visible) interp.redraw(); } - private function primHide(b:Block):void { + private function primHide(b:Array):void { var s:ScratchSprite = interp.targetSprite(); if ((s == null) || !s.visible) return; s.visible = false; @@ -256,8 +255,8 @@ public class LooksPrims { s.updateBubble(); interp.redraw(); } - - private function primHideAll(b:Block):void { + + private function primHideAll(b:Array):void { // Hide all sprites and delete all clones. Only works from the stage. if (!interp.targetObj().isStage) return; app.stagePane.deleteClones(); @@ -271,17 +270,17 @@ public class LooksPrims { interp.redraw(); } - private function primGoFront(b:Block):void { + private function primGoFront(b:Array):void { var s:ScratchSprite = interp.targetSprite(); if ((s == null) || (s.parent == null)) return; s.parent.setChildIndex(s, s.parent.numChildren - 1); if (s.visible) interp.redraw(); } - private function primGoBack(b:Block):void { + private function primGoBack(b:Array):void { var s:ScratchSprite = interp.targetSprite(); if ((s == null) || (s.parent == null)) return; - var newIndex:int = s.parent.getChildIndex(s) - interp.numarg(b, 0); + var newIndex:int = s.parent.getChildIndex(s) - interp.numarg(b[0]); newIndex = Math.max(minSpriteLayer(), Math.min(newIndex, s.parent.numChildren - 1)); if (newIndex > 0 && newIndex < s.parent.numChildren) { @@ -296,27 +295,27 @@ public class LooksPrims { return stg.getChildIndex(stg.videoImage ? stg.videoImage : stg.penLayer) + 1; } - private function primSetVideoState(b:Block):void { - app.stagePane.setVideoState(interp.arg(b, 0)); + private function primSetVideoState(b:Array):void { + app.stagePane.setVideoState(b[0]); } - private function primSetVideoTransparency(b:Block):void { - app.stagePane.setVideoTransparency(interp.numarg(b, 0)); + private function primSetVideoTransparency(b:Array):void { + app.stagePane.setVideoTransparency(interp.numarg(b[0])); app.stagePane.setVideoState('on'); } - private function primScrollAlign(b:Block):void { + private function primScrollAlign(b:Array):void { if (!interp.targetObj().isStage) return; - app.stagePane.scrollAlign(interp.arg(b, 0)); + app.stagePane.scrollAlign(b[0]); } - private function primScrollRight(b:Block):void { + private function primScrollRight(b:Array):void { if (!interp.targetObj().isStage) return; - app.stagePane.scrollRight(interp.numarg(b, 0)); + app.stagePane.scrollRight(interp.numarg(b[0])); } - private function primScrollUp(b:Block):void { + private function primScrollUp(b:Array):void { if (!interp.targetObj().isStage) return; - app.stagePane.scrollUp(interp.numarg(b, 0)); + app.stagePane.scrollUp(interp.numarg(b[0])); } }} diff --git a/src/primitives/MotionAndPenPrims.as b/src/primitives/MotionAndPenPrims.as index f101ede15..26800036e 100644 --- a/src/primitives/MotionAndPenPrims.as +++ b/src/primitives/MotionAndPenPrims.as @@ -43,7 +43,7 @@ public class MotionAndPenPrims { this.interp = interpreter; } - public function addPrimsTo(primTable:Dictionary):void { + public function addPrimsTo(primTable:Dictionary, specialTable:Dictionary):void { primTable["forward:"] = primMove; primTable["turnRight:"] = primTurnRight; primTable["turnLeft:"] = primTurnLeft; @@ -51,7 +51,7 @@ public class MotionAndPenPrims { primTable["pointTowards:"] = primPointTowards; primTable["gotoX:y:"] = primGoTo; primTable["gotoSpriteOrMouse:"] = primGoToSpriteOrMouse; - primTable["glideSecs:toX:y:elapsed:from:"] = primGlide; + specialTable["glideSecs:toX:y:elapsed:from:"] = primGlide; primTable["changeXposBy:"] = primChangeX; primTable["xpos:"] = primSetX; @@ -77,41 +77,41 @@ public class MotionAndPenPrims { primTable["stampCostume"] = primStamp; } - private function primMove(b:Block):void { + private function primMove(b:Array):void { var s:ScratchSprite = interp.targetSprite(); if (s == null) return; var radians:Number = (Math.PI * (90 - s.direction)) / 180; - var d:Number = interp.numarg(b, 0); + var d:Number = interp.numarg(b[0]); moveSpriteTo(s, s.scratchX + (d * Math.cos(radians)), s.scratchY + (d * Math.sin(radians))); } - private function primTurnRight(b:Block):void { + private function primTurnRight(b:Array):void { var s:ScratchSprite = interp.targetSprite(); if (s != null) { - s.setDirection(s.direction + interp.numarg(b, 0)); + s.setDirection(s.direction + interp.numarg(b[0])); if (s.visible) interp.redraw(); } } - private function primTurnLeft(b:Block):void { + private function primTurnLeft(b:Array):void { var s:ScratchSprite = interp.targetSprite(); if (s != null) { - s.setDirection(s.direction - interp.numarg(b, 0)); + s.setDirection(s.direction - interp.numarg(b[0])); if (s.visible) interp.redraw(); } } - private function primSetDirection(b:Block):void { + private function primSetDirection(b:Array):void { var s:ScratchSprite = interp.targetSprite(); if (s != null) { - s.setDirection(interp.numarg(b, 0)); + s.setDirection(interp.numarg(b[0])); if (s.visible) interp.redraw(); } } - private function primPointTowards(b:Block):void { + private function primPointTowards(b:Array):void { var s:ScratchSprite = interp.targetSprite(); - var p:Point = mouseOrSpritePosition(interp.arg(b, 0)); + var p:Point = mouseOrSpritePosition(b[0]); if ((s == null) || (p == null)) return; var dx:Number = p.x - s.scratchX; var dy:Number = p.y - s.scratchY; @@ -120,25 +120,25 @@ public class MotionAndPenPrims { if (s.visible) interp.redraw(); } - private function primGoTo(b:Block):void { + private function primGoTo(b:Array):void { var s:ScratchSprite = interp.targetSprite(); - if (s != null) moveSpriteTo(s, interp.numarg(b, 0), interp.numarg(b, 1)); + if (s != null) moveSpriteTo(s, interp.numarg(b[0]), interp.numarg(b[1])); } - private function primGoToSpriteOrMouse(b:Block):void { + private function primGoToSpriteOrMouse(b:Array):void { var s:ScratchSprite = interp.targetSprite(); - var p:Point = mouseOrSpritePosition(interp.arg(b, 0)); + var p:Point = mouseOrSpritePosition(b[0]); if ((s == null) || (p == null)) return; moveSpriteTo(s, p.x, p.y); } - private function primGlide(b:Block):void { + private function primGlide(b:Array):void { var s:ScratchSprite = interp.targetSprite(); if (s == null) return; if (interp.activeThread.firstTime) { - var secs:Number = interp.numarg(b, 0); - var destX:Number = interp.numarg(b, 1); - var destY:Number = interp.numarg(b, 2); + var secs:Number = interp.numarg(b[0]); + var destX:Number = interp.numarg(b[1]); + var destY:Number = interp.numarg(b[2]); if (secs <= 0) { moveSpriteTo(s, destX, destY); return; @@ -179,27 +179,27 @@ public class MotionAndPenPrims { return null; } - private function primChangeX(b:Block):void { + private function primChangeX(b:Array):void { var s:ScratchSprite = interp.targetSprite(); - if (s != null) moveSpriteTo(s, s.scratchX + interp.numarg(b, 0), s.scratchY); + if (s != null) moveSpriteTo(s, s.scratchX + interp.numarg(b[0]), s.scratchY); } - private function primSetX(b:Block):void { + private function primSetX(b:Array):void { var s:ScratchSprite = interp.targetSprite(); - if (s != null) moveSpriteTo(s, interp.numarg(b, 0), s.scratchY); + if (s != null) moveSpriteTo(s, interp.numarg(b[0]), s.scratchY); } - private function primChangeY(b:Block):void { + private function primChangeY(b:Array):void { var s:ScratchSprite = interp.targetSprite(); - if (s != null) moveSpriteTo(s, s.scratchX, s.scratchY + interp.numarg(b, 0)); + if (s != null) moveSpriteTo(s, s.scratchX, s.scratchY + interp.numarg(b[0])); } - private function primSetY(b:Block):void { + private function primSetY(b:Array):void { var s:ScratchSprite = interp.targetSprite(); - if (s != null) moveSpriteTo(s, s.scratchX, interp.numarg(b, 0)); + if (s != null) moveSpriteTo(s, s.scratchX, interp.numarg(b[0])); } - private function primBounceOffEdge(b:Block):void { + private function primBounceOffEdge(b:Array):void { var s:ScratchSprite = interp.targetSprite(); if (s == null) return; if (!turnAwayFromEdge(s)) return; @@ -207,17 +207,17 @@ public class MotionAndPenPrims { if (s.visible) interp.redraw(); } - private function primXPosition(b:Block):Number { + private function primXPosition(b:Array):Number { var s:ScratchSprite = interp.targetSprite(); return (s != null) ? snapToInteger(s.scratchX) : 0; } - private function primYPosition(b:Block):Number { + private function primYPosition(b:Array):Number { var s:ScratchSprite = interp.targetSprite(); return (s != null) ? snapToInteger(s.scratchY) : 0; } - private function primDirection(b:Block):Number { + private function primDirection(b:Array):Number { var s:ScratchSprite = interp.targetSprite(); return (s != null) ? snapToInteger(s.direction) : 0; } @@ -229,12 +229,12 @@ public class MotionAndPenPrims { return (delta < 1e-9) ? rounded : n; } - private function primClear(b:Block):void { + private function primClear(b:Array):void { app.stagePane.clearPenStrokes(); interp.redraw(); } - private function primPenDown(b:Block):void { + private function primPenDown(b:Array):void { var s:ScratchSprite = interp.targetSprite(); if (s != null) s.penIsDown = true; touch(s, s.scratchX, s.scratchY); @@ -252,47 +252,47 @@ public class MotionAndPenPrims { app.stagePane.penActivity = true; } - private function primPenUp(b:Block):void { + private function primPenUp(b:Array):void { var s:ScratchSprite = interp.targetSprite(); if (s != null) s.penIsDown = false; } - private function primSetPenColor(b:Block):void { + private function primSetPenColor(b:Array):void { var s:ScratchSprite = interp.targetSprite(); - if (s != null) s.setPenColor(interp.numarg(b, 0)); + if (s != null) s.setPenColor(interp.numarg(b[0])); } - private function primSetPenHue(b:Block):void { + private function primSetPenHue(b:Array):void { var s:ScratchSprite = interp.targetSprite(); - if (s != null) s.setPenHue(interp.numarg(b, 0)); + if (s != null) s.setPenHue(interp.numarg(b[0])); } - private function primChangePenHue(b:Block):void { + private function primChangePenHue(b:Array):void { var s:ScratchSprite = interp.targetSprite(); - if (s != null) s.setPenHue(s.penHue + interp.numarg(b, 0)); + if (s != null) s.setPenHue(s.penHue + interp.numarg(b[0])); } - private function primSetPenShade(b:Block):void { + private function primSetPenShade(b:Array):void { var s:ScratchSprite = interp.targetSprite(); - if (s != null) s.setPenShade(interp.numarg(b, 0)); + if (s != null) s.setPenShade(interp.numarg(b[0])); } - private function primChangePenShade(b:Block):void { + private function primChangePenShade(b:Array):void { var s:ScratchSprite = interp.targetSprite(); - if (s != null) s.setPenShade(s.penShade + interp.numarg(b, 0)); + if (s != null) s.setPenShade(s.penShade + interp.numarg(b[0])); } - private function primSetPenSize(b:Block):void { + private function primSetPenSize(b:Array):void { var s:ScratchSprite = interp.targetSprite(); - if (s != null) s.setPenSize(Math.max(1, Math.min(960, Math.round(interp.numarg(b, 0))))); + if (s != null) s.setPenSize(Math.max(1, Math.min(960, Math.round(interp.numarg(b[0]))))); } - private function primChangePenSize(b:Block):void { + private function primChangePenSize(b:Array):void { var s:ScratchSprite = interp.targetSprite(); - if (s != null) s.setPenSize(s.penWidth + interp.numarg(b, 0)); + if (s != null) s.setPenSize(s.penWidth + interp.numarg(b[0])); } - - private function primStamp(b:Block):void { + + private function primStamp(b:Array):void { var s:ScratchSprite = interp.targetSprite(); // In 3D mode, get the alpha from the ghost filter // Otherwise, it can be easily accessed from the color transform. diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index 65bd2b946..aa31970e2 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -48,30 +48,30 @@ public class Primitives { this.interp = interpreter; } - public function addPrimsTo(primTable:Dictionary):void { + public function addPrimsTo(primTable:Dictionary, specialTable:Dictionary):void { // operators - primTable["+"] = function(b:*):* { return interp.numarg(b, 0) + interp.numarg(b, 1) }; - primTable["-"] = function(b:*):* { return interp.numarg(b, 0) - interp.numarg(b, 1) }; - primTable["*"] = function(b:*):* { return interp.numarg(b, 0) * interp.numarg(b, 1) }; - primTable["/"] = function(b:*):* { return interp.numarg(b, 0) / interp.numarg(b, 1) }; + primTable["+"] = function(b:*):* { return interp.numarg(b[0]) + interp.numarg(b[1]) }; + primTable["-"] = function(b:*):* { return interp.numarg(b[0]) - interp.numarg(b[1]) }; + primTable["*"] = function(b:*):* { return interp.numarg(b[0]) * interp.numarg(b[1]) }; + primTable["/"] = function(b:*):* { return interp.numarg(b[0]) / interp.numarg(b[1]) }; primTable["randomFrom:to:"] = primRandom; - primTable["<"] = function(b:*):* { return compare(interp.arg(b, 0), interp.arg(b, 1)) < 0 }; - primTable["="] = function(b:*):* { return compare(interp.arg(b, 0), interp.arg(b, 1)) == 0 }; - primTable[">"] = function(b:*):* { return compare(interp.arg(b, 0), interp.arg(b, 1)) > 0 }; - primTable["&"] = function(b:*):* { return interp.arg(b, 0) && interp.arg(b, 1) }; - primTable["|"] = function(b:*):* { return interp.arg(b, 0) || interp.arg(b, 1) }; - primTable["not"] = function(b:*):* { return !interp.arg(b, 0) }; - primTable["abs"] = function(b:*):* { return Math.abs(interp.numarg(b, 0)) }; - primTable["sqrt"] = function(b:*):* { return Math.sqrt(interp.numarg(b, 0)) }; - primTable["power:of:"] = function(b:*):* { return Math.pow(interp.numarg(b, 0), interp.numarg(b, 1)) }; + primTable["<"] = function(b:*):* { return compare(b[0], b[1]) < 0 }; + primTable["="] = function(b:*):* { return compare(b[0], b[1]) == 0 }; + primTable[">"] = function(b:*):* { return compare(b[0], b[1]) > 0 }; + primTable["&"] = function(b:*):* { return interp.boolarg(b[0]) && interp.boolarg(b[1]) }; + primTable["|"] = function(b:*):* { return interp.boolarg(b[0]) || interp.boolarg(b[1]) }; + primTable["not"] = function(b:*):* { return !interp.boolarg(b[0]) }; + primTable["abs"] = function(b:*):* { return Math.abs(interp.numarg(b[0])) }; + primTable["sqrt"] = function(b:*):* { return Math.sqrt(interp.numarg(b[0])) }; + primTable["power:of:"] = function(b:*):* { return Math.pow(interp.numarg(b[0]), interp.numarg(b[1])) }; primTable["reverseString:"] = primReverseString; - primTable["concatenate:with:"] = function(b:*):* { return ("" + interp.arg(b, 0) + interp.arg(b, 1)).substr(0, 10240); }; + primTable["concatenate:with:"] = function(b:*):* { return ("" + b[0] + b[1]).substr(0, 10240); }; primTable["letter:of:"] = primLetterOf; - primTable["stringLength:"] = function(b:*):* { return String(interp.arg(b, 0)).length }; + primTable["stringLength:"] = function(b:*):* { return String(b[0]).length }; primTable["%"] = primModulo; - primTable["rounded"] = function(b:*):* { return Math.round(interp.numarg(b, 0)) }; + primTable["rounded"] = function(b:*):* { return Math.round(interp.numarg(b[0])) }; primTable["computeFunction:of:"] = primMathFunction; primTable["chooseConstant:"] = primGetConstant; @@ -94,54 +94,49 @@ public class Primitives { primTable["httpBlock:"] = primHttp; primTable["httpReturn:"] = function(b:*):* {return httpReturn}; - new LooksPrims(app, interp).addPrimsTo(primTable); - new MotionAndPenPrims(app, interp).addPrimsTo(primTable); - new SoundPrims(app, interp).addPrimsTo(primTable); - new VideoMotionPrims(app, interp).addPrimsTo(primTable); - addOtherPrims(primTable); + new LooksPrims(app, interp).addPrimsTo(primTable, specialTable); + new MotionAndPenPrims(app, interp).addPrimsTo(primTable, specialTable); + new SoundPrims(app, interp).addPrimsTo(primTable, specialTable); + new VideoMotionPrims(app, interp).addPrimsTo(primTable, specialTable); + addOtherPrims(primTable, specialTable); } - protected function addOtherPrims(primTable:Dictionary):void { - new SensingPrims(app, interp).addPrimsTo(primTable); - new ListPrims(app, interp).addPrimsTo(primTable); + protected function addOtherPrims(primTable:Dictionary, specialTable:Dictionary):void { + new SensingPrims(app, interp).addPrimsTo(primTable, specialTable); + new ListPrims(app, interp).addPrimsTo(primTable, specialTable); } - private function primRandom(b:Block):Number { - var n1:Number = interp.numarg(b, 0); - var n2:Number = interp.numarg(b, 1); + private function primRandom(b:Array):Number { + var n1:Number = interp.numarg(b[0]); + var n2:Number = interp.numarg(b[1]); var low:Number = (n1 <= n2) ? n1 : n2; var hi:Number = (n1 <= n2) ? n2 : n1; if (low == hi) return low; - // if both low and hi are ints, truncate the result to an int - var ba1:BlockArg = b.args[0] as BlockArg; - var ba2:BlockArg = b.args[1] as BlockArg; - var int1:Boolean = ba1 ? ba1.numberType == BlockArg.NT_INT : int(n1) == n1; - var int2:Boolean = ba2 ? ba2.numberType == BlockArg.NT_INT : int(n2) == n2; - if (int1 && int2) + if ((int(low) == low) && (int(hi) == hi)) { return low + int(Math.random() * ((hi + 1) - low)); - + } return (Math.random() * (hi - low)) + low; } - private function primLetterOf(b:Block):String { - var s:String = interp.arg(b, 1); - var i:int = interp.numarg(b, 0) - 1; + private function primLetterOf(b:Array):String { + var s:String = b[1]; + var i:int = interp.numarg(b[0]) - 1; if ((i < 0) || (i >= s.length)) return ""; return s.charAt(i); } - private function primModulo(b:Block):Number { - var n:Number = interp.numarg(b, 0); - var modulus:Number = interp.numarg(b, 1); + private function primModulo(b:Array):Number { + var n:Number = interp.numarg(b[0]); + var modulus:Number = interp.numarg(b[1]); var result:Number = n % modulus; if (result / modulus < 0) result += modulus; return result; } - private function primMathFunction(b:Block):Number { - var op:* = interp.arg(b, 0); - var n:Number = interp.numarg(b, 1); + private function primMathFunction(b:Array):Number { + var op:* = b[0]; + var n:Number = interp.numarg(b[1]); switch(op) { case "abs": return Math.abs(n); case "floor": return Math.floor(n); @@ -189,8 +184,8 @@ public class Primitives { return 1; } - private function primCreateCloneOf(b:Block):void { - var objName:String = interp.arg(b, 0); + private function primCreateCloneOf(b:Array):void { + var objName:String = b[0]; var proto:ScratchSprite = app.stagePane.spriteNamed(objName); if ('_myself_' == objName) proto = interp.activeThread.target; if (!proto) return; @@ -212,7 +207,7 @@ public class Primitives { app.runtime.cloneCount++; } - private function primDeleteClone(b:Block):void { + private function primDeleteClone(b:Array):void { var clone:ScratchSprite = interp.targetSprite(); if ((clone == null) || (!clone.isClone) || (clone.parent == null)) return; if (clone.bubble && clone.bubble.parent) clone.bubble.parent.removeChild(clone.bubble); @@ -220,9 +215,9 @@ public class Primitives { app.interp.stopThreadsFor(clone); app.runtime.cloneCount--; } - - private function primReverseString(b:Block):String { - var reverse:String = interp.arg(b, 0); + + private function primReverseString(b:Array):String { + var reverse:String = b[0]; var result:String = ""; var i:int; for(i = reverse.length; i > 0; i--) { @@ -232,8 +227,8 @@ public class Primitives { } - private function primGetConstant(b:Block):Number { - var pickConstant:* = interp.arg(b, 0); + private function primGetConstant(b:Array):Number { + var pickConstant:* = b[0]; switch(pickConstant) { case "Pi": return Math.PI; case "E": return Math.E; @@ -241,10 +236,10 @@ public class Primitives { return 0; } // Sharp --- HTTP - private function primHttp(b:Block):void { + private function primHttp(b:Array):void { if(httpRequestsActive == httpRequestsAllowed) return; httpRequestsActive++; - var url:String = interp.arg(b, 1); + var url:String = b[0]; var req:URLRequest = new URLRequest(url); req.method = URLRequestMethod.GET; diff --git a/src/primitives/SensingPrims.as b/src/primitives/SensingPrims.as index a4ea745ff..cac184325 100644 --- a/src/primitives/SensingPrims.as +++ b/src/primitives/SensingPrims.as @@ -43,13 +43,13 @@ public class SensingPrims { this.interp = interpreter; } - public function addPrimsTo(primTable:Dictionary):void { + public function addPrimsTo(primTable:Dictionary, specialTable:Dictionary):void { // sensing primTable['touching:'] = primTouching; primTable['touchingColor:'] = primTouchingColor; primTable['color:sees:'] = primColorSees; - primTable['doAsk'] = primAsk; + specialTable['doAsk'] = primAsk; primTable['answer'] = function(b:*):* { return app.runtime.lastAnswer }; primTable['mousePressed'] = function(b:*):* { return app.gh.mouseIsDown }; @@ -63,12 +63,12 @@ public class SensingPrims { primTable['soundLevel'] = function(b:*):* { return app.runtime.soundLevel() }; primTable['isLoud'] = function(b:*):* { return app.runtime.isLoud() }; primTable['timestamp'] = primTimestamp; - primTable['timeAndDate'] = function(b:*):* { return app.runtime.getTimeString(interp.arg(b, 0)) }; + primTable['timeAndDate'] = function(b:*):* { return app.runtime.getTimeString(b[0]) }; //primTable['getUserName'] = function(b:*):* { return '' }; // sensor - primTable['sensor:'] = function(b:*):* { return app.runtime.getSensor(interp.arg(b, 0)) }; - primTable['sensorPressed:'] = function(b:*):* { return app.runtime.getBooleanSensor(interp.arg(b, 0)) }; + primTable['sensor:'] = function(b:*):* { return app.runtime.getSensor(b[0]) }; + primTable['sensorPressed:'] = function(b:*):* { return app.runtime.getBooleanSensor(b[0]) }; // variable and list watchers primTable['showVariable:'] = primShowWatcher; @@ -85,18 +85,18 @@ public class SensingPrims { } // Sharp - private function primNotify(b:Block):void{ + private function primNotify(b:Array):void{ if(dialogBoxActive == dialogBoxAllowed) return; dialogBoxActive++; - DialogBox.notify(interp.arg(b,1),interp.arg(b,0),null,false, function(d:*):*{ dialogBoxActive--; }); + DialogBox.notify(b[1],b[0],null,false, function(d:*):*{ dialogBoxActive--; }); } // TODO: move to stage static private var stageRect:Rectangle = new Rectangle(0, 0, 480, 360); - private function primTouching(b:Block):Boolean { + private function primTouching(b:Array):Boolean { var s:ScratchSprite = interp.targetSprite(); if (s == null) return false; - var arg:* = interp.arg(b, 0); + var arg:* = b[0]; if ('_edge_' == arg) { if(stageRect.containsRect(s.getBounds(s.parent))) return false; @@ -132,12 +132,12 @@ public class SensingPrims { // private var testSpr:Sprite; // private var myBMTest:Bitmap; // private var stageBMTest:Bitmap; - private function primTouchingColor(b:Block):Boolean { + private function primTouchingColor(b:Array):Boolean { // Note: Attempted to switch app.stage.quality to LOW to disable anti-aliasing, which // can create false colors. Unfortunately, that caused serious performance issues. var s:ScratchSprite = interp.targetSprite(); if (s == null) return false; - var c:int = interp.arg(b, 0) | 0xFF000000; + var c:int = b[0] | 0xFF000000; var myBM:BitmapData = s.bitmap(true); var stageBM:BitmapData = stageBitmapWithoutSpriteFilteredByColor(s, c); // if(s.objName == 'sensor') { @@ -160,13 +160,13 @@ public class SensingPrims { return myBM.hitTest(new Point(0, 0), 1, stageBM, new Point(0, 0), 1); } - private function primColorSees(b:Block):Boolean { + private function primColorSees(b:Array):Boolean { // Note: Attempted to switch app.stage.quality to LOW to disable anti-aliasing, which // can create false colors. Unfortunately, that caused serious performance issues. var s:ScratchSprite = interp.targetSprite(); if (s == null) return false; - var c1:int = interp.arg(b, 0) | 0xFF000000; - var c2:int = interp.arg(b, 1) | 0xFF000000; + var c1:int = b[0] | 0xFF000000; + var c2:int = b[1] | 0xFF000000; var myBM:BitmapData = bitmapFilteredByColor(s.bitmap(true), c1); var stageBM:BitmapData = stageBitmapWithoutSpriteFilteredByColor(s, c2); // if(!testSpr) { @@ -215,7 +215,7 @@ public class SensingPrims { return app.stagePane.getBitmapWithoutSpriteFilteredByColor(s, c); } - private function primAsk(b:Block):void { + private function primAsk(b:Array):void { if (app.runtime.askPromptShowing()) { // wait if (1) some other sprite is asking (2) this question is answered (when firstTime is false) interp.doYield(); @@ -223,7 +223,7 @@ public class SensingPrims { } var obj:ScratchObj = interp.targetObj(); if (interp.activeThread.firstTime) { - var question:String = interp.arg(b, 0); + var question:String = b[0]; if ((obj is ScratchSprite) && (obj.visible)) { ScratchSprite(obj).showBubble(question, 'talk', true); app.runtime.showAskPrompt(''); @@ -234,12 +234,15 @@ public class SensingPrims { interp.doYield(); } else { if ((obj is ScratchSprite) && (obj.visible)) ScratchSprite(obj).hideBubble(); - interp.activeThread.firstTime = true; + var block:Block = interp.activeThread.block; + interp.activeThread.popState(); + interp.activeThread.firstTime = true; + if (block.nextBlock) interp.activeThread.pushStateForBlock(block.nextBlock); } } - private function primKeyPressed(b:Block):Boolean { - var key:String = interp.arg(b, 0); + private function primKeyPressed(b:Array):Boolean { + var key:String = b[0]; if (key == 'any') { for each (var k:Boolean in app.runtime.keyIsDown) { if (k) return true; @@ -256,18 +259,18 @@ public class SensingPrims { return app.runtime.keyIsDown[ch]; } - private function primDistanceTo(b:Block):Number { + private function primDistanceTo(b:Array):Number { var s:ScratchSprite = interp.targetSprite(); - var p:Point = mouseOrSpritePosition(interp.arg(b, 0)); + var p:Point = mouseOrSpritePosition(b[0]); if ((s == null) || (p == null)) return 10000; var dx:Number = p.x - s.scratchX; var dy:Number = p.y - s.scratchY; return Math.sqrt((dx * dx) + (dy * dy)); } - private function primGetAttribute(b:Block):* { - var attribute:String = interp.arg(b, 0); - var obj:ScratchObj = app.stagePane.objNamed(String(interp.arg(b, 1))); + private function primGetAttribute(b:Array):* { + var attribute:String = b[0]; + var obj:ScratchObj = app.stagePane.objNamed(String(b[1])); if (!(obj is ScratchObj)) return 0; if (obj is ScratchSprite) { var s:ScratchSprite = ScratchSprite(obj); @@ -300,27 +303,27 @@ public class SensingPrims { return null; } - private function primShowWatcher(b:Block):* { + private function primShowWatcher(b:Array):* { var obj:ScratchObj = interp.targetObj(); - if (obj) app.runtime.showVarOrListFor(interp.arg(b, 0), false, obj); + if (obj) app.runtime.showVarOrListFor(b[0], false, obj); } - private function primHideWatcher(b:Block):* { + private function primHideWatcher(b:Array):* { var obj:ScratchObj = interp.targetObj(); - if (obj) app.runtime.hideVarOrListFor(interp.arg(b, 0), false, obj); + if (obj) app.runtime.hideVarOrListFor(b[0], false, obj); } - private function primShowListWatcher(b:Block):* { + private function primShowListWatcher(b:Array):* { var obj:ScratchObj = interp.targetObj(); - if (obj) app.runtime.showVarOrListFor(interp.arg(b, 0), true, obj); + if (obj) app.runtime.showVarOrListFor(b[0], true, obj); } - private function primHideListWatcher(b:Block):* { + private function primHideListWatcher(b:Array):* { var obj:ScratchObj = interp.targetObj(); - if (obj) app.runtime.hideVarOrListFor(interp.arg(b, 0), true, obj); + if (obj) app.runtime.hideVarOrListFor(b[0], true, obj); } - private function primTimestamp(b:Block):* { + private function primTimestamp(b:Array):* { const millisecondsPerDay:int = 24 * 60 * 60 * 1000; const epoch:Date = new Date(2000, 0, 1); // Jan 1, 2000 (Note: Months are zero-based.) var now:Date = new Date(); diff --git a/src/primitives/SoundPrims.as b/src/primitives/SoundPrims.as index e25ad3d5b..caf463da3 100644 --- a/src/primitives/SoundPrims.as +++ b/src/primitives/SoundPrims.as @@ -39,16 +39,16 @@ public class SoundPrims { this.interp = interpreter; } - public function addPrimsTo(primTable:Dictionary):void { + public function addPrimsTo(primTable:Dictionary, specialTable:Dictionary):void { primTable["playSound:"] = primPlaySound; - primTable["doPlaySoundAndWait"] = primPlaySoundUntilDone; + specialTable["doPlaySoundAndWait"] = primPlaySoundUntilDone; primTable["stopAllSounds"] = function(b:*):* { ScratchSoundPlayer.stopAllSounds() }; - primTable["drum:duration:elapsed:from:"] = primPlayDrum; // Scratch 1.4 drum numbers - primTable["playDrum"] = primPlayDrum; - primTable["rest:elapsed:from:"] = primPlayRest; + specialTable["drum:duration:elapsed:from:"] = primPlayDrum; // Scratch 1.4 drum numbers + specialTable["playDrum"] = primPlayDrum; + specialTable["rest:elapsed:from:"] = primPlayRest; - primTable["noteOn:duration:elapsed:from:"] = primPlayNote; + specialTable["noteOn:duration:elapsed:from:"] = primPlayNote; primTable["midiInstrument:"] = primSetInstrument; // Scratch 1.4 instrument numbers primTable["instrument:"] = primSetInstrument; @@ -56,121 +56,96 @@ public class SoundPrims { primTable["setVolumeTo:"] = primSetVolume; primTable["volume"] = primVolume; - primTable["changeTempoBy:"] = function(b:*):* { - app.stagePane.setTempo(app.stagePane.tempoBPM + interp.numarg(b, 0)); - interp.redraw(); - }; - primTable["setTempoTo:"] = function(b:*):* { - app.stagePane.setTempo(interp.numarg(b, 0)); - interp.redraw(); - }; + primTable["changeTempoBy:"] = function(b:*):* { app.stagePane.setTempo(app.stagePane.tempoBPM + interp.numarg(b[0])) }; + primTable["setTempoTo:"] = function(b:*):* { app.stagePane.setTempo(interp.numarg(b[0])) }; primTable["tempo"] = function(b:*):* { return app.stagePane.tempoBPM }; } - private function primPlaySound(b:Block):void { - if(Scratch.app.sharpSettings.data.allowSound){ - var snd:ScratchSound = interp.targetObj().findSound(interp.arg(b, 0)); - if (snd != null) playSound(snd, interp.targetObj()); - } + private function primPlaySound(b:Array):void { + var snd:ScratchSound = interp.targetObj().findSound(b[0]); + if (snd != null) playSound(snd, interp.targetObj()); } - private function primPlaySoundUntilDone(b:Block):void { - if(Scratch.app.sharpSettings.data.allowSound){ - var activeThread:Thread = interp.activeThread; - if (activeThread.firstTime) { - var snd:ScratchSound = interp.targetObj().findSound(interp.arg(b, 0)); - if (snd == null) return; - activeThread.tmpObj = playSound(snd, interp.targetObj()); - activeThread.firstTime = false; - } - var player:ScratchSoundPlayer = ScratchSoundPlayer(activeThread.tmpObj); - if ((player == null) || (player.atEnd())) { // finished playing - activeThread.tmp = 0; - activeThread.firstTime = true; - } else { - interp.doYield(); - } + private function primPlaySoundUntilDone(b:Array):void { + var activeThread:Thread = interp.activeThread; + if (activeThread.firstTime) { + var snd:ScratchSound = interp.targetObj().findSound(b[0]); + if (snd == null) return; + activeThread.tmpObj = playSound(snd, interp.targetObj()); + activeThread.firstTime = false; + } + var player:ScratchSoundPlayer = ScratchSoundPlayer(activeThread.tmpObj); + if ((player == null) || player.atEnd()) { // finished playing + activeThread.tmp = 0; + activeThread.firstTime = true; + var block:Block = activeThread.block; + activeThread.popState(); + if (block.nextBlock) activeThread.pushStateForBlock(block.nextBlock); + } else { + interp.doYield(); } } - private function primPlayNote(b:Block):void { - if(Scratch.app.sharpSettings.data.allowSound){ - var s:ScratchObj = interp.targetObj(); - if (s == null) return; - if (interp.activeThread.firstTime) { - var key:Number = interp.numarg(b, 0); - var secs:Number = beatsToSeconds(interp.numarg(b, 1)); - interp.activeThread.tmpObj = playNote(s.instrument, key, secs, s); - interp.startTimer(secs); - } else { - interp.checkTimer(); - } + private function primPlayNote(b:Array):void { + var s:ScratchObj = interp.targetObj(); + if (s == null) return; + if (interp.activeThread.firstTime) { + var key:Number = interp.numarg(b[0]); + var secs:Number = beatsToSeconds(interp.numarg(b[1])); + interp.activeThread.tmpObj = playNote(s.instrument, key, secs, s); + interp.startTimer(secs); + } else { + interp.checkTimer(); } } - private function primPlayDrum(b:Block):void { - if(Scratch.app.sharpSettings.data.allowSound){ - var s:ScratchObj = interp.targetObj(); - if (s == null) return; - if (interp.activeThread.firstTime) { - var drum:int = Math.round(interp.numarg(b, 0)); - var isMIDI:Boolean = (b.op == 'drum:duration:elapsed:from:'); - var secs:Number = beatsToSeconds(interp.numarg(b, 1)); - playDrum(drum, isMIDI, 10, s); // always play entire drum sample - interp.startTimer(secs); - } else { - interp.checkTimer(); - } + private function primPlayDrum(b:Array):void { + var s:ScratchObj = interp.targetObj(); + if (s == null) return; + if (interp.activeThread.firstTime) { + var drum:int = Math.round(interp.numarg(b[0])); + var isMIDI:Boolean = (b.op == 'drum:duration:elapsed:from:'); + var secs:Number = beatsToSeconds(interp.numarg(b[1])); + playDrum(drum, isMIDI, 10, s); // always play entire drum sample + interp.startTimer(secs); + } else { + interp.checkTimer(); } } private function playSound(s:ScratchSound, client:ScratchObj):ScratchSoundPlayer { - if(Scratch.app.sharpSettings.data.allowSound){ - var player:ScratchSoundPlayer = s.sndplayer(); - player.client = client; - player.startPlaying(); - return player; - }else{ - return null; - } + var player:ScratchSoundPlayer = s.sndplayer(); + player.client = client; + player.startPlaying(); + return player; } private function playDrum(drum:int, isMIDI:Boolean, secs:Number, client:ScratchObj):ScratchSoundPlayer { - if(Scratch.app.sharpSettings.data.allowSound){ - var player:NotePlayer = SoundBank.getDrumPlayer(drum, isMIDI, secs); - if (player == null) return null; - player.client = client; - player.setDuration(secs); - player.startPlaying(); - return player; - }else{ - return null; - } + var player:NotePlayer = SoundBank.getDrumPlayer(drum, isMIDI, secs); + if (player == null) return null; + player.client = client; + player.setDuration(secs); + player.startPlaying(); + return player; } private function playNote(instrument:int, midiKey:Number, secs:Number, client:ScratchObj):ScratchSoundPlayer { - if(Scratch.app.sharpSettings.data.allowSound){ - var player:NotePlayer = SoundBank.getNotePlayer(instrument, midiKey); - if (player == null) return null; - player.client = client; - player.setNoteAndDuration(midiKey, secs); - player.startPlaying(); - return player; - }else{ - return null; - } + var player:NotePlayer = SoundBank.getNotePlayer(instrument, midiKey); + if (player == null) return null; + player.client = client; + player.setNoteAndDuration(midiKey, secs); + player.startPlaying(); + return player; } - private function primPlayRest(b:Block):void { - if(Scratch.app.sharpSettings.data.allowSound){ - var s:ScratchObj = interp.targetObj(); - if (s == null) return; - if (interp.activeThread.firstTime) { - var secs:Number = beatsToSeconds(interp.numarg(b, 0)); - interp.startTimer(secs); - } else { - interp.checkTimer(); - } + private function primPlayRest(b:Array):void { + var s:ScratchObj = interp.targetObj(); + if (s == null) return; + if (interp.activeThread.firstTime) { + var secs:Number = beatsToSeconds(interp.numarg(b[0])); + interp.startTimer(secs); + } else { + interp.checkTimer(); } } @@ -178,36 +153,28 @@ public class SoundPrims { return (beats * 60) / app.stagePane.tempoBPM; } - private function primSetInstrument(b:Block):void { - if(Scratch.app.sharpSettings.data.allowSound){ - // Set Scratch 2.0 instrument. - var instr:int = interp.numarg(b, 0) - 1; - if (b.op == 'midiInstrument:') { - // map old to new instrument number - instr = instrumentMap[instr] - 1; // maps to -1 if out of range - } - instr = Math.max(0, Math.min(instr, SoundBank.instrumentNames.length - 1)); - if (interp.targetObj()) interp.targetObj().instrument = instr; + private function primSetInstrument(b:Array):void { + // Set Scratch 2.0 instrument. + var instr:int = interp.numarg(b[0]) - 1; + if (b.op == 'midiInstrument:') { + // map old to new instrument number + instr = instrumentMap[instr] - 1; // maps to -1 if out of range } + instr = Math.max(0, Math.min(instr, SoundBank.instrumentNames.length - 1)); + if (interp.targetObj()) interp.targetObj().instrument = instr; } - private function primChangeVolume(b:Block):void { + private function primChangeVolume(b:Array):void { var s:ScratchObj = interp.targetObj(); - if (s != null) { - s.setVolume(s.volume + interp.numarg(b, 0)); - interp.redraw(); - } + if (s != null) s.setVolume(s.volume + interp.numarg(b[0])); } - private function primSetVolume(b:Block):void { + private function primSetVolume(b:Array):void { var s:ScratchObj = interp.targetObj(); - if (s != null) { - s.setVolume(interp.numarg(b, 0)); - interp.redraw(); - } + if (s != null) s.setVolume(interp.numarg(b[0])); } - private function primVolume(b:Block):Number { + private function primVolume(b:Array):Number { var s:ScratchObj = interp.targetObj(); return (s != null) ? s.volume : 0; } @@ -279,5 +246,4 @@ public class SoundPrims { // Telephone Ring, Helicopter, Applause, Gunshot 21, 21, 21, 21 ]; - -}} +}} \ No newline at end of file diff --git a/src/primitives/VideoMotionPrims.as b/src/primitives/VideoMotionPrims.as index 6bf77bf42..12b958348 100644 --- a/src/primitives/VideoMotionPrims.as +++ b/src/primitives/VideoMotionPrims.as @@ -65,15 +65,15 @@ public class VideoMotionPrims { frameBuffer = new BitmapData(WIDTH, HEIGHT); } - public function addPrimsTo(primTable:Dictionary):void { + public function addPrimsTo(primTable:Dictionary, specialTable:Dictionary):void { primTable['senseVideoMotion'] = primVideoMotion; readMotionSensor = getMotionOn; } - private function primVideoMotion(b:Block):Number { - var motionType:String = interp.arg(b, 0); - var obj:ScratchObj = app.stagePane.objNamed(String(interp.arg(b, 1))); - if ('this sprite' == interp.arg(b, 1)) obj = interp.targetObj(); + private function primVideoMotion(b:Array):Number { + var motionType:String = b[0]; + var obj:ScratchObj = app.stagePane.objNamed(String(b[1])); + if ('this sprite' == b[1]) obj = interp.targetObj(); return getMotionOn(motionType, obj); } @@ -282,4 +282,4 @@ public class VideoMotionPrims { analysisDone = true; } -}} +}} \ No newline at end of file diff --git a/src/scratch/BlockMenus.as b/src/scratch/BlockMenus.as index bc5656c6d..430c47e21 100644 --- a/src/scratch/BlockMenus.as +++ b/src/scratch/BlockMenus.as @@ -589,7 +589,7 @@ public class BlockMenus implements DragClient { } var d:DialogBox = new DialogBox(editSpec2); d.addTitle('Edit Block'); - d.addWidget(new ProcedureSpecEditor(block.spec, block.parameterNames, block.warpProcFlag)); + d.addWidget(new ProcedureSpecEditor(block.spec, block.parameterNames, block.warpProcFlag, block.procedureType, true)); d.addAcceptCancelButtons('OK'); d.showOnStage(app.stage, true); ProcedureSpecEditor(d.widget).setInitialFocus(); @@ -603,6 +603,7 @@ public class BlockMenus implements DragClient { block.parameterNames = ProcedureSpecEditor(dialog.widget).inputNames(); block.defaultArgValues = ProcedureSpecEditor(dialog.widget).defaultArgValues(); block.warpProcFlag = ProcedureSpecEditor(dialog.widget).warpFlag(); + block.procedureType = ProcedureSpecEditor(dialog.widget).type(); block.setSpec(newSpec); if (block.nextBlock) block.nextBlock.allBlocksDo(function(b:Block):void { if (b.op == Specs.GET_PARAM) b.parameterIndex = -1; // parameters may have changed; clear cached indices diff --git a/src/scratch/PaletteBuilder.as b/src/scratch/PaletteBuilder.as index 5890cec14..10e22d343 100644 --- a/src/scratch/PaletteBuilder.as +++ b/src/scratch/PaletteBuilder.as @@ -129,13 +129,11 @@ public class PaletteBuilder { var catColor:int = Specs.blockColor(Specs.procedureColor); addItem(new Button(Translator.map('Make a Block'), makeNewBlock, false, '/help/studio/tips/blocks/make-a-block/')); var definitions:Array = app.viewedObj().procedureDefinitions(); + addBlocksForCategory(10, Specs.procedureColor); if (definitions.length > 0) { nextY += 5; for each (var proc:Block in definitions) { - //if(!proc.isCustomReporter && !proc.isCustomBoolean) var b:Block = new Block(proc.spec, ' ', Specs.procedureColor, Specs.CALL, proc.defaultArgValues); - //if(proc.isCustomReporter && !proc.isCustomBoolean) var b:Block = new Block(proc.spec, 'r', Specs.procedureColor, Specs.CALL, proc.defaultArgValues); - //if(!proc.isCustomReporter && proc.isCustomBoolean) var b:Block = new Block(proc.spec, 'b', Specs.procedureColor, Specs.CALL, proc.defaultArgValues); - var b:Block = new Block(proc.spec, ' ', Specs.procedureColor, Specs.CALL, proc.defaultArgValues); + var b:Block = new Block(proc.spec, proc.procedureType, Specs.procedureColor, Specs.CALL, proc.defaultArgValues); addItem(b); } nextY += 5; @@ -257,10 +255,7 @@ public class PaletteBuilder { newHat.parameterNames = specEditor.inputNames(); newHat.defaultArgValues = specEditor.defaultArgValues(); newHat.warpProcFlag = specEditor.warpFlag(); - //if(specEditor.returnValuesCheckbox.isOn() && !specEditor.returnBooleanCheckbox.isOn()) newHat.setCustomBlockType(Block.CUSTOM_REPORTER); - //if(specEditor.returnValuesCheckbox.isOn() && specEditor.returnBooleanCheckbox.isOn()) newHat.setCustomBlockType(Block.CUSTOM_BOOLEAN); - //if(!specEditor.returnValuesCheckbox.isOn() && !specEditor.returnBooleanCheckbox.isOn()) newHat.setCustomBlockType(Block.CUSTOM_COMMAND); - newHat.setCustomBlockType(Block.CUSTOM_COMMAND); + newHat.procedureType = specEditor.type(); newHat.setSpec(spec); newHat.x = 10 - app.scriptsPane.x + Math.random() * 100; newHat.y = 10 - app.scriptsPane.y + Math.random() * 100; @@ -271,7 +266,7 @@ public class PaletteBuilder { app.setSaveNeeded(); } - var specEditor:ProcedureSpecEditor = new ProcedureSpecEditor('', [], false); + var specEditor:ProcedureSpecEditor = new ProcedureSpecEditor('', [], false, ' ', false); var d:DialogBox = new DialogBox(addBlockHat); d.addTitle('New Block'); d.addWidget(specEditor); diff --git a/src/scratch/ScratchRuntime.as b/src/scratch/ScratchRuntime.as index 6d914f136..9874c68f5 100644 --- a/src/scratch/ScratchRuntime.as +++ b/src/scratch/ScratchRuntime.as @@ -660,8 +660,8 @@ public class ScratchRuntime { if (!hat.isHat || !hat.nextBlock) return; // skip disconnected hats if ('whenSensorGreaterThan' == hat.op) { - var sensorName:String = interp.arg(hat, 0); - var threshold:Number = interp.numarg(hat, 1); + var sensorName:String = (hat.args[0] as BlockArg).argValue; + var threshold:Number = Number((hat.args[1] as BlockArg).argValue) || 0; if (('loudness' == sensorName && soundLevel() > threshold) || ('timer' == sensorName && timer() > threshold) || ('video motion' == sensorName && target.visible && VideoMotionPrims.readMotionSensor('motion', target) > threshold)) { @@ -672,7 +672,7 @@ public class ScratchRuntime { activeHats.push(hat); } } else if ('whenSensorConnected' == hat.op) { - if (getBooleanSensor(interp.arg(hat, 0))) { + if (getBooleanSensor((hat.args[0] as BlockArg).argValue)) { if (triggeredHats.indexOf(hat) == -1) { // not already trigged // only start the stack if it is not already running if (!interp.isRunning(hat, target)) interp.toggleThread(hat, target); @@ -687,7 +687,7 @@ public class ScratchRuntime { var numArgs:uint = hat.args.length; var finalArgs:Array = new Array(numArgs); for (var i:uint = 0; i < numArgs; ++i) - finalArgs[i] = interp.arg(hat, i); + finalArgs[i] = (hat.args[i] as BlockArg).argValue; processExtensionReporter(hat, target, extName, op, finalArgs); } @@ -752,7 +752,7 @@ public class ScratchRuntime { var op:String = b.op; if (op == Specs.GET_PARAM) b.parameterIndex = -1; // need to invalidate index cache if (('senseVideoMotion' == op) || - (('whenSensorGreaterThan' == op) && ('video motion' == interp.arg(b, 0)))) { + (('whenSensorGreaterThan' == op) && ('video motion' == (b.args[0] as BlockArg).argValue))) { app.libraryPart.showVideoButton(); } diff --git a/src/ui/ProcedureSpecEditor.as b/src/ui/ProcedureSpecEditor.as index 477e85120..79f486295 100644 --- a/src/ui/ProcedureSpecEditor.as +++ b/src/ui/ProcedureSpecEditor.as @@ -30,12 +30,17 @@ package ui { public class ProcedureSpecEditor extends Sprite { + private var isEdit:Boolean; private var base:Shape; + private var shape:int; private var blockShape:BlockShape; private var row:Array = []; private var moreLabel:TextField; private var moreButton:IconButton; + private var shapeLabels:Array = []; + private var shapeIcons:Array = []; + private var shapeButtons:Array = []; private var buttonLabels:Array = []; private var buttons:Array = []; @@ -48,11 +53,14 @@ public class ProcedureSpecEditor extends Sprite { private const labelColor:int = 0x8738bf; // 0x6c36b3; // 0x9c35b3; private const selectedLabelColor:int = 0xefa6ff; - public function ProcedureSpecEditor(originalSpec:String, inputNames:Array, warpFlag:Boolean) { + public function ProcedureSpecEditor(originalSpec:String, inputNames:Array, warpFlag:Boolean, type:String, isEdit:Boolean) { + this.isEdit = isEdit; + addChild(base = new Shape()); setWidthHeight(350, 10); - blockShape = new BlockShape(BlockShape.CmdShape, Specs.procedureColor); + shape = type == "b" ? BlockShape.BooleanShape : type == "r" ? BlockShape.NumberShape : BlockShape.CmdShape; + blockShape = new BlockShape(shape, Specs.procedureColor); blockShape.setWidthAndTopHeight(100, 25, true); addChild(blockShape); @@ -84,7 +92,9 @@ public class ProcedureSpecEditor extends Sprite { 'Add string input:', 'Add boolean input:', 'Add label text:', - 'text', + "Doesn't report", + 'Reports number or text', + 'Reports true or false', ]; } @@ -111,7 +121,7 @@ public class ProcedureSpecEditor extends Sprite { clearRow(); var i:int = 0; for each (var s:String in ReadStream.tokenize(spec)) { - if (s.length >= 2 && s.charAt(0) == '%') { // argument spec + if ((s.length >= 2) && (s.charAt(0) == '%')) { // argument spec var argSpec:String = s.charAt(1); var arg:BlockArg = null; if (argSpec == 'b') arg = makeBooleanArg(); @@ -123,11 +133,9 @@ public class ProcedureSpecEditor extends Sprite { } } else { if ((row.length > 0) && (row[row.length - 1] is TextField)) { - var tf:TextField = row[row.length - 1]; - tf.appendText(' ' + ReadStream.unescape(s)); - fixLabelWidth(tf); + TextField(row[row.length - 1]).appendText(' ' + s); } else { - addElement(makeTextField(ReadStream.unescape(s))); + addElement(makeTextField(s)); } } } @@ -138,7 +146,7 @@ public class ProcedureSpecEditor extends Sprite { public function spec():String { var result:String = ''; for each (var o:* in row) { - if (o is TextField) result += ReadStream.escape(TextField(o).text); + if (o is TextField) result += TextField(o).text; if (o is BlockArg) result += '%' + BlockArg(o).type; if ((result.length > 0) && (result.charAt(result.length - 1) != ' ')) result += ' '; } @@ -146,6 +154,10 @@ public class ProcedureSpecEditor extends Sprite { return result; } + public function type():String { + return shape == BlockShape.BooleanShape ? "b" : shape == BlockShape.NumberShape ? "r" : " "; + } + public function defaultArgValues():Array { var result:Array = []; for each (var el:* in row) { @@ -169,12 +181,22 @@ public class ProcedureSpecEditor extends Sprite { public function inputNames():Array { var result:Array = []; for each (var o:* in row) { - if (o is BlockArg) result.push(uniqueName(result, BlockArg(o).field.text)); + if (o is BlockArg) result.push(BlockArg(o).field.text); } return result; } private function addButtonsAndLabels():void { + shapeLabels = [ + makeLabel("Doesn't report", 14), + makeLabel('Reports number or text', 14), + makeLabel('Reports true or false', 14), + ]; + shapeButtons = [ + new IconButton(function():void { setShape(BlockShape.CmdShape) }, null), + new IconButton(function():void { setShape(BlockShape.NumberShape) }, null), + new IconButton(function():void { setShape(BlockShape.BooleanShape) }, null) + ]; buttonLabels = [ makeLabel('Add number input:', 14), makeLabel('Add string input:', 14), @@ -185,10 +207,26 @@ public class ProcedureSpecEditor extends Sprite { new Button('', function():void { appendObj(makeNumberArg()) }), new Button('', function():void { appendObj(makeStringArg()) }), new Button('', function():void { appendObj(makeBooleanArg()) }), - new Button(Translator.map('text'), function():void { appendObj(makeTextField('')) }) + new Button('text', function():void { appendObj(makeTextField('')) }) ]; + shapeButtons[0].setOn(true); + const lightGray:int = 0xA0A0A0; + var icon:BlockShape; + + shapeIcons = []; + icon = new BlockShape(BlockShape.CmdShape, Specs.procedureColor); + icon.setWidthAndTopHeight(34, 18, true); + shapeIcons.push(icon); + + icon = new BlockShape(BlockShape.NumberShape, Specs.procedureColor); + icon.setWidthAndTopHeight(34, 18, true); + shapeIcons.push(icon); + + icon = new BlockShape(BlockShape.BooleanShape, Specs.procedureColor); + icon.setWidthAndTopHeight(34, 18, true); + shapeIcons.push(icon); icon = new BlockShape(BlockShape.NumberShape, lightGray); icon.setWidthAndTopHeight(25, 14, true); @@ -198,12 +236,9 @@ public class ProcedureSpecEditor extends Sprite { icon.setWidthAndTopHeight(22, 14, true); buttons[1].setIcon(icon); - var icon:BlockShape = new BlockShape(BlockShape.BooleanShape, lightGray); + icon = new BlockShape(BlockShape.BooleanShape, lightGray); icon.setWidthAndTopHeight(25, 14, true); buttons[2].setIcon(icon); - - for each (var label:TextField in buttonLabels) addChild(label); - for each (var b:Button in buttons) addChild(b); } private function addwarpCheckbox():void { @@ -224,7 +259,7 @@ public class ProcedureSpecEditor extends Sprite { private function toggleButtons(ignore:*):void { var buttonsShowing:Boolean = buttons[0].parent != null; - showButtons(!buttonsShowing) + showButtons(!buttonsShowing); } private function deleteItem(ignore:*):void { @@ -241,15 +276,21 @@ public class ProcedureSpecEditor extends Sprite { } private function showButtons(showParams:Boolean):void { - var label:TextField, b:Button; + var label:TextField, b:Button, ib:IconButton, shape:BlockShape; if (showParams) { for each (label in buttonLabels) addChild(label); + if (!isEdit) for each (label in shapeLabels) addChild(label); for each (b in buttons) addChild(b); + if (!isEdit) for each (ib in shapeButtons) addChild(ib); + if (!isEdit) for each (shape in shapeIcons) addChild(shape); addChild(warpCheckbox); addChild(warpLabel); } else { for each (label in buttonLabels) if (label.parent) removeChild(label); + for each (label in shapeLabels) if (label.parent) removeChild(label); for each (b in buttons) if (b.parent) removeChild(b); + for each (ib in shapeButtons) if (b.parent) removeChild(b); + for each (shape in shapeIcons) if (shape.parent) removeChild(shape); if (warpCheckbox.parent) removeChild(warpCheckbox); if (warpLabel.parent) removeChild(warpLabel); } @@ -261,6 +302,19 @@ public class ProcedureSpecEditor extends Sprite { if (parent is DialogBox) DialogBox(parent).fixLayout(); } + private function setShape(shape:int):void { + this.shape = shape; + var ob:IconButton = shapeButtons[shape == BlockShape.BooleanShape ? 2 : shape == BlockShape.NumberShape ? 1 : 0]; + for each (var ib:IconButton in shapeButtons) { + ib.setOn(ib == ob); + } + var k:int = getChildIndex(blockShape); + removeChildAt(k); + blockShape = new BlockShape(shape, Specs.procedureColor); + addChildAt(blockShape, k); + fixLayout(); + } + private function makeBooleanArg():BlockArg { var result:BlockArg = new BlockArg('b', 0xFFFFFF, true); result.setArgValue(unusedArgName('boolean')); @@ -295,9 +349,10 @@ public class ProcedureSpecEditor extends Sprite { addChild(o); if (stage) { if (o is TextField) stage.focus = TextField(o); - if (o is BlockArg) BlockArg(o).startEditing(); + if (o is BlockArg) stage.focus = BlockArg(o).field; } fixLayout(); + if (parent is DialogBox) DialogBox(parent).fixLayout(); } private function makeTextField(contents:String):TextField { @@ -306,7 +361,7 @@ public class ProcedureSpecEditor extends Sprite { result.backgroundColor = labelColor; result.background = true; result.type = TextFieldType.INPUT; - result.defaultTextFormat = Block.blockLabelFormat; + result.defaultTextFormat = new TextFormat(CSS.font, 12, 0xFFFFFF); if (contents.length > 0) { result.width = 1000; result.text = contents; @@ -329,11 +384,11 @@ public class ProcedureSpecEditor extends Sprite { row = newRow; } - private function fixLayout(updateDelete:Boolean = true):void { + private function fixLayout():void { removeDeletedElementsFromRow(); blockShape.x = 10; blockShape.y = 10; - var nextX:int = blockShape.x + 6; + var nextX:int = blockShape.x + (shape == BlockShape.BooleanShape ? 14 : 6); var nextY:int = blockShape.y + 5; var maxH:int = 0; for each (var o:DisplayObject in row) maxH = Math.max(maxH, o.height); @@ -343,39 +398,43 @@ public class ProcedureSpecEditor extends Sprite { nextX += o.width + 4; if ((o is BlockArg) && (BlockArg(o).type == 's')) nextX -= 2; } - var blockW:int = Math.max(40, nextX + 4 - blockShape.x); + var blockW:int = Math.max(40, nextX + (shape == BlockShape.BooleanShape ? 12 : 4) - blockShape.x); blockShape.setWidthAndTopHeight(blockW, maxH + 11, true); moreButton.x = 0; - moreButton.y = blockShape.y + blockShape.height + 12; + moreButton.y = blockShape.y + blockShape.height + (shape == BlockShape.CmdShape ? 12 : 15); moreLabel.x = 10; moreLabel.y = moreButton.y - 4; - var labelX:int = blockShape.x + 45; - var buttonX:int = 240; - for each (var l:TextField in buttonLabels) { - buttonX = Math.max(buttonX, labelX + l.textWidth + 10); - } - - var rowY:int = blockShape.y + blockShape.height + 30; + var rowY:int = blockShape.y + blockShape.height + (shape == BlockShape.CmdShape ? 30 : 33); for (var i:int = 0; i < buttons.length; i++) { - var label:TextField = buttonLabels[i]; - buttonLabels[i].x = labelX; + buttonLabels[i].x = blockShape.x + 45; buttonLabels[i].y = rowY; - buttons[i].x = buttonX; + buttons[i].x = 240; buttons[i].y = rowY - 4; rowY += 30; } + if (!isEdit) { + for (i = 0; i < shapeButtons.length; i++) { + shapeButtons[i].x = blockShape.x + 46; + shapeButtons[i].y = rowY + 4; + shapeIcons[i].x = shapeButtons[i].x + shapeButtons[i].width + 8; + shapeIcons[i].y = rowY; + shapeLabels[i].x = shapeIcons[i].x + shapeIcons[i].width + 8; + shapeLabels[i].y = rowY; + rowY += 30; + } + } + warpCheckbox.x = blockShape.x + 46; warpCheckbox.y = rowY + 4; warpLabel.x = warpCheckbox.x + 18; warpLabel.y = warpCheckbox.y - 3; - if (updateDelete) updateDeleteButton(); - if (parent is DialogBox) DialogBox(parent).fixLayout(); + updateDeleteButton(); } /* Editing Parameter Names */ @@ -424,24 +483,10 @@ public class ProcedureSpecEditor extends Sprite { private function setFocus(o:DisplayObject):void { if (!stage) return; if (o is TextField) stage.focus = TextField(o); - if (o is BlockArg) BlockArg(o).startEditing(); - } - - private function uniqueName(taken:Array, name:String):String { - if (taken.indexOf(name) == -1) return name; - var e:Array = /\d+$/.exec(name); - var n:String = e ? e[0] : ""; - var base:String = name.slice(0, name.length - n.length); - var i:int = int(n || "1") + 1; - while (taken.indexOf(base + i) != -1) { - i++; - } - return base + i; + if (o is BlockArg) stage.focus = BlockArg(o).field; } private function focusChange(evt:FocusEvent):void { - var params:Array = []; - var change:Boolean = false; // Update label fields to show focus. for each (var o:DisplayObject in row) { if (o is TextField) { @@ -449,17 +494,9 @@ public class ProcedureSpecEditor extends Sprite { var hasFocus:Boolean = (stage != null) && (tf == stage.focus); tf.textColor = hasFocus ? 0 : 0xFFFFFF; tf.backgroundColor = hasFocus ? selectedLabelColor : labelColor; - } else if (o is BlockArg) { - tf = BlockArg(o).field; - if (params.indexOf(tf.text) != -1) { - BlockArg(o).setArgValue(uniqueName(params, tf.text)); - change = true; - } - params.push(tf.text); } } - if (change) fixLayout(false); - else if (evt.type == FocusEvent.FOCUS_IN) updateDeleteButton(); + if (evt.type == FocusEvent.FOCUS_IN) updateDeleteButton(); } private function updateDeleteButton():void { @@ -485,4 +522,4 @@ public class ProcedureSpecEditor extends Sprite { deleteButton.y = -6; } -}} +}} \ No newline at end of file From 7623b270fbafd3bc98324a3b910eb718c4f3b945 Mon Sep 17 00:00:00 2001 From: Alexander Liu Date: Sat, 11 Jun 2016 08:12:46 +0700 Subject: [PATCH 062/141] Update Primitives.as --- src/primitives/Primitives.as | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index aa31970e2..b625fda6d 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -65,6 +65,7 @@ public class Primitives { primTable["sqrt"] = function(b:*):* { return Math.sqrt(interp.numarg(b[0])) }; primTable["power:of:"] = function(b:*):* { return Math.pow(interp.numarg(b[0]), interp.numarg(b[1])) }; primTable["reverseString:"] = primReverseString; + primTable["splitStringFrom:"] = primSplit; primTable["concatenate:with:"] = function(b:*):* { return ("" + b[0] + b[1]).substr(0, 10240); }; primTable["letter:of:"] = primLetterOf; @@ -235,6 +236,17 @@ public class Primitives { } return 0; } + private function primSplit(b:Block):String { + var a:String = interp.arg(b, 0); + var result:String = ""; + var i:int; + var j:int = interp.numarg(b, 2); + for(i = interp.numarg(b, 1); i < j + 1; i++) { + result += a.charAt(i -1); + } + return result; + + } // Sharp --- HTTP private function primHttp(b:Array):void { if(httpRequestsActive == httpRequestsAllowed) return; From 4a3ef6a31596844222853d11d5612387b3930f42 Mon Sep 17 00:00:00 2001 From: Alexander Liu Date: Sat, 11 Jun 2016 08:21:36 +0700 Subject: [PATCH 063/141] Revert "Fully Implement Custom Reporters" (#13) --- src/Specs.as | 5 - src/blocks/Block.as | 46 +++- src/blocks/BlockIO.as | 13 +- src/blocks/BlockShape.as | 22 +- src/extensions/ExtensionManager.as | 65 ++--- src/interpreter/Interpreter.as | 380 ++++++++++++---------------- src/interpreter/Thread.as | 47 ++-- src/primitives/ListPrims.as | 51 ++-- src/primitives/LooksPrims.as | 101 ++++---- src/primitives/MotionAndPenPrims.as | 102 ++++---- src/primitives/Primitives.as | 103 ++++---- src/primitives/SensingPrims.as | 69 +++-- src/primitives/SoundPrims.as | 208 ++++++++------- src/primitives/VideoMotionPrims.as | 12 +- src/scratch/BlockMenus.as | 3 +- src/scratch/PaletteBuilder.as | 13 +- src/scratch/ScratchRuntime.as | 10 +- src/ui/ProcedureSpecEditor.as | 157 +++++------- 18 files changed, 680 insertions(+), 727 deletions(-) diff --git a/src/Specs.as b/src/Specs.as index a454b2485..059127699 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -36,8 +36,6 @@ public class Specs { public static const CHANGE_VAR:String = "changeVar:by:"; public static const GET_LIST:String = "contentsOfList:"; public static const CALL:String = "call"; - public static const CALL_BOOLEAN:String = "callb"; - public static const CALL_NUMBER:String = "callr"; public static const PROCEDURE_DEF:String = "procDef"; public static const GET_PARAM:String = "getParam"; @@ -405,9 +403,6 @@ public class Specs { ["show list %m.list", " ", 12, "showList:"], ["hide list %m.list", " ", 12, "hideList:"], - // custom blocks - ["report %s", "f", 10, "report", ""], - // Sharp // --HTTP-- ["%m.httpMethod %s", " ", 13, "httpBlock:", "GET", "https://api.scratch.mit.edu"], diff --git a/src/blocks/Block.as b/src/blocks/Block.as index 03a31f5c5..2ef4f7d85 100644 --- a/src/blocks/Block.as +++ b/src/blocks/Block.as @@ -64,18 +64,21 @@ public class Block extends Sprite { private static var useEmbeddedFont:Boolean = false; public static var MenuHandlerFunction:Function; // optional function to handle block and blockArg menus + + public var isCustomReporter:Boolean = false; + public var isCustomBoolean:Boolean = false; + + public var isReturnBlock:Boolean = false; public var spec:String; public var type:String; public var op:String = ""; public var opFunction:Function; - public var isSpecialOp:Boolean = false; public var args:Array = []; public var defaultArgValues:Array = []; public var parameterIndex:int = -1; // cache of parameter index, used by GET_PARAM block public var parameterNames:Array; // used by procedure definition hats; null for other blocks public var warpProcFlag:Boolean; // used by procedure definition hats to indicate warp speed - public var procedureType:String; // used by procedure definition hats; " ", "r", or "b" public var rightToLeft:Boolean; public var isHat:Boolean = false; @@ -117,6 +120,7 @@ public class Block extends Sprite { this.spec = Translator.map(spec); this.type = type; this.op = op; + if(op == "call" && type == "r" || type == "b") isReturnBlock = true; if ((Specs.CALL == op) || (Specs.GET_LIST == op) || @@ -133,14 +137,14 @@ public class Block extends Sprite { if ((type == " ") || (type == "") || (type == "w")) { base = new BlockShape(BlockShape.CmdShape, color); indentTop = 3; - } else if (type == "b" || type == "ob") { - base = new BlockShape(type == "ob" ? BlockShape.BooleanOutlineShape : BlockShape.BooleanShape, color); + } else if (type == "b") { + base = new BlockShape(BlockShape.BooleanShape, color); isReporter = true; indentLeft = 9; indentRight = 7; - } else if (type == "r" || type == "R" || type == "or") { + } else if (type == "r" || type == "R") { this.type = 'r'; - base = new BlockShape(type == "or" ? BlockShape.NumberOutlineShape : BlockShape.NumberShape, color); + base = new BlockShape(BlockShape.NumberShape, color); isReporter = true; forceAsync = (type == 'r') && Scratch.app.extensionManager.shouldForceAsync(op); isRequester = (type == 'R') || forceAsync; @@ -167,7 +171,7 @@ public class Block extends Sprite { base = new BlockShape(BlockShape.FinalCmdShape, color); isTerminal = true; indentTop = 5; - } else if (type == "o" || type == "o ") { // cmd outline for proc definition + } else if (type == "o") { // cmd outline for proc definition base = new BlockShape(BlockShape.CmdOutlineShape, color); base.filters = []; // no bezel indentTop = 3; @@ -183,6 +187,25 @@ public class Block extends Sprite { addEventListener(FocusEvent.KEY_FOCUS_CHANGE, focusChange); } + public static const CUSTOM_COMMAND:Number = 0; + public static const CUSTOM_REPORTER:Number = 1; + public static const CUSTOM_BOOLEAN:Number = 2; + + public function setCustomBlockType(bType:Number = CUSTOM_COMMAND):void{ + if(bType == CUSTOM_COMMAND){ + isCustomBoolean = false; + isCustomReporter = false; + }else if(bType == CUSTOM_REPORTER){ + isCustomBoolean = false; + isCustomReporter = true; + }else if(bType == CUSTOM_BOOLEAN){ + isCustomBoolean = true; + isCustomReporter = false; + }else{ + setCustomBlockType(CUSTOM_COMMAND); + } + } + public function setSpec(newSpec:String, defaultArgs:Array = null):void { for each (var o:DisplayObject in labelsAndArgs) { if (o.parent != null) o.parent.removeChild(o); @@ -282,7 +305,7 @@ public class Block extends Sprite { // Create a block representing a procedure declaration to be embedded in a // procedure definition header block. For each formal parameter, embed a // reporter for that parameter. - var b:Block = new Block(spec, "o" + procedureType, Specs.procedureColor, 'proc_declaration'); + var b:Block = new Block(spec, "o", Specs.procedureColor, 'proc_declaration'); if (!parameterNames) parameterNames = []; for (var i:int = 0; i < parameterNames.length; i++) { var argType:String = (typeof(defaultArgValues[i]) == 'boolean') ? 'b' : 'r'; @@ -489,7 +512,7 @@ public class Block extends Sprite { for (i = 0; i < labelsAndArgs.length; i++) { item = labelsAndArgs[i]; // Next line moves the argument of if and if-else blocks right slightly: - if (!isReporter && i == 1 && !(argTypes[i] == 'label')) x = Math.max(x, 30); + if ((i == 1) && !(argTypes[i] == 'label')) x = Math.max(x, 30); item.x = x; maxH = Math.max(maxH, item.height); x += item.width + 2; @@ -503,7 +526,7 @@ public class Block extends Sprite { if ((item is BlockArg) && (!BlockArg(item).numberType)) item.y += 1; } - if ([' ', '', 'o ', 'o'].indexOf(type) >= 0) x = Math.max(x, minCommandWidth); // minimum width for command blocks + if ([' ', '', 'o'].indexOf(type) >= 0) x = Math.max(x, minCommandWidth); // minimum width for command blocks if (['c', 'cf', 'e'].indexOf(type) >= 0) x = Math.max(x, minLoopWidth); // minimum width for C and E blocks if (['h'].indexOf(type) >= 0) x = Math.max(x, minHatWidth); // minimum width for hat blocks if (elseLabel) x = Math.max(x, indentLeft + elseLabel.width + 2); @@ -576,13 +599,12 @@ public class Block extends Sprite { public function duplicate(forClone:Boolean, forStage:Boolean = false):Block { var newSpec:String = spec; if (op == 'whenClicked') newSpec = forStage ? 'when Stage clicked' : 'when this sprite clicked'; - var dup:Block = new Block(newSpec, procedureType ? procedureType : type, (int)(forClone ? -1 : base.color), op); + var dup:Block = new Block(newSpec, type, (int)(forClone ? -1 : base.color), op); dup.isRequester = isRequester; dup.forceAsync = forceAsync; dup.parameterNames = parameterNames; dup.defaultArgValues = defaultArgValues; dup.warpProcFlag = warpProcFlag; - dup.procedureType = procedureType; if (forClone) { dup.copyArgsForClone(args); } else { diff --git a/src/blocks/BlockIO.as b/src/blocks/BlockIO.as index d80848292..e79fe029f 100644 --- a/src/blocks/BlockIO.as +++ b/src/blocks/BlockIO.as @@ -70,12 +70,8 @@ public class BlockIO { if (b.op == Specs.GET_LIST) return [Specs.GET_LIST, b.spec]; // list reporter if (b.op == Specs.GET_PARAM) return [Specs.GET_PARAM, b.spec, b.type]; // parameter reporter if (b.op == Specs.PROCEDURE_DEF) // procedure definition - return [Specs.PROCEDURE_DEF, b.spec, b.parameterNames, b.defaultArgValues, b.warpProcFlag, b.procedureType]; - if (b.op == Specs.CALL) { - // procedure call - arguments follow spec - // because procedures used to only be commands, they didn't store their type in the array format; to maintain backwards compatibility, we store the type by splitting Specs.CALL into separate selectors for each type - result = [b.type == 'b' ? Specs.CALL_BOOLEAN : b.type == 'r' ? Specs.CALL_NUMBER : Specs.CALL, b.spec]; - } + return [Specs.PROCEDURE_DEF, b.spec, b.parameterNames, b.defaultArgValues, b.warpProcFlag]; + if (b.op == Specs.CALL) result = [Specs.CALL, b.spec]; // procedure call - arguments follow spec for each (var a:* in b.normalizedArgs()) { // Note: arguments are always saved in normalized (i.e. left-to-right) order if (a is Block) result.push(blockToArray(a)); @@ -105,8 +101,8 @@ public class BlockIO { b = convertOldCmd(cmd); if (b) { b.fixArgLayout(); return b } - if (cmd[0] == Specs.CALL || cmd[0] == Specs.CALL_BOOLEAN || cmd[0] == Specs.CALL_NUMBER) { - b = new Block(cmd[1], cmd[0] == Specs.CALL_BOOLEAN ? 'b' : cmd[0] == Specs.CALL_NUMBER ? 'r' : '', Specs.procedureColor, Specs.CALL); + if (cmd[0] == Specs.CALL) { + b = new Block(cmd[1], '', Specs.procedureColor, Specs.CALL); cmd.splice(0, 1); } else { var spec:Array = specForCmd(cmd, undefinedBlockType); @@ -195,7 +191,6 @@ public class BlockIO { b.parameterNames = cmd[2]; b.defaultArgValues = cmd[3]; if (cmd.length > 4) b.warpProcFlag = cmd[4]; - if (cmd.length > 5) b.procedureType = cmd[5]; b.setSpec(cmd[1]); b.fixArgLayout(); return b; diff --git a/src/blocks/BlockShape.as b/src/blocks/BlockShape.as index d44a4019d..0aa3cd98a 100644 --- a/src/blocks/BlockShape.as +++ b/src/blocks/BlockShape.as @@ -42,8 +42,6 @@ public class BlockShape extends Shape { public static const FinalLoopShape:int = 10; // E-shaped blocks public static const IfElseShape:int = 11; - public static const BooleanOutlineShape:int = 12; - public static const NumberOutlineShape:int = 13; // Geometry public static const NotchDepth:int = 3; @@ -189,8 +187,6 @@ public class BlockShape extends Shape { case CmdShape: case FinalCmdShape: drawFunction = drawCmdShape; break; case CmdOutlineShape: drawFunction = drawCmdOutlineShape; break; - case BooleanOutlineShape: drawFunction = drawBooleanOutlineShape; break; - case NumberOutlineShape: drawFunction = drawNumberOutlineShape; break; case LoopShape: case FinalLoopShape: drawFunction = drawLoopShape; break; case IfElseShape: drawFunction = drawIfElseShape; break; @@ -211,13 +207,6 @@ public class BlockShape extends Shape { g.lineTo(w - centerY, topH); } - private function drawBooleanOutlineShape(g:Graphics):void { - g.endFill(); - g.lineStyle(2, 0xFFFFFF, 0.2); - drawBooleanShape(g); - g.lineTo(topH / 2, topH); - } - private function drawNumberShape(g:Graphics):void { var centerY:int = topH / 2; g.moveTo(centerY, topH); @@ -228,13 +217,6 @@ public class BlockShape extends Shape { curve(w, centerY, w - centerY, topH); } - private function drawNumberOutlineShape(g:Graphics):void { - g.endFill(); - g.lineStyle(2, 0xFFFFFF, 0.2); - drawNumberShape(g); - g.lineTo(topH / 2, topH); - } - private function drawCmdShape(g:Graphics):void { drawTop(g); drawRightAndBottom(g, topH, (shape != FinalCmdShape)); @@ -353,7 +335,7 @@ public class BlockShape extends Shape { } private function curve(p1x:int, p1y:int, p2x:int, p2y:int, roundness:Number = 0.42):void { - // Compute the Bezier control point by following an orthogal vector from the midpoint + // Compute the Bezier control point by following an orthogonal vector from the midpoint // of the line between p1 and p2 scaled by roundness * dist(p1, p2). The default roundness // approximates a circular arc. Negative roundness gives a concave curve. @@ -364,4 +346,4 @@ public class BlockShape extends Shape { graphics.curveTo(cx, cy, p2x, p2y); } -}} \ No newline at end of file +}} diff --git a/src/extensions/ExtensionManager.as b/src/extensions/ExtensionManager.as index 607400c81..5dfd07455 100644 --- a/src/extensions/ExtensionManager.as +++ b/src/extensions/ExtensionManager.as @@ -391,17 +391,18 @@ public class ExtensionManager { // Execution //------------------------------ - public function primExtensionOp(args:Array):* { - var activeThread:Thread = app.interp.activeThread; - var b:Block = activeThread.block; + public function primExtensionOp(b:Block):* { var unpackedOp:Array = unpackExtensionAndOp(b.op); var extName:String = unpackedOp[0]; var ext:ScratchExtension = extensionDict[extName]; if (ext == null) return 0; // unknown extension var primOrVarName:String = unpackedOp[1]; + var args:Array = []; + for (var i:int = 0; i < b.args.length; i++) { + args.push(app.interp.arg(b, i)); + } var value:*; - if(b.isHat && b.isAsyncHat){ if(b.requestState == 0){ request(extName, primOrVarName, args, b); @@ -441,22 +442,26 @@ public class ExtensionManager { return; } else if (b.isReporter) { - if (b.isRequester) { - if (b.requestState == 2) { + if(b.isRequester) { + if(b.requestState == 2) { b.requestState = 0; - activeThread.popState(); - activeThread.values.push(b.response); - return; - } else if(b.requestState == 0) { + return b.response; + } + else if(b.requestState == 0) { request(extName, primOrVarName, args, b); } - } else { + + // Returns null if we just made a request or we're still waiting + return null; + } + else { var sensorName:String = primOrVarName; - if (ext.port > 0) { // we were checking ext.isInternal before, should we? + if(ext.port > 0) { // we were checking ext.isInternal before, should we? sensorName = encodeURIComponent(sensorName); for each (var a:* in args) sensorName += '/' + encodeURIComponent(a); // append menu args value = ext.stateVars[sensorName]; - } else if(Scratch.app.jsEnabled) { + } + else if(Scratch.app.jsEnabled) { // JavaScript if (Scratch.app.isOffline) { throw new IllegalOperationError("JS reporters must be requesters in Offline."); @@ -467,9 +472,7 @@ public class ExtensionManager { } if (value == undefined) value = 0; // default to zero if missing if ('b' == b.type) value = (ext.port>0 ? 'true' == value : true == value); // coerce value to a boolean - activeThread.popState(); - activeThread.values.push(value); - return + return value; } } else { if ('w' == b.type) { @@ -481,13 +484,12 @@ public class ExtensionManager { app.interp.doYield(); justStartedWait = true; - if (ext.port == 0) { + if(ext.port == 0) { activeThread.firstTime = false; - if (app.jsEnabled) { + if(app.jsEnabled) app.externalCall('ScratchExtensions.runAsync', null, ext.name, primOrVarName, args, id); - } else { + else ext.busy.pop(); - } return; } @@ -499,10 +501,6 @@ public class ExtensionManager { } else { activeThread.tmp = 0; activeThread.firstTime = true; - var block:Block = activeThread.block; - activeThread.popState(); - if (block.nextBlock) - activeThread.pushStateForBlock(block.nextBlock); } return; } @@ -516,13 +514,22 @@ public class ExtensionManager { if (ext == null) return; // unknown extension if (ext.port > 0) { var activeThread:Thread = app.interp.activeThread; + if(activeThread && op != 'reset_all') { + if(activeThread.firstTime) { + httpCall(ext, op, args); + activeThread.firstTime = false; + app.interp.doYield(); + } + else { + activeThread.firstTime = true; + } + } + else { httpCall(ext, op, args); - activeThread.firstTime = false; - app.interp.doYield(); + } } else { - if (op == 'reset_all') op = 'resetAll'; if (Scratch.app.jsEnabled) { - if (op == 'resetAll') { + if (op == 'reset_all') { app.externalCall('ScratchExtensions.stop', null, ext.name); } else { @@ -719,4 +726,4 @@ public class ExtensionManager { } return false; } -}} \ No newline at end of file +}} diff --git a/src/interpreter/Interpreter.as b/src/interpreter/Interpreter.as index 68823ac4b..379214324 100644 --- a/src/interpreter/Interpreter.as +++ b/src/interpreter/Interpreter.as @@ -80,7 +80,6 @@ public class Interpreter { private var app:Scratch; private var primTable:Dictionary; // maps opcodes to functions - private var specialTable:Dictionary; // blocks that require special op functions private var threads:Array = []; // all threads private var yield:Boolean; // set true to indicate that active thread should yield control private var startTime:int; // start time for stepThreads() @@ -96,10 +95,6 @@ public class Interpreter { protected var debugFunc:Function; - static private var yieldBlock:Block = new Block('', '', 0, 'yield'); - static private var returnBlock:Block = new Block('', '', 0, 'doReturn', [0]); - static private var report0Block:Block = new Block('%s', '', 0, 'report', [0]); - public function Interpreter(app:Scratch) { this.app = app; initPrims(); @@ -150,9 +145,9 @@ public class Interpreter { var reporter:Block = b; var interp:Interpreter = this; b = new Block("%s", "", -1); - b.opFunction = function(b:Array):void { + b.opFunction = function(b:Block):void { var p:Point = reporter.localToGlobal(new Point(0, 0)); - app.showBubble(String(b[0]), p.x, p.y, reporter.getRect(app.stage).width); + app.showBubble(String(interp.arg(b, 0)), p.x, p.y, reporter.getRect(app.stage).width); }; b.args[0] = reporter; } @@ -268,21 +263,36 @@ public class Interpreter { return; } } - yield = false; while (true) { if (activeThread == warpThread) currentMSecs = getTimer(); evalCmd(activeThread.block); - if (activeThread.block == null) { - //click on reporter shows value in log - if (activeThread.values.length) { - app.jsThrowError(activeThread.values[0]); - } - return; - } if (yield) { - if (activeThread != warpThread || currentMSecs - startTime > warpMSecs) return; - yield = false; + if (activeThread == warpThread) { + if ((currentMSecs - startTime) > warpMSecs) return; + yield = false; + continue; + } else return; + } + + if (activeThread.block != null) + activeThread.block = activeThread.block.nextBlock; + + while (activeThread.block == null) { // end of block sequence + if (!activeThread.popState()) return; // end of script + if ((activeThread.block == warpBlock) && activeThread.firstTime) { // end of outer warp block + clearWarpBlock(); + activeThread.block = activeThread.block.nextBlock; + continue; + } + if (activeThread.isLoop) { + if (activeThread == warpThread) { + if ((currentMSecs - startTime) > warpMSecs) return; + } else return; + } else { + if (activeThread.block.op == Specs.CALL) activeThread.firstTime = true; // in case set false by call + activeThread.block = activeThread.block.nextBlock; + } } } } @@ -293,75 +303,74 @@ public class Interpreter { } /* Evaluation */ - public function evalCmd(b:Block):void { - + public function evalCmd(b:Block):* { + if (!b) return 0; // arg() and friends can pass null if arg index is out of range var op:String = b.op; if (b.opFunction == null) { - if (ExtensionManager.hasExtensionPrefix(op)) { - b.isSpecialOp = true; - b.opFunction = app.extensionManager.primExtensionOp; - } else if (specialTable[op]){ - b.isSpecialOp = true; - b.opFunction = specialTable[op]; - } - else { - b.opFunction = (primTable[op] == undefined) ? primNoop : primTable[op]; - } + if (ExtensionManager.hasExtensionPrefix(op)) b.opFunction = app.extensionManager.primExtensionOp; + else b.opFunction = (primTable[op] == undefined) ? primNoop : primTable[op]; + } + + // TODO: Optimize this into a cached check if the args *could* block at all + if(b.args.length && checkBlockingArgs(b)) { + doYield(); + return null; } // Debug code if(debugFunc != null) debugFunc(b); + + return b.opFunction(b); + } - if (b.opFunction == primNoop) { - // kludge: don't evaluate args for primNoop because procDef has weird ones - activeThread.popState(); - if (b.nextBlock) activeThread.pushStateForBlock(b.nextBlock); - return; + // Returns true if the thread needs to yield while data is requested + public function checkBlockingArgs(b:Block):Boolean { + // Do any of the arguments request data? If so, start any requests and yield. + var shouldYield:Boolean = false; + var args:Array = b.args; + for(var i:uint=0; i 0) { activeThread.tmp--; // decrement count - startCmdList(block.subStack1, true); + startCmdList(b.subStack1, true); } else { - activeThread.popState(); activeThread.firstTime = true; - if (block.nextBlock) activeThread.pushStateForBlock(block.nextBlock); } } - - private function primCodeSection(b:Array):void { - var block:Block = activeThread.block; - activeThread.popState(); - activeThread.firstTime = true; - if (block.nextBlock) activeThread.pushStateForBlock(block.nextBlock); - startCmdList(block.subStack1, false); + private function primCodeSection(b:Block):void{ + if (activeThread.firstTime) { + var repeatCount:Number = 1; // clip to range: 0 to 2^31-1 + activeThread.tmp = repeatCount; + activeThread.firstTime = false; + } + if (activeThread.tmp > 0) { + activeThread.tmp--; // decrement count + startCmdList(b.subStack1, true); + } else { + activeThread.firstTime = true; + } } - private function primStop(b:Array):void { - var type:String = b[0]; + private function primStop(b:Block):void { + var type:String = arg(b, 0); if (type == 'all') { app.runtime.stopAll(); yield = true } - if (type == 'this script') primReturn([0]); + if (type == 'this script') primReturn(b); if (type == 'other scripts in sprite') stopThreadsFor(activeThread.target, true); if (type == 'other scripts in stage') stopThreadsFor(activeThread.target, true); } - private function primWait(b:Array):void { + private function primWait(b:Block):void { if (activeThread.firstTime) { - startTimer(numarg(b[0])); + startTimer(numarg(b, 0)); redraw(); } else checkTimer(); } @@ -679,52 +650,47 @@ public class Interpreter { // Procedure call/return - private function primCall(b:Array):void { + private function primCall(b:Block):* { // Call a procedure. Handle recursive calls and "warp" procedures. - - var block:Block = activeThread.block; + // The activeThread.firstTime flag is used to mark the first call + // to a procedure running in warp mode. activeThread.firstTime is + // false for subsequent calls to warp mode procedures. // Lookup the procedure and cache for future use var obj:ScratchObj = activeThread.target; - var insideLoop:* = null; - var spec:String = block.spec; + var spec:String = b.spec; var proc:Block = obj.procCache[spec]; if (!proc) { proc = obj.lookupProcedure(spec); obj.procCache[spec] = proc; } - if (!proc) { - if (activeThread.block.type == 'o ') activeThread.values.push(0); - activeThread.popState(); - if (block.nextBlock) activeThread.pushStateForBlock(block.nextBlock); - return; - } + if (!proc) return; if (warpThread) { - if (currentMSecs - startTime > warpMSecs) yield = true; + activeThread.firstTime = false; + if ((currentMSecs - startTime) > warpMSecs) yield = true; } else { if (proc.warpProcFlag) { // Start running in warp mode. - warpBlock = block; + warpBlock = b; warpThread = activeThread; - } else if (activeThread.isRecursiveCall(block, proc)) { + activeThread.firstTime = true; + } + else if (activeThread.isRecursiveCall(b, proc)) { yield = true; } } - activeThread.pushStateForBlock(report0Block); - activeThread.args = b; - startCmdList(proc); + var argCount:int = proc.parameterNames.length; + var argList:Array = []; + for (var i:int = 0; i < argCount; ++i) argList.push(arg(b, i)); + startCmdList(proc, false, argList); } - private function primReturn(b:Array):void { + private function primReturn(b:Block):void { // Return from the innermost procedure. If not in a procedure, stop the thread. - var call:Block = activeThread.returnFromProcedure(); - if (call) { - if (call.isReporter) { - activeThread.values.push(b[0]); - } - } else { + if (!activeThread.returnFromProcedure()) { activeThread.stop(); + yield = true; } } @@ -732,59 +698,49 @@ public class Interpreter { // Optimization: to avoid the cost of looking up the variable every time, // a reference to the Variable object is cached in the target object. - private function primVarGet(b:Array):void { - var block:Block = activeThread.block; - activeThread.popState(); - var v:Variable = activeThread.target.varCache[block.spec]; + private function primVarGet(b:Block):* { + var target:ScratchObj = app.runtime.currentDoObj ? app.runtime.currentDoObj : activeThread.target; + + var v:Variable = target.varCache[b.spec]; if (v == null) { - v = activeThread.target.varCache[block.spec] = activeThread.target.lookupOrCreateVar(block.spec); - if (v == null) { - activeThread.values.push(0); - return; - } + v = target.varCache[b.spec] = target.lookupOrCreateVar(b.spec); + if (v == null) return 0; } - activeThread.values.push(v.value); + // XXX: Do we need a get() for persistent variables here ? + return v.value; } - protected function primVarSet(b:Array):Variable { - var v:Variable = activeThread.target.varCache[b[0]]; + protected function primVarSet(b:Block):Variable { + var name:String = arg(b, 0); + var v:Variable = activeThread.target.varCache[name]; if (!v) { - v = activeThread.target.varCache[b.spec] = activeThread.target.lookupOrCreateVar(b[0]); + v = activeThread.target.varCache[name] = activeThread.target.lookupOrCreateVar(name); if (!v) return null; } var oldvalue:* = v.value; - v.value = b[1]; + v.value = arg(b, 1); return v; } - protected function primVarChange(b:Array):Variable { - var name:String = b[0]; + protected function primVarChange(b:Block):Variable { + var name:String = arg(b, 0); var v:Variable = activeThread.target.varCache[name]; if (!v) { v = activeThread.target.varCache[name] = activeThread.target.lookupOrCreateVar(name); if (!v) return null; } - v.value = Number(v.value) + b[1]; + v.value = Number(v.value) + numarg(b, 1); return v; } - private function primGetParam(b:Array):* { - var block:Block = activeThread.block; - activeThread.popState(); - if (!block.isReporter) return; - if (block.parameterIndex < 0) { - var proc:Block = block.topBlock(); - if (proc.parameterNames) block.parameterIndex = proc.parameterNames.indexOf(block.spec); - if (block.parameterIndex < 0) { - activeThread.values.push(0); - return; - } - } - if (activeThread.args == null || block.parameterIndex >= activeThread.args.length) { - activeThread.values.push(0); - return; + private function primGetParam(b:Block):* { + if (b.parameterIndex < 0) { + var proc:Block = b.topBlock(); + if (proc.parameterNames) b.parameterIndex = proc.parameterNames.indexOf(b.spec); + if (b.parameterIndex < 0) return 0; } - activeThread.values.push(activeThread.args[block.parameterIndex]); + if ((activeThread.args == null) || (b.parameterIndex >= activeThread.args.length)) return 0; + return activeThread.args[b.parameterIndex]; } }} diff --git a/src/interpreter/Thread.as b/src/interpreter/Thread.as index 3aee1e321..8179c3a67 100644 --- a/src/interpreter/Thread.as +++ b/src/interpreter/Thread.as @@ -36,13 +36,13 @@ public class Thread { // the following state is pushed and popped when running substacks public var block:Block; + public var isLoop:Boolean; public var firstTime:Boolean; // used by certain control structures public var tmp:int; // used by repeat and wait - public var values:Array; // the evaluated inputs public var args:Array; // arguments to a user-defined procedure // the stack - private var stack:Vector.; + public var stack:Vector.; private var sp:int; public function Thread(b:Block, targetObj:*, startupDelay:int = 0) { @@ -51,35 +51,34 @@ public class Thread { topBlock = b; startDelayCount = startupDelay; // initForBlock - block = null; + block = b; + isLoop = false; firstTime = true; tmp = 0; - values = []; - pushStateForBlock(b); } public function pushStateForBlock(b:Block):void { if (sp >= (stack.length - 1)) growStack(); var old:StackFrame = stack[sp++]; old.block = block; + old.isLoop = isLoop; old.firstTime = firstTime; old.tmp = tmp; - old.values = values; old.args = args; // initForBlock block = b; + isLoop = false; firstTime = true; tmp = 0; - values = []; } public function popState():Boolean { if (sp == 0) return false; var old:StackFrame = stack[--sp]; block = old.block; + isLoop = old.isLoop; firstTime = old.firstTime; tmp = old.tmp; - values = old.values; args = old.args; return true; } @@ -88,7 +87,6 @@ public class Thread { public function stop():void { block = null; - values = []; stack = new Vector.(4); stack[0] = new StackFrame(); stack[1] = new StackFrame(); @@ -101,7 +99,7 @@ public class Thread { var callCount:int = 5; // maximum number of enclosing procedure calls to examine for (var i:int = sp - 1; i >= 0; i--) { var b:Block = stack[i].block; - if (b && b.op == Specs.CALL) { + if (b.op == Specs.CALL) { if (procCall == b) return true; if (procHat == target.procCache[b.spec]) return true; } @@ -110,33 +108,26 @@ public class Thread { return false; } - public function returnFromProcedure():Block { - if (block && block.op == Specs.CALL) { - var b:Block = block; - popState(); - if (b.nextBlock) pushStateForBlock(b.nextBlock); - return block; - } + public function returnFromProcedure():Boolean { for (var i:int = sp - 1; i >= 0; i--) { - b = stack[i].block; - if (b && b.op == Specs.CALL) { - sp = i; - popState(); - if (b.nextBlock) pushStateForBlock(b.nextBlock); - return b; + if (stack[i].block.op == Specs.CALL) { + sp = i + 1; // 'hack' the stack pointer, but don't do the final popState here + block = null; // make it do the final popState through the usual stepActiveThread mechanism + return true; } } - return null; + return false; } private function initForBlock(b:Block):void { block = b; + isLoop = false; firstTime = true; tmp = 0; } private function growStack():void { - // The stack is an array of StackFrame instances, pre-allocated for efficiency. + // The stack is an array of Thread instances, pre-allocated for efficiency. // When growing, the current size is doubled. var s:int = stack.length; var n:int = s + s; @@ -151,9 +142,9 @@ import blocks.*; import interpreter.*; class StackFrame { - internal var block:Block; + public var block:Block; + internal var isLoop:Boolean; internal var firstTime:Boolean; internal var tmp:int; - internal var values:Array; internal var args:Array; -} \ No newline at end of file +} diff --git a/src/primitives/ListPrims.as b/src/primitives/ListPrims.as index 20c68bde0..10a7675ab 100644 --- a/src/primitives/ListPrims.as +++ b/src/primitives/ListPrims.as @@ -39,7 +39,7 @@ public class ListPrims { this.interp = interpreter; } - public function addPrimsTo(primTable:Dictionary, specialTable:Dictionary):void { + public function addPrimsTo(primTable:Dictionary):void { primTable[Specs.GET_LIST] = primContents; primTable['append:toList:'] = primAppend; primTable['deleteLine:ofList:'] = primDelete; @@ -50,7 +50,7 @@ public class ListPrims { primTable['list:contains:'] = primContains; } - private function primContents(b:Array):String { + private function primContents(b:Block):String { var list:ListWatcher = interp.targetObj().lookupOrCreateList(b.spec); if (!list) return ''; var allSingleLetters:Boolean = true; @@ -63,10 +63,10 @@ public class ListPrims { return (list.contents.join(allSingleLetters ? '' : ' ')); } - private function primAppend(b:Array):void { - var list:ListWatcher = listarg(b[1]); + private function primAppend(b:Block):void { + var list:ListWatcher = listarg(b, 1); if (!list) return; - listAppend(list, b[0]); + listAppend(list, interp.arg(b, 0)); if (list.visible) list.updateWatcher(list.contents.length, false, interp); } @@ -74,9 +74,9 @@ public class ListPrims { list.contents.push(item); } - private function primDelete(b:Array):void { - var which:* = b[0]; - var list:ListWatcher = listarg(b[1]); + private function primDelete(b:Block):void { + var which:* = interp.arg(b, 0); + var list:ListWatcher = listarg(b, 1); if (!list) return; var len:int = list.contents.length; if (which == 'all') { @@ -100,9 +100,9 @@ public class ListPrims { } private function primInsert(b:Block):void { - var val:* = b[0]; - var where:* = b[1]; - var list:ListWatcher = listarg(b[2]); + var val:* = interp.arg(b, 0); + var where:* = interp.arg(b, 1); + var list:ListWatcher = listarg(b, 2); if (!list) return; if (where == 'last') { listAppend(list, val); @@ -119,12 +119,12 @@ public class ListPrims { list.contents.splice(i - 1, 0, item); } - private function primReplace(b:Array):void { - var list:ListWatcher = listarg(b[1]); + private function primReplace(b:Block):void { + var list:ListWatcher = listarg(b, 1); if (!list) return; - var i:int = computeIndex(b[0], list.contents.length); + var i:int = computeIndex(interp.arg(b, 0), list.contents.length); if (i < 0) return; - listReplace(list, i, b[2]); + listReplace(list, i, interp.arg(b, 2)); if (list.visible) list.updateWatcher(i, false, interp); } @@ -132,25 +132,25 @@ public class ListPrims { list.contents[i - 1] = item; } - private function primGetItem(b:Array):* { - var list:ListWatcher = listarg(b[1]); + private function primGetItem(b:Block):* { + var list:ListWatcher = listarg(b, 1); if (!list) return ''; - var i:int = computeIndex(b[0], list.contents.length); + var i:int = computeIndex(interp.arg(b, 0), list.contents.length); if (i < 0) return ''; if (list.visible) list.updateWatcher(i, true, interp); return list.contents[i - 1]; } - private function primLength(b:Array):Number { - var list:ListWatcher = listarg(b[0]); + private function primLength(b:Block):Number { + var list:ListWatcher = listarg(b, 0); if (!list) return 0; return list.contents.length; } - private function primContains(b:Array):Boolean { - var list:ListWatcher = listarg(b[0]); + private function primContains(b:Block):Boolean { + var list:ListWatcher = listarg(b, 0); if (!list) return false; - var item:* = b[1]; + var item:* = interp.arg(b, 1); if (list.contents.indexOf(item) >= 0) return true; for each (var el:* in list.contents) { // use Scratch comparison operator (Scratch considers the string '123' equal to the number 123) @@ -159,7 +159,8 @@ public class ListPrims { return false; } - private function listarg(listName:String):ListWatcher { + private function listarg(b:Block, i:int):ListWatcher { + var listName:String = interp.arg(b, i); if (listName.length == 0) return null; var obj:ScratchObj = interp.targetObj(); var result:ListWatcher = obj.listCache[listName]; @@ -182,4 +183,4 @@ public class ListPrims { return i; } -}} \ No newline at end of file +}} diff --git a/src/primitives/LooksPrims.as b/src/primitives/LooksPrims.as index d47471272..75aadaf8f 100644 --- a/src/primitives/LooksPrims.as +++ b/src/primitives/LooksPrims.as @@ -38,7 +38,7 @@ public class LooksPrims { this.interp = interpreter; } - public function addPrimsTo(primTable:Dictionary, specialTable:Dictionary):void { + public function addPrimsTo(primTable:Dictionary):void { primTable['lookLike:'] = primShowCostume; primTable['nextCostume'] = primNextCostume; primTable['costumeIndex'] = primCostumeIndex; @@ -49,12 +49,12 @@ public class LooksPrims { primTable['backgroundIndex'] = primSceneIndex; primTable['sceneName'] = primSceneName; primTable['nextScene'] = function(b:*):* { startScene('next backdrop', false) }; - primTable['startScene'] = function(b:*):* { startScene(b[0], false) }; - primTable['startSceneAndWait'] = function(b:*):* { startScene(b[0], true) }; + primTable['startScene'] = function(b:*):* { startScene(interp.arg(b, 0), false) }; + primTable['startSceneAndWait'] = function(b:*):* { startScene(interp.arg(b, 0), true) }; - specialTable['say:duration:elapsed:from:'] = function(b:*):* { showBubbleAndWait(b, 'talk') }; + primTable['say:duration:elapsed:from:'] = function(b:*):* { showBubbleAndWait(b, 'talk') }; primTable['say:'] = function(b:*):* { showBubble(b, 'talk') }; - specialTable['think:duration:elapsed:from:'] = function(b:*):* { showBubbleAndWait(b, 'think') }; + primTable['think:duration:elapsed:from:'] = function(b:*):* { showBubbleAndWait(b, 'think') }; primTable['think:'] = function(b:*):* { showBubble(b, 'think') }; primTable['changeGraphicEffect:by:'] = primChangeEffect; @@ -84,16 +84,16 @@ public class LooksPrims { primTable['setRotationStyle'] = primSetRotationStyle; } - private function primNextCostume(b:Array):void { + private function primNextCostume(b:Block):void { var s:ScratchObj = interp.targetObj(); if (s != null) s.showCostume(s.currentCostumeIndex + 1); if (s.visible) interp.redraw(); } - private function primShowCostume(b:Array):void { + private function primShowCostume(b:Block):void { var s:ScratchObj = interp.targetObj(); if (s == null) return; - var arg:* = b[0]; + var arg:* = interp.arg(b, 0); if (typeof(arg) == 'number') { s.showCostume(arg - 1); } else { @@ -113,21 +113,21 @@ public class LooksPrims { if (s.visible) interp.redraw(); } - private function primCostumeIndex(b:Array):Number { + private function primCostumeIndex(b:Block):Number { var s:ScratchObj = interp.targetObj(); return (s == null) ? 1 : s.costumeNumber(); } - private function primCostumeName(b:Array):String { + private function primCostumeName(b:Block):String { var s:ScratchObj = interp.targetObj(); return (s == null) ? '' : s.currentCostume().costumeName; } - private function primSceneIndex(b:Array):Number { + private function primSceneIndex(b:Block):Number { return app.stagePane.costumeNumber(); } - private function primSceneName(b:Array):String { + private function primSceneName(b:Block):String { return app.stagePane.currentCostume().costumeName; } @@ -149,13 +149,14 @@ public class LooksPrims { var costumes:Array = app.stagePane.costumes; return costumes[(i + costumes.length) % costumes.length].costumeName; } - private function showBubbleAndWait(b:Array, type:String):void { + + private function showBubbleAndWait(b:Block, type:String):void { var text:*, secs:Number; var s:ScratchSprite = interp.targetSprite(); if (s == null) return; if (interp.activeThread.firstTime) { - text = b[0]; - secs = interp.numarg(b[1]); + text = interp.arg(b, 0); + secs = interp.numarg(b, 1); s.showBubble(text, type, b); if (s.visible) interp.redraw(); interp.startTimer(secs); @@ -166,25 +167,25 @@ public class LooksPrims { } } - private function showBubble(b:Array, type:String = null):void { + private function showBubble(b:Block, type:String = null):void { var text:*, secs:Number; var s:ScratchSprite = interp.targetSprite(); if (s == null) return; if (type == null) { // combined talk/think/shout/whisper command - type = b[0]; - text = b[1]; + type = interp.arg(b, 0); + text = interp.arg(b, 1); } else { // talk or think command - text = b[0]; + text = interp.arg(b, 0); } s.showBubble(text, type, b); if (s.visible) interp.redraw(); } - private function primChangeEffect(b:Array):void { + private function primChangeEffect(b:Block):void { var s:ScratchObj = interp.targetObj(); if (s == null) return; - var filterName:String = b[0]; - var delta:Number = interp.numarg(b[1]); + var filterName:String = interp.arg(b, 0); + var delta:Number = interp.numarg(b, 1); if(delta == 0) return; var newValue:Number = s.filterPack.getFilterSetting(filterName) + delta; @@ -193,52 +194,52 @@ public class LooksPrims { if (s.visible || s == Scratch.app.stagePane) interp.redraw(); } - private function primSetEffect(b:Array):void { + private function primSetEffect(b:Block):void { var s:ScratchObj = interp.targetObj(); if (s == null) return; - var filterName:String = b[0]; - var newValue:Number = interp.numarg(b[1]); + var filterName:String = interp.arg(b, 0); + var newValue:Number = interp.numarg(b, 1); if(s.filterPack.setFilter(filterName, newValue)) s.applyFilters(); if (s.visible || s == Scratch.app.stagePane) interp.redraw(); } - private function primClearEffects(b:Array):void { + private function primClearEffects(b:Block):void { var s:ScratchObj = interp.targetObj(); s.clearFilters(); s.applyFilters(); if (s.visible || s == Scratch.app.stagePane) interp.redraw(); } - private function primChangeSize(b:Array):void { + private function primChangeSize(b:Block):void { var s:ScratchSprite = interp.targetSprite(); if (s == null) return; var oldScale:Number = s.scaleX; - s.setSize(s.getSize() + interp.numarg(b[0])); + s.setSize(s.getSize() + interp.numarg(b, 0)); if (s.visible && (s.scaleX != oldScale)) interp.redraw(); } - private function primSetRotationStyle(b:Array):void { + private function primSetRotationStyle(b:Block):void { var s:ScratchSprite = interp.targetSprite(); - var newStyle:String = b[0] as String; + var newStyle:String = interp.arg(b, 0) as String; if ((s == null) || (newStyle == null)) return; s.setRotationStyle(newStyle); } - private function primSetSize(b:Array):void { + private function primSetSize(b:Block):void { var s:ScratchSprite = interp.targetSprite(); if (s == null) return; - s.setSize(interp.numarg(b[0])); + s.setSize(interp.numarg(b, 0)); if (s.visible) interp.redraw(); } - private function primSize(b:Array):Number { + private function primSize(b:Block):Number { var s:ScratchSprite = interp.targetSprite(); if (s == null) return 100; return Math.round(s.getSize()); // reporter returns rounded size, as in Scratch 1.4 } - private function primShow(b:Array):void { + private function primShow(b:Block):void { var s:ScratchSprite = interp.targetSprite(); if (s == null) return; s.visible = true; @@ -247,7 +248,7 @@ public class LooksPrims { if (s.visible) interp.redraw(); } - private function primHide(b:Array):void { + private function primHide(b:Block):void { var s:ScratchSprite = interp.targetSprite(); if ((s == null) || !s.visible) return; s.visible = false; @@ -255,8 +256,8 @@ public class LooksPrims { s.updateBubble(); interp.redraw(); } - - private function primHideAll(b:Array):void { + + private function primHideAll(b:Block):void { // Hide all sprites and delete all clones. Only works from the stage. if (!interp.targetObj().isStage) return; app.stagePane.deleteClones(); @@ -270,17 +271,17 @@ public class LooksPrims { interp.redraw(); } - private function primGoFront(b:Array):void { + private function primGoFront(b:Block):void { var s:ScratchSprite = interp.targetSprite(); if ((s == null) || (s.parent == null)) return; s.parent.setChildIndex(s, s.parent.numChildren - 1); if (s.visible) interp.redraw(); } - private function primGoBack(b:Array):void { + private function primGoBack(b:Block):void { var s:ScratchSprite = interp.targetSprite(); if ((s == null) || (s.parent == null)) return; - var newIndex:int = s.parent.getChildIndex(s) - interp.numarg(b[0]); + var newIndex:int = s.parent.getChildIndex(s) - interp.numarg(b, 0); newIndex = Math.max(minSpriteLayer(), Math.min(newIndex, s.parent.numChildren - 1)); if (newIndex > 0 && newIndex < s.parent.numChildren) { @@ -295,27 +296,27 @@ public class LooksPrims { return stg.getChildIndex(stg.videoImage ? stg.videoImage : stg.penLayer) + 1; } - private function primSetVideoState(b:Array):void { - app.stagePane.setVideoState(b[0]); + private function primSetVideoState(b:Block):void { + app.stagePane.setVideoState(interp.arg(b, 0)); } - private function primSetVideoTransparency(b:Array):void { - app.stagePane.setVideoTransparency(interp.numarg(b[0])); + private function primSetVideoTransparency(b:Block):void { + app.stagePane.setVideoTransparency(interp.numarg(b, 0)); app.stagePane.setVideoState('on'); } - private function primScrollAlign(b:Array):void { + private function primScrollAlign(b:Block):void { if (!interp.targetObj().isStage) return; - app.stagePane.scrollAlign(b[0]); + app.stagePane.scrollAlign(interp.arg(b, 0)); } - private function primScrollRight(b:Array):void { + private function primScrollRight(b:Block):void { if (!interp.targetObj().isStage) return; - app.stagePane.scrollRight(interp.numarg(b[0])); + app.stagePane.scrollRight(interp.numarg(b, 0)); } - private function primScrollUp(b:Array):void { + private function primScrollUp(b:Block):void { if (!interp.targetObj().isStage) return; - app.stagePane.scrollUp(interp.numarg(b[0])); + app.stagePane.scrollUp(interp.numarg(b, 0)); } }} diff --git a/src/primitives/MotionAndPenPrims.as b/src/primitives/MotionAndPenPrims.as index 26800036e..f101ede15 100644 --- a/src/primitives/MotionAndPenPrims.as +++ b/src/primitives/MotionAndPenPrims.as @@ -43,7 +43,7 @@ public class MotionAndPenPrims { this.interp = interpreter; } - public function addPrimsTo(primTable:Dictionary, specialTable:Dictionary):void { + public function addPrimsTo(primTable:Dictionary):void { primTable["forward:"] = primMove; primTable["turnRight:"] = primTurnRight; primTable["turnLeft:"] = primTurnLeft; @@ -51,7 +51,7 @@ public class MotionAndPenPrims { primTable["pointTowards:"] = primPointTowards; primTable["gotoX:y:"] = primGoTo; primTable["gotoSpriteOrMouse:"] = primGoToSpriteOrMouse; - specialTable["glideSecs:toX:y:elapsed:from:"] = primGlide; + primTable["glideSecs:toX:y:elapsed:from:"] = primGlide; primTable["changeXposBy:"] = primChangeX; primTable["xpos:"] = primSetX; @@ -77,41 +77,41 @@ public class MotionAndPenPrims { primTable["stampCostume"] = primStamp; } - private function primMove(b:Array):void { + private function primMove(b:Block):void { var s:ScratchSprite = interp.targetSprite(); if (s == null) return; var radians:Number = (Math.PI * (90 - s.direction)) / 180; - var d:Number = interp.numarg(b[0]); + var d:Number = interp.numarg(b, 0); moveSpriteTo(s, s.scratchX + (d * Math.cos(radians)), s.scratchY + (d * Math.sin(radians))); } - private function primTurnRight(b:Array):void { + private function primTurnRight(b:Block):void { var s:ScratchSprite = interp.targetSprite(); if (s != null) { - s.setDirection(s.direction + interp.numarg(b[0])); + s.setDirection(s.direction + interp.numarg(b, 0)); if (s.visible) interp.redraw(); } } - private function primTurnLeft(b:Array):void { + private function primTurnLeft(b:Block):void { var s:ScratchSprite = interp.targetSprite(); if (s != null) { - s.setDirection(s.direction - interp.numarg(b[0])); + s.setDirection(s.direction - interp.numarg(b, 0)); if (s.visible) interp.redraw(); } } - private function primSetDirection(b:Array):void { + private function primSetDirection(b:Block):void { var s:ScratchSprite = interp.targetSprite(); if (s != null) { - s.setDirection(interp.numarg(b[0])); + s.setDirection(interp.numarg(b, 0)); if (s.visible) interp.redraw(); } } - private function primPointTowards(b:Array):void { + private function primPointTowards(b:Block):void { var s:ScratchSprite = interp.targetSprite(); - var p:Point = mouseOrSpritePosition(b[0]); + var p:Point = mouseOrSpritePosition(interp.arg(b, 0)); if ((s == null) || (p == null)) return; var dx:Number = p.x - s.scratchX; var dy:Number = p.y - s.scratchY; @@ -120,25 +120,25 @@ public class MotionAndPenPrims { if (s.visible) interp.redraw(); } - private function primGoTo(b:Array):void { + private function primGoTo(b:Block):void { var s:ScratchSprite = interp.targetSprite(); - if (s != null) moveSpriteTo(s, interp.numarg(b[0]), interp.numarg(b[1])); + if (s != null) moveSpriteTo(s, interp.numarg(b, 0), interp.numarg(b, 1)); } - private function primGoToSpriteOrMouse(b:Array):void { + private function primGoToSpriteOrMouse(b:Block):void { var s:ScratchSprite = interp.targetSprite(); - var p:Point = mouseOrSpritePosition(b[0]); + var p:Point = mouseOrSpritePosition(interp.arg(b, 0)); if ((s == null) || (p == null)) return; moveSpriteTo(s, p.x, p.y); } - private function primGlide(b:Array):void { + private function primGlide(b:Block):void { var s:ScratchSprite = interp.targetSprite(); if (s == null) return; if (interp.activeThread.firstTime) { - var secs:Number = interp.numarg(b[0]); - var destX:Number = interp.numarg(b[1]); - var destY:Number = interp.numarg(b[2]); + var secs:Number = interp.numarg(b, 0); + var destX:Number = interp.numarg(b, 1); + var destY:Number = interp.numarg(b, 2); if (secs <= 0) { moveSpriteTo(s, destX, destY); return; @@ -179,27 +179,27 @@ public class MotionAndPenPrims { return null; } - private function primChangeX(b:Array):void { + private function primChangeX(b:Block):void { var s:ScratchSprite = interp.targetSprite(); - if (s != null) moveSpriteTo(s, s.scratchX + interp.numarg(b[0]), s.scratchY); + if (s != null) moveSpriteTo(s, s.scratchX + interp.numarg(b, 0), s.scratchY); } - private function primSetX(b:Array):void { + private function primSetX(b:Block):void { var s:ScratchSprite = interp.targetSprite(); - if (s != null) moveSpriteTo(s, interp.numarg(b[0]), s.scratchY); + if (s != null) moveSpriteTo(s, interp.numarg(b, 0), s.scratchY); } - private function primChangeY(b:Array):void { + private function primChangeY(b:Block):void { var s:ScratchSprite = interp.targetSprite(); - if (s != null) moveSpriteTo(s, s.scratchX, s.scratchY + interp.numarg(b[0])); + if (s != null) moveSpriteTo(s, s.scratchX, s.scratchY + interp.numarg(b, 0)); } - private function primSetY(b:Array):void { + private function primSetY(b:Block):void { var s:ScratchSprite = interp.targetSprite(); - if (s != null) moveSpriteTo(s, s.scratchX, interp.numarg(b[0])); + if (s != null) moveSpriteTo(s, s.scratchX, interp.numarg(b, 0)); } - private function primBounceOffEdge(b:Array):void { + private function primBounceOffEdge(b:Block):void { var s:ScratchSprite = interp.targetSprite(); if (s == null) return; if (!turnAwayFromEdge(s)) return; @@ -207,17 +207,17 @@ public class MotionAndPenPrims { if (s.visible) interp.redraw(); } - private function primXPosition(b:Array):Number { + private function primXPosition(b:Block):Number { var s:ScratchSprite = interp.targetSprite(); return (s != null) ? snapToInteger(s.scratchX) : 0; } - private function primYPosition(b:Array):Number { + private function primYPosition(b:Block):Number { var s:ScratchSprite = interp.targetSprite(); return (s != null) ? snapToInteger(s.scratchY) : 0; } - private function primDirection(b:Array):Number { + private function primDirection(b:Block):Number { var s:ScratchSprite = interp.targetSprite(); return (s != null) ? snapToInteger(s.direction) : 0; } @@ -229,12 +229,12 @@ public class MotionAndPenPrims { return (delta < 1e-9) ? rounded : n; } - private function primClear(b:Array):void { + private function primClear(b:Block):void { app.stagePane.clearPenStrokes(); interp.redraw(); } - private function primPenDown(b:Array):void { + private function primPenDown(b:Block):void { var s:ScratchSprite = interp.targetSprite(); if (s != null) s.penIsDown = true; touch(s, s.scratchX, s.scratchY); @@ -252,47 +252,47 @@ public class MotionAndPenPrims { app.stagePane.penActivity = true; } - private function primPenUp(b:Array):void { + private function primPenUp(b:Block):void { var s:ScratchSprite = interp.targetSprite(); if (s != null) s.penIsDown = false; } - private function primSetPenColor(b:Array):void { + private function primSetPenColor(b:Block):void { var s:ScratchSprite = interp.targetSprite(); - if (s != null) s.setPenColor(interp.numarg(b[0])); + if (s != null) s.setPenColor(interp.numarg(b, 0)); } - private function primSetPenHue(b:Array):void { + private function primSetPenHue(b:Block):void { var s:ScratchSprite = interp.targetSprite(); - if (s != null) s.setPenHue(interp.numarg(b[0])); + if (s != null) s.setPenHue(interp.numarg(b, 0)); } - private function primChangePenHue(b:Array):void { + private function primChangePenHue(b:Block):void { var s:ScratchSprite = interp.targetSprite(); - if (s != null) s.setPenHue(s.penHue + interp.numarg(b[0])); + if (s != null) s.setPenHue(s.penHue + interp.numarg(b, 0)); } - private function primSetPenShade(b:Array):void { + private function primSetPenShade(b:Block):void { var s:ScratchSprite = interp.targetSprite(); - if (s != null) s.setPenShade(interp.numarg(b[0])); + if (s != null) s.setPenShade(interp.numarg(b, 0)); } - private function primChangePenShade(b:Array):void { + private function primChangePenShade(b:Block):void { var s:ScratchSprite = interp.targetSprite(); - if (s != null) s.setPenShade(s.penShade + interp.numarg(b[0])); + if (s != null) s.setPenShade(s.penShade + interp.numarg(b, 0)); } - private function primSetPenSize(b:Array):void { + private function primSetPenSize(b:Block):void { var s:ScratchSprite = interp.targetSprite(); - if (s != null) s.setPenSize(Math.max(1, Math.min(960, Math.round(interp.numarg(b[0]))))); + if (s != null) s.setPenSize(Math.max(1, Math.min(960, Math.round(interp.numarg(b, 0))))); } - private function primChangePenSize(b:Array):void { + private function primChangePenSize(b:Block):void { var s:ScratchSprite = interp.targetSprite(); - if (s != null) s.setPenSize(s.penWidth + interp.numarg(b[0])); + if (s != null) s.setPenSize(s.penWidth + interp.numarg(b, 0)); } - - private function primStamp(b:Array):void { + + private function primStamp(b:Block):void { var s:ScratchSprite = interp.targetSprite(); // In 3D mode, get the alpha from the ghost filter // Otherwise, it can be easily accessed from the color transform. diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index b625fda6d..d085b25b3 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -48,31 +48,31 @@ public class Primitives { this.interp = interpreter; } - public function addPrimsTo(primTable:Dictionary, specialTable:Dictionary):void { + public function addPrimsTo(primTable:Dictionary):void { // operators - primTable["+"] = function(b:*):* { return interp.numarg(b[0]) + interp.numarg(b[1]) }; - primTable["-"] = function(b:*):* { return interp.numarg(b[0]) - interp.numarg(b[1]) }; - primTable["*"] = function(b:*):* { return interp.numarg(b[0]) * interp.numarg(b[1]) }; - primTable["/"] = function(b:*):* { return interp.numarg(b[0]) / interp.numarg(b[1]) }; + primTable["+"] = function(b:*):* { return interp.numarg(b, 0) + interp.numarg(b, 1) }; + primTable["-"] = function(b:*):* { return interp.numarg(b, 0) - interp.numarg(b, 1) }; + primTable["*"] = function(b:*):* { return interp.numarg(b, 0) * interp.numarg(b, 1) }; + primTable["/"] = function(b:*):* { return interp.numarg(b, 0) / interp.numarg(b, 1) }; primTable["randomFrom:to:"] = primRandom; - primTable["<"] = function(b:*):* { return compare(b[0], b[1]) < 0 }; - primTable["="] = function(b:*):* { return compare(b[0], b[1]) == 0 }; - primTable[">"] = function(b:*):* { return compare(b[0], b[1]) > 0 }; - primTable["&"] = function(b:*):* { return interp.boolarg(b[0]) && interp.boolarg(b[1]) }; - primTable["|"] = function(b:*):* { return interp.boolarg(b[0]) || interp.boolarg(b[1]) }; - primTable["not"] = function(b:*):* { return !interp.boolarg(b[0]) }; - primTable["abs"] = function(b:*):* { return Math.abs(interp.numarg(b[0])) }; - primTable["sqrt"] = function(b:*):* { return Math.sqrt(interp.numarg(b[0])) }; - primTable["power:of:"] = function(b:*):* { return Math.pow(interp.numarg(b[0]), interp.numarg(b[1])) }; + primTable["<"] = function(b:*):* { return compare(interp.arg(b, 0), interp.arg(b, 1)) < 0 }; + primTable["="] = function(b:*):* { return compare(interp.arg(b, 0), interp.arg(b, 1)) == 0 }; + primTable[">"] = function(b:*):* { return compare(interp.arg(b, 0), interp.arg(b, 1)) > 0 }; + primTable["&"] = function(b:*):* { return interp.arg(b, 0) && interp.arg(b, 1) }; + primTable["|"] = function(b:*):* { return interp.arg(b, 0) || interp.arg(b, 1) }; + primTable["not"] = function(b:*):* { return !interp.arg(b, 0) }; + primTable["abs"] = function(b:*):* { return Math.abs(interp.numarg(b, 0)) }; + primTable["sqrt"] = function(b:*):* { return Math.sqrt(interp.numarg(b, 0)) }; + primTable["power:of:"] = function(b:*):* { return Math.pow(interp.numarg(b, 0), interp.numarg(b, 1)) }; primTable["reverseString:"] = primReverseString; primTable["splitStringFrom:"] = primSplit; - primTable["concatenate:with:"] = function(b:*):* { return ("" + b[0] + b[1]).substr(0, 10240); }; + primTable["concatenate:with:"] = function(b:*):* { return ("" + interp.arg(b, 0) + interp.arg(b, 1)).substr(0, 10240); }; primTable["letter:of:"] = primLetterOf; - primTable["stringLength:"] = function(b:*):* { return String(b[0]).length }; + primTable["stringLength:"] = function(b:*):* { return String(interp.arg(b, 0)).length }; primTable["%"] = primModulo; - primTable["rounded"] = function(b:*):* { return Math.round(interp.numarg(b[0])) }; + primTable["rounded"] = function(b:*):* { return Math.round(interp.numarg(b, 0)) }; primTable["computeFunction:of:"] = primMathFunction; primTable["chooseConstant:"] = primGetConstant; @@ -95,49 +95,54 @@ public class Primitives { primTable["httpBlock:"] = primHttp; primTable["httpReturn:"] = function(b:*):* {return httpReturn}; - new LooksPrims(app, interp).addPrimsTo(primTable, specialTable); - new MotionAndPenPrims(app, interp).addPrimsTo(primTable, specialTable); - new SoundPrims(app, interp).addPrimsTo(primTable, specialTable); - new VideoMotionPrims(app, interp).addPrimsTo(primTable, specialTable); - addOtherPrims(primTable, specialTable); + new LooksPrims(app, interp).addPrimsTo(primTable); + new MotionAndPenPrims(app, interp).addPrimsTo(primTable); + new SoundPrims(app, interp).addPrimsTo(primTable); + new VideoMotionPrims(app, interp).addPrimsTo(primTable); + addOtherPrims(primTable); } - protected function addOtherPrims(primTable:Dictionary, specialTable:Dictionary):void { - new SensingPrims(app, interp).addPrimsTo(primTable, specialTable); - new ListPrims(app, interp).addPrimsTo(primTable, specialTable); + protected function addOtherPrims(primTable:Dictionary):void { + new SensingPrims(app, interp).addPrimsTo(primTable); + new ListPrims(app, interp).addPrimsTo(primTable); } - private function primRandom(b:Array):Number { - var n1:Number = interp.numarg(b[0]); - var n2:Number = interp.numarg(b[1]); + private function primRandom(b:Block):Number { + var n1:Number = interp.numarg(b, 0); + var n2:Number = interp.numarg(b, 1); var low:Number = (n1 <= n2) ? n1 : n2; var hi:Number = (n1 <= n2) ? n2 : n1; if (low == hi) return low; + // if both low and hi are ints, truncate the result to an int - if ((int(low) == low) && (int(hi) == hi)) { + var ba1:BlockArg = b.args[0] as BlockArg; + var ba2:BlockArg = b.args[1] as BlockArg; + var int1:Boolean = ba1 ? ba1.numberType == BlockArg.NT_INT : int(n1) == n1; + var int2:Boolean = ba2 ? ba2.numberType == BlockArg.NT_INT : int(n2) == n2; + if (int1 && int2) return low + int(Math.random() * ((hi + 1) - low)); - } + return (Math.random() * (hi - low)) + low; } - private function primLetterOf(b:Array):String { - var s:String = b[1]; - var i:int = interp.numarg(b[0]) - 1; + private function primLetterOf(b:Block):String { + var s:String = interp.arg(b, 1); + var i:int = interp.numarg(b, 0) - 1; if ((i < 0) || (i >= s.length)) return ""; return s.charAt(i); } - private function primModulo(b:Array):Number { - var n:Number = interp.numarg(b[0]); - var modulus:Number = interp.numarg(b[1]); + private function primModulo(b:Block):Number { + var n:Number = interp.numarg(b, 0); + var modulus:Number = interp.numarg(b, 1); var result:Number = n % modulus; if (result / modulus < 0) result += modulus; return result; } - private function primMathFunction(b:Array):Number { - var op:* = b[0]; - var n:Number = interp.numarg(b[1]); + private function primMathFunction(b:Block):Number { + var op:* = interp.arg(b, 0); + var n:Number = interp.numarg(b, 1); switch(op) { case "abs": return Math.abs(n); case "floor": return Math.floor(n); @@ -185,8 +190,8 @@ public class Primitives { return 1; } - private function primCreateCloneOf(b:Array):void { - var objName:String = b[0]; + private function primCreateCloneOf(b:Block):void { + var objName:String = interp.arg(b, 0); var proto:ScratchSprite = app.stagePane.spriteNamed(objName); if ('_myself_' == objName) proto = interp.activeThread.target; if (!proto) return; @@ -208,7 +213,7 @@ public class Primitives { app.runtime.cloneCount++; } - private function primDeleteClone(b:Array):void { + private function primDeleteClone(b:Block):void { var clone:ScratchSprite = interp.targetSprite(); if ((clone == null) || (!clone.isClone) || (clone.parent == null)) return; if (clone.bubble && clone.bubble.parent) clone.bubble.parent.removeChild(clone.bubble); @@ -216,9 +221,9 @@ public class Primitives { app.interp.stopThreadsFor(clone); app.runtime.cloneCount--; } - - private function primReverseString(b:Array):String { - var reverse:String = b[0]; + + private function primReverseString(b:Block):String { + var reverse:String = interp.arg(b, 0); var result:String = ""; var i:int; for(i = reverse.length; i > 0; i--) { @@ -228,8 +233,8 @@ public class Primitives { } - private function primGetConstant(b:Array):Number { - var pickConstant:* = b[0]; + private function primGetConstant(b:Block):Number { + var pickConstant:* = interp.arg(b, 0); switch(pickConstant) { case "Pi": return Math.PI; case "E": return Math.E; @@ -248,10 +253,10 @@ public class Primitives { } // Sharp --- HTTP - private function primHttp(b:Array):void { + private function primHttp(b:Block):void { if(httpRequestsActive == httpRequestsAllowed) return; httpRequestsActive++; - var url:String = b[0]; + var url:String = interp.arg(b, 1); var req:URLRequest = new URLRequest(url); req.method = URLRequestMethod.GET; diff --git a/src/primitives/SensingPrims.as b/src/primitives/SensingPrims.as index cac184325..a4ea745ff 100644 --- a/src/primitives/SensingPrims.as +++ b/src/primitives/SensingPrims.as @@ -43,13 +43,13 @@ public class SensingPrims { this.interp = interpreter; } - public function addPrimsTo(primTable:Dictionary, specialTable:Dictionary):void { + public function addPrimsTo(primTable:Dictionary):void { // sensing primTable['touching:'] = primTouching; primTable['touchingColor:'] = primTouchingColor; primTable['color:sees:'] = primColorSees; - specialTable['doAsk'] = primAsk; + primTable['doAsk'] = primAsk; primTable['answer'] = function(b:*):* { return app.runtime.lastAnswer }; primTable['mousePressed'] = function(b:*):* { return app.gh.mouseIsDown }; @@ -63,12 +63,12 @@ public class SensingPrims { primTable['soundLevel'] = function(b:*):* { return app.runtime.soundLevel() }; primTable['isLoud'] = function(b:*):* { return app.runtime.isLoud() }; primTable['timestamp'] = primTimestamp; - primTable['timeAndDate'] = function(b:*):* { return app.runtime.getTimeString(b[0]) }; + primTable['timeAndDate'] = function(b:*):* { return app.runtime.getTimeString(interp.arg(b, 0)) }; //primTable['getUserName'] = function(b:*):* { return '' }; // sensor - primTable['sensor:'] = function(b:*):* { return app.runtime.getSensor(b[0]) }; - primTable['sensorPressed:'] = function(b:*):* { return app.runtime.getBooleanSensor(b[0]) }; + primTable['sensor:'] = function(b:*):* { return app.runtime.getSensor(interp.arg(b, 0)) }; + primTable['sensorPressed:'] = function(b:*):* { return app.runtime.getBooleanSensor(interp.arg(b, 0)) }; // variable and list watchers primTable['showVariable:'] = primShowWatcher; @@ -85,18 +85,18 @@ public class SensingPrims { } // Sharp - private function primNotify(b:Array):void{ + private function primNotify(b:Block):void{ if(dialogBoxActive == dialogBoxAllowed) return; dialogBoxActive++; - DialogBox.notify(b[1],b[0],null,false, function(d:*):*{ dialogBoxActive--; }); + DialogBox.notify(interp.arg(b,1),interp.arg(b,0),null,false, function(d:*):*{ dialogBoxActive--; }); } // TODO: move to stage static private var stageRect:Rectangle = new Rectangle(0, 0, 480, 360); - private function primTouching(b:Array):Boolean { + private function primTouching(b:Block):Boolean { var s:ScratchSprite = interp.targetSprite(); if (s == null) return false; - var arg:* = b[0]; + var arg:* = interp.arg(b, 0); if ('_edge_' == arg) { if(stageRect.containsRect(s.getBounds(s.parent))) return false; @@ -132,12 +132,12 @@ public class SensingPrims { // private var testSpr:Sprite; // private var myBMTest:Bitmap; // private var stageBMTest:Bitmap; - private function primTouchingColor(b:Array):Boolean { + private function primTouchingColor(b:Block):Boolean { // Note: Attempted to switch app.stage.quality to LOW to disable anti-aliasing, which // can create false colors. Unfortunately, that caused serious performance issues. var s:ScratchSprite = interp.targetSprite(); if (s == null) return false; - var c:int = b[0] | 0xFF000000; + var c:int = interp.arg(b, 0) | 0xFF000000; var myBM:BitmapData = s.bitmap(true); var stageBM:BitmapData = stageBitmapWithoutSpriteFilteredByColor(s, c); // if(s.objName == 'sensor') { @@ -160,13 +160,13 @@ public class SensingPrims { return myBM.hitTest(new Point(0, 0), 1, stageBM, new Point(0, 0), 1); } - private function primColorSees(b:Array):Boolean { + private function primColorSees(b:Block):Boolean { // Note: Attempted to switch app.stage.quality to LOW to disable anti-aliasing, which // can create false colors. Unfortunately, that caused serious performance issues. var s:ScratchSprite = interp.targetSprite(); if (s == null) return false; - var c1:int = b[0] | 0xFF000000; - var c2:int = b[1] | 0xFF000000; + var c1:int = interp.arg(b, 0) | 0xFF000000; + var c2:int = interp.arg(b, 1) | 0xFF000000; var myBM:BitmapData = bitmapFilteredByColor(s.bitmap(true), c1); var stageBM:BitmapData = stageBitmapWithoutSpriteFilteredByColor(s, c2); // if(!testSpr) { @@ -215,7 +215,7 @@ public class SensingPrims { return app.stagePane.getBitmapWithoutSpriteFilteredByColor(s, c); } - private function primAsk(b:Array):void { + private function primAsk(b:Block):void { if (app.runtime.askPromptShowing()) { // wait if (1) some other sprite is asking (2) this question is answered (when firstTime is false) interp.doYield(); @@ -223,7 +223,7 @@ public class SensingPrims { } var obj:ScratchObj = interp.targetObj(); if (interp.activeThread.firstTime) { - var question:String = b[0]; + var question:String = interp.arg(b, 0); if ((obj is ScratchSprite) && (obj.visible)) { ScratchSprite(obj).showBubble(question, 'talk', true); app.runtime.showAskPrompt(''); @@ -234,15 +234,12 @@ public class SensingPrims { interp.doYield(); } else { if ((obj is ScratchSprite) && (obj.visible)) ScratchSprite(obj).hideBubble(); - var block:Block = interp.activeThread.block; - interp.activeThread.popState(); - interp.activeThread.firstTime = true; - if (block.nextBlock) interp.activeThread.pushStateForBlock(block.nextBlock); + interp.activeThread.firstTime = true; } } - private function primKeyPressed(b:Array):Boolean { - var key:String = b[0]; + private function primKeyPressed(b:Block):Boolean { + var key:String = interp.arg(b, 0); if (key == 'any') { for each (var k:Boolean in app.runtime.keyIsDown) { if (k) return true; @@ -259,18 +256,18 @@ public class SensingPrims { return app.runtime.keyIsDown[ch]; } - private function primDistanceTo(b:Array):Number { + private function primDistanceTo(b:Block):Number { var s:ScratchSprite = interp.targetSprite(); - var p:Point = mouseOrSpritePosition(b[0]); + var p:Point = mouseOrSpritePosition(interp.arg(b, 0)); if ((s == null) || (p == null)) return 10000; var dx:Number = p.x - s.scratchX; var dy:Number = p.y - s.scratchY; return Math.sqrt((dx * dx) + (dy * dy)); } - private function primGetAttribute(b:Array):* { - var attribute:String = b[0]; - var obj:ScratchObj = app.stagePane.objNamed(String(b[1])); + private function primGetAttribute(b:Block):* { + var attribute:String = interp.arg(b, 0); + var obj:ScratchObj = app.stagePane.objNamed(String(interp.arg(b, 1))); if (!(obj is ScratchObj)) return 0; if (obj is ScratchSprite) { var s:ScratchSprite = ScratchSprite(obj); @@ -303,27 +300,27 @@ public class SensingPrims { return null; } - private function primShowWatcher(b:Array):* { + private function primShowWatcher(b:Block):* { var obj:ScratchObj = interp.targetObj(); - if (obj) app.runtime.showVarOrListFor(b[0], false, obj); + if (obj) app.runtime.showVarOrListFor(interp.arg(b, 0), false, obj); } - private function primHideWatcher(b:Array):* { + private function primHideWatcher(b:Block):* { var obj:ScratchObj = interp.targetObj(); - if (obj) app.runtime.hideVarOrListFor(b[0], false, obj); + if (obj) app.runtime.hideVarOrListFor(interp.arg(b, 0), false, obj); } - private function primShowListWatcher(b:Array):* { + private function primShowListWatcher(b:Block):* { var obj:ScratchObj = interp.targetObj(); - if (obj) app.runtime.showVarOrListFor(b[0], true, obj); + if (obj) app.runtime.showVarOrListFor(interp.arg(b, 0), true, obj); } - private function primHideListWatcher(b:Array):* { + private function primHideListWatcher(b:Block):* { var obj:ScratchObj = interp.targetObj(); - if (obj) app.runtime.hideVarOrListFor(b[0], true, obj); + if (obj) app.runtime.hideVarOrListFor(interp.arg(b, 0), true, obj); } - private function primTimestamp(b:Array):* { + private function primTimestamp(b:Block):* { const millisecondsPerDay:int = 24 * 60 * 60 * 1000; const epoch:Date = new Date(2000, 0, 1); // Jan 1, 2000 (Note: Months are zero-based.) var now:Date = new Date(); diff --git a/src/primitives/SoundPrims.as b/src/primitives/SoundPrims.as index caf463da3..e25ad3d5b 100644 --- a/src/primitives/SoundPrims.as +++ b/src/primitives/SoundPrims.as @@ -39,16 +39,16 @@ public class SoundPrims { this.interp = interpreter; } - public function addPrimsTo(primTable:Dictionary, specialTable:Dictionary):void { + public function addPrimsTo(primTable:Dictionary):void { primTable["playSound:"] = primPlaySound; - specialTable["doPlaySoundAndWait"] = primPlaySoundUntilDone; + primTable["doPlaySoundAndWait"] = primPlaySoundUntilDone; primTable["stopAllSounds"] = function(b:*):* { ScratchSoundPlayer.stopAllSounds() }; - specialTable["drum:duration:elapsed:from:"] = primPlayDrum; // Scratch 1.4 drum numbers - specialTable["playDrum"] = primPlayDrum; - specialTable["rest:elapsed:from:"] = primPlayRest; + primTable["drum:duration:elapsed:from:"] = primPlayDrum; // Scratch 1.4 drum numbers + primTable["playDrum"] = primPlayDrum; + primTable["rest:elapsed:from:"] = primPlayRest; - specialTable["noteOn:duration:elapsed:from:"] = primPlayNote; + primTable["noteOn:duration:elapsed:from:"] = primPlayNote; primTable["midiInstrument:"] = primSetInstrument; // Scratch 1.4 instrument numbers primTable["instrument:"] = primSetInstrument; @@ -56,96 +56,121 @@ public class SoundPrims { primTable["setVolumeTo:"] = primSetVolume; primTable["volume"] = primVolume; - primTable["changeTempoBy:"] = function(b:*):* { app.stagePane.setTempo(app.stagePane.tempoBPM + interp.numarg(b[0])) }; - primTable["setTempoTo:"] = function(b:*):* { app.stagePane.setTempo(interp.numarg(b[0])) }; + primTable["changeTempoBy:"] = function(b:*):* { + app.stagePane.setTempo(app.stagePane.tempoBPM + interp.numarg(b, 0)); + interp.redraw(); + }; + primTable["setTempoTo:"] = function(b:*):* { + app.stagePane.setTempo(interp.numarg(b, 0)); + interp.redraw(); + }; primTable["tempo"] = function(b:*):* { return app.stagePane.tempoBPM }; } - private function primPlaySound(b:Array):void { - var snd:ScratchSound = interp.targetObj().findSound(b[0]); - if (snd != null) playSound(snd, interp.targetObj()); + private function primPlaySound(b:Block):void { + if(Scratch.app.sharpSettings.data.allowSound){ + var snd:ScratchSound = interp.targetObj().findSound(interp.arg(b, 0)); + if (snd != null) playSound(snd, interp.targetObj()); + } } - private function primPlaySoundUntilDone(b:Array):void { - var activeThread:Thread = interp.activeThread; - if (activeThread.firstTime) { - var snd:ScratchSound = interp.targetObj().findSound(b[0]); - if (snd == null) return; - activeThread.tmpObj = playSound(snd, interp.targetObj()); - activeThread.firstTime = false; - } - var player:ScratchSoundPlayer = ScratchSoundPlayer(activeThread.tmpObj); - if ((player == null) || player.atEnd()) { // finished playing - activeThread.tmp = 0; - activeThread.firstTime = true; - var block:Block = activeThread.block; - activeThread.popState(); - if (block.nextBlock) activeThread.pushStateForBlock(block.nextBlock); - } else { - interp.doYield(); + private function primPlaySoundUntilDone(b:Block):void { + if(Scratch.app.sharpSettings.data.allowSound){ + var activeThread:Thread = interp.activeThread; + if (activeThread.firstTime) { + var snd:ScratchSound = interp.targetObj().findSound(interp.arg(b, 0)); + if (snd == null) return; + activeThread.tmpObj = playSound(snd, interp.targetObj()); + activeThread.firstTime = false; + } + var player:ScratchSoundPlayer = ScratchSoundPlayer(activeThread.tmpObj); + if ((player == null) || (player.atEnd())) { // finished playing + activeThread.tmp = 0; + activeThread.firstTime = true; + } else { + interp.doYield(); + } } } - private function primPlayNote(b:Array):void { - var s:ScratchObj = interp.targetObj(); - if (s == null) return; - if (interp.activeThread.firstTime) { - var key:Number = interp.numarg(b[0]); - var secs:Number = beatsToSeconds(interp.numarg(b[1])); - interp.activeThread.tmpObj = playNote(s.instrument, key, secs, s); - interp.startTimer(secs); - } else { - interp.checkTimer(); + private function primPlayNote(b:Block):void { + if(Scratch.app.sharpSettings.data.allowSound){ + var s:ScratchObj = interp.targetObj(); + if (s == null) return; + if (interp.activeThread.firstTime) { + var key:Number = interp.numarg(b, 0); + var secs:Number = beatsToSeconds(interp.numarg(b, 1)); + interp.activeThread.tmpObj = playNote(s.instrument, key, secs, s); + interp.startTimer(secs); + } else { + interp.checkTimer(); + } } } - private function primPlayDrum(b:Array):void { - var s:ScratchObj = interp.targetObj(); - if (s == null) return; - if (interp.activeThread.firstTime) { - var drum:int = Math.round(interp.numarg(b[0])); - var isMIDI:Boolean = (b.op == 'drum:duration:elapsed:from:'); - var secs:Number = beatsToSeconds(interp.numarg(b[1])); - playDrum(drum, isMIDI, 10, s); // always play entire drum sample - interp.startTimer(secs); - } else { - interp.checkTimer(); + private function primPlayDrum(b:Block):void { + if(Scratch.app.sharpSettings.data.allowSound){ + var s:ScratchObj = interp.targetObj(); + if (s == null) return; + if (interp.activeThread.firstTime) { + var drum:int = Math.round(interp.numarg(b, 0)); + var isMIDI:Boolean = (b.op == 'drum:duration:elapsed:from:'); + var secs:Number = beatsToSeconds(interp.numarg(b, 1)); + playDrum(drum, isMIDI, 10, s); // always play entire drum sample + interp.startTimer(secs); + } else { + interp.checkTimer(); + } } } private function playSound(s:ScratchSound, client:ScratchObj):ScratchSoundPlayer { - var player:ScratchSoundPlayer = s.sndplayer(); - player.client = client; - player.startPlaying(); - return player; + if(Scratch.app.sharpSettings.data.allowSound){ + var player:ScratchSoundPlayer = s.sndplayer(); + player.client = client; + player.startPlaying(); + return player; + }else{ + return null; + } } private function playDrum(drum:int, isMIDI:Boolean, secs:Number, client:ScratchObj):ScratchSoundPlayer { - var player:NotePlayer = SoundBank.getDrumPlayer(drum, isMIDI, secs); - if (player == null) return null; - player.client = client; - player.setDuration(secs); - player.startPlaying(); - return player; + if(Scratch.app.sharpSettings.data.allowSound){ + var player:NotePlayer = SoundBank.getDrumPlayer(drum, isMIDI, secs); + if (player == null) return null; + player.client = client; + player.setDuration(secs); + player.startPlaying(); + return player; + }else{ + return null; + } } private function playNote(instrument:int, midiKey:Number, secs:Number, client:ScratchObj):ScratchSoundPlayer { - var player:NotePlayer = SoundBank.getNotePlayer(instrument, midiKey); - if (player == null) return null; - player.client = client; - player.setNoteAndDuration(midiKey, secs); - player.startPlaying(); - return player; + if(Scratch.app.sharpSettings.data.allowSound){ + var player:NotePlayer = SoundBank.getNotePlayer(instrument, midiKey); + if (player == null) return null; + player.client = client; + player.setNoteAndDuration(midiKey, secs); + player.startPlaying(); + return player; + }else{ + return null; + } } - private function primPlayRest(b:Array):void { - var s:ScratchObj = interp.targetObj(); - if (s == null) return; - if (interp.activeThread.firstTime) { - var secs:Number = beatsToSeconds(interp.numarg(b[0])); - interp.startTimer(secs); - } else { - interp.checkTimer(); + private function primPlayRest(b:Block):void { + if(Scratch.app.sharpSettings.data.allowSound){ + var s:ScratchObj = interp.targetObj(); + if (s == null) return; + if (interp.activeThread.firstTime) { + var secs:Number = beatsToSeconds(interp.numarg(b, 0)); + interp.startTimer(secs); + } else { + interp.checkTimer(); + } } } @@ -153,28 +178,36 @@ public class SoundPrims { return (beats * 60) / app.stagePane.tempoBPM; } - private function primSetInstrument(b:Array):void { - // Set Scratch 2.0 instrument. - var instr:int = interp.numarg(b[0]) - 1; - if (b.op == 'midiInstrument:') { - // map old to new instrument number - instr = instrumentMap[instr] - 1; // maps to -1 if out of range + private function primSetInstrument(b:Block):void { + if(Scratch.app.sharpSettings.data.allowSound){ + // Set Scratch 2.0 instrument. + var instr:int = interp.numarg(b, 0) - 1; + if (b.op == 'midiInstrument:') { + // map old to new instrument number + instr = instrumentMap[instr] - 1; // maps to -1 if out of range + } + instr = Math.max(0, Math.min(instr, SoundBank.instrumentNames.length - 1)); + if (interp.targetObj()) interp.targetObj().instrument = instr; } - instr = Math.max(0, Math.min(instr, SoundBank.instrumentNames.length - 1)); - if (interp.targetObj()) interp.targetObj().instrument = instr; } - private function primChangeVolume(b:Array):void { + private function primChangeVolume(b:Block):void { var s:ScratchObj = interp.targetObj(); - if (s != null) s.setVolume(s.volume + interp.numarg(b[0])); + if (s != null) { + s.setVolume(s.volume + interp.numarg(b, 0)); + interp.redraw(); + } } - private function primSetVolume(b:Array):void { + private function primSetVolume(b:Block):void { var s:ScratchObj = interp.targetObj(); - if (s != null) s.setVolume(interp.numarg(b[0])); + if (s != null) { + s.setVolume(interp.numarg(b, 0)); + interp.redraw(); + } } - private function primVolume(b:Array):Number { + private function primVolume(b:Block):Number { var s:ScratchObj = interp.targetObj(); return (s != null) ? s.volume : 0; } @@ -246,4 +279,5 @@ public class SoundPrims { // Telephone Ring, Helicopter, Applause, Gunshot 21, 21, 21, 21 ]; -}} \ No newline at end of file + +}} diff --git a/src/primitives/VideoMotionPrims.as b/src/primitives/VideoMotionPrims.as index 12b958348..6bf77bf42 100644 --- a/src/primitives/VideoMotionPrims.as +++ b/src/primitives/VideoMotionPrims.as @@ -65,15 +65,15 @@ public class VideoMotionPrims { frameBuffer = new BitmapData(WIDTH, HEIGHT); } - public function addPrimsTo(primTable:Dictionary, specialTable:Dictionary):void { + public function addPrimsTo(primTable:Dictionary):void { primTable['senseVideoMotion'] = primVideoMotion; readMotionSensor = getMotionOn; } - private function primVideoMotion(b:Array):Number { - var motionType:String = b[0]; - var obj:ScratchObj = app.stagePane.objNamed(String(b[1])); - if ('this sprite' == b[1]) obj = interp.targetObj(); + private function primVideoMotion(b:Block):Number { + var motionType:String = interp.arg(b, 0); + var obj:ScratchObj = app.stagePane.objNamed(String(interp.arg(b, 1))); + if ('this sprite' == interp.arg(b, 1)) obj = interp.targetObj(); return getMotionOn(motionType, obj); } @@ -282,4 +282,4 @@ public class VideoMotionPrims { analysisDone = true; } -}} \ No newline at end of file +}} diff --git a/src/scratch/BlockMenus.as b/src/scratch/BlockMenus.as index 430c47e21..bc5656c6d 100644 --- a/src/scratch/BlockMenus.as +++ b/src/scratch/BlockMenus.as @@ -589,7 +589,7 @@ public class BlockMenus implements DragClient { } var d:DialogBox = new DialogBox(editSpec2); d.addTitle('Edit Block'); - d.addWidget(new ProcedureSpecEditor(block.spec, block.parameterNames, block.warpProcFlag, block.procedureType, true)); + d.addWidget(new ProcedureSpecEditor(block.spec, block.parameterNames, block.warpProcFlag)); d.addAcceptCancelButtons('OK'); d.showOnStage(app.stage, true); ProcedureSpecEditor(d.widget).setInitialFocus(); @@ -603,7 +603,6 @@ public class BlockMenus implements DragClient { block.parameterNames = ProcedureSpecEditor(dialog.widget).inputNames(); block.defaultArgValues = ProcedureSpecEditor(dialog.widget).defaultArgValues(); block.warpProcFlag = ProcedureSpecEditor(dialog.widget).warpFlag(); - block.procedureType = ProcedureSpecEditor(dialog.widget).type(); block.setSpec(newSpec); if (block.nextBlock) block.nextBlock.allBlocksDo(function(b:Block):void { if (b.op == Specs.GET_PARAM) b.parameterIndex = -1; // parameters may have changed; clear cached indices diff --git a/src/scratch/PaletteBuilder.as b/src/scratch/PaletteBuilder.as index 10e22d343..5890cec14 100644 --- a/src/scratch/PaletteBuilder.as +++ b/src/scratch/PaletteBuilder.as @@ -129,11 +129,13 @@ public class PaletteBuilder { var catColor:int = Specs.blockColor(Specs.procedureColor); addItem(new Button(Translator.map('Make a Block'), makeNewBlock, false, '/help/studio/tips/blocks/make-a-block/')); var definitions:Array = app.viewedObj().procedureDefinitions(); - addBlocksForCategory(10, Specs.procedureColor); if (definitions.length > 0) { nextY += 5; for each (var proc:Block in definitions) { - var b:Block = new Block(proc.spec, proc.procedureType, Specs.procedureColor, Specs.CALL, proc.defaultArgValues); + //if(!proc.isCustomReporter && !proc.isCustomBoolean) var b:Block = new Block(proc.spec, ' ', Specs.procedureColor, Specs.CALL, proc.defaultArgValues); + //if(proc.isCustomReporter && !proc.isCustomBoolean) var b:Block = new Block(proc.spec, 'r', Specs.procedureColor, Specs.CALL, proc.defaultArgValues); + //if(!proc.isCustomReporter && proc.isCustomBoolean) var b:Block = new Block(proc.spec, 'b', Specs.procedureColor, Specs.CALL, proc.defaultArgValues); + var b:Block = new Block(proc.spec, ' ', Specs.procedureColor, Specs.CALL, proc.defaultArgValues); addItem(b); } nextY += 5; @@ -255,7 +257,10 @@ public class PaletteBuilder { newHat.parameterNames = specEditor.inputNames(); newHat.defaultArgValues = specEditor.defaultArgValues(); newHat.warpProcFlag = specEditor.warpFlag(); - newHat.procedureType = specEditor.type(); + //if(specEditor.returnValuesCheckbox.isOn() && !specEditor.returnBooleanCheckbox.isOn()) newHat.setCustomBlockType(Block.CUSTOM_REPORTER); + //if(specEditor.returnValuesCheckbox.isOn() && specEditor.returnBooleanCheckbox.isOn()) newHat.setCustomBlockType(Block.CUSTOM_BOOLEAN); + //if(!specEditor.returnValuesCheckbox.isOn() && !specEditor.returnBooleanCheckbox.isOn()) newHat.setCustomBlockType(Block.CUSTOM_COMMAND); + newHat.setCustomBlockType(Block.CUSTOM_COMMAND); newHat.setSpec(spec); newHat.x = 10 - app.scriptsPane.x + Math.random() * 100; newHat.y = 10 - app.scriptsPane.y + Math.random() * 100; @@ -266,7 +271,7 @@ public class PaletteBuilder { app.setSaveNeeded(); } - var specEditor:ProcedureSpecEditor = new ProcedureSpecEditor('', [], false, ' ', false); + var specEditor:ProcedureSpecEditor = new ProcedureSpecEditor('', [], false); var d:DialogBox = new DialogBox(addBlockHat); d.addTitle('New Block'); d.addWidget(specEditor); diff --git a/src/scratch/ScratchRuntime.as b/src/scratch/ScratchRuntime.as index 9874c68f5..6d914f136 100644 --- a/src/scratch/ScratchRuntime.as +++ b/src/scratch/ScratchRuntime.as @@ -660,8 +660,8 @@ public class ScratchRuntime { if (!hat.isHat || !hat.nextBlock) return; // skip disconnected hats if ('whenSensorGreaterThan' == hat.op) { - var sensorName:String = (hat.args[0] as BlockArg).argValue; - var threshold:Number = Number((hat.args[1] as BlockArg).argValue) || 0; + var sensorName:String = interp.arg(hat, 0); + var threshold:Number = interp.numarg(hat, 1); if (('loudness' == sensorName && soundLevel() > threshold) || ('timer' == sensorName && timer() > threshold) || ('video motion' == sensorName && target.visible && VideoMotionPrims.readMotionSensor('motion', target) > threshold)) { @@ -672,7 +672,7 @@ public class ScratchRuntime { activeHats.push(hat); } } else if ('whenSensorConnected' == hat.op) { - if (getBooleanSensor((hat.args[0] as BlockArg).argValue)) { + if (getBooleanSensor(interp.arg(hat, 0))) { if (triggeredHats.indexOf(hat) == -1) { // not already trigged // only start the stack if it is not already running if (!interp.isRunning(hat, target)) interp.toggleThread(hat, target); @@ -687,7 +687,7 @@ public class ScratchRuntime { var numArgs:uint = hat.args.length; var finalArgs:Array = new Array(numArgs); for (var i:uint = 0; i < numArgs; ++i) - finalArgs[i] = (hat.args[i] as BlockArg).argValue; + finalArgs[i] = interp.arg(hat, i); processExtensionReporter(hat, target, extName, op, finalArgs); } @@ -752,7 +752,7 @@ public class ScratchRuntime { var op:String = b.op; if (op == Specs.GET_PARAM) b.parameterIndex = -1; // need to invalidate index cache if (('senseVideoMotion' == op) || - (('whenSensorGreaterThan' == op) && ('video motion' == (b.args[0] as BlockArg).argValue))) { + (('whenSensorGreaterThan' == op) && ('video motion' == interp.arg(b, 0)))) { app.libraryPart.showVideoButton(); } diff --git a/src/ui/ProcedureSpecEditor.as b/src/ui/ProcedureSpecEditor.as index 79f486295..477e85120 100644 --- a/src/ui/ProcedureSpecEditor.as +++ b/src/ui/ProcedureSpecEditor.as @@ -30,17 +30,12 @@ package ui { public class ProcedureSpecEditor extends Sprite { - private var isEdit:Boolean; private var base:Shape; - private var shape:int; private var blockShape:BlockShape; private var row:Array = []; private var moreLabel:TextField; private var moreButton:IconButton; - private var shapeLabels:Array = []; - private var shapeIcons:Array = []; - private var shapeButtons:Array = []; private var buttonLabels:Array = []; private var buttons:Array = []; @@ -53,14 +48,11 @@ public class ProcedureSpecEditor extends Sprite { private const labelColor:int = 0x8738bf; // 0x6c36b3; // 0x9c35b3; private const selectedLabelColor:int = 0xefa6ff; - public function ProcedureSpecEditor(originalSpec:String, inputNames:Array, warpFlag:Boolean, type:String, isEdit:Boolean) { - this.isEdit = isEdit; - + public function ProcedureSpecEditor(originalSpec:String, inputNames:Array, warpFlag:Boolean) { addChild(base = new Shape()); setWidthHeight(350, 10); - shape = type == "b" ? BlockShape.BooleanShape : type == "r" ? BlockShape.NumberShape : BlockShape.CmdShape; - blockShape = new BlockShape(shape, Specs.procedureColor); + blockShape = new BlockShape(BlockShape.CmdShape, Specs.procedureColor); blockShape.setWidthAndTopHeight(100, 25, true); addChild(blockShape); @@ -92,9 +84,7 @@ public class ProcedureSpecEditor extends Sprite { 'Add string input:', 'Add boolean input:', 'Add label text:', - "Doesn't report", - 'Reports number or text', - 'Reports true or false', + 'text', ]; } @@ -121,7 +111,7 @@ public class ProcedureSpecEditor extends Sprite { clearRow(); var i:int = 0; for each (var s:String in ReadStream.tokenize(spec)) { - if ((s.length >= 2) && (s.charAt(0) == '%')) { // argument spec + if (s.length >= 2 && s.charAt(0) == '%') { // argument spec var argSpec:String = s.charAt(1); var arg:BlockArg = null; if (argSpec == 'b') arg = makeBooleanArg(); @@ -133,9 +123,11 @@ public class ProcedureSpecEditor extends Sprite { } } else { if ((row.length > 0) && (row[row.length - 1] is TextField)) { - TextField(row[row.length - 1]).appendText(' ' + s); + var tf:TextField = row[row.length - 1]; + tf.appendText(' ' + ReadStream.unescape(s)); + fixLabelWidth(tf); } else { - addElement(makeTextField(s)); + addElement(makeTextField(ReadStream.unescape(s))); } } } @@ -146,7 +138,7 @@ public class ProcedureSpecEditor extends Sprite { public function spec():String { var result:String = ''; for each (var o:* in row) { - if (o is TextField) result += TextField(o).text; + if (o is TextField) result += ReadStream.escape(TextField(o).text); if (o is BlockArg) result += '%' + BlockArg(o).type; if ((result.length > 0) && (result.charAt(result.length - 1) != ' ')) result += ' '; } @@ -154,10 +146,6 @@ public class ProcedureSpecEditor extends Sprite { return result; } - public function type():String { - return shape == BlockShape.BooleanShape ? "b" : shape == BlockShape.NumberShape ? "r" : " "; - } - public function defaultArgValues():Array { var result:Array = []; for each (var el:* in row) { @@ -181,22 +169,12 @@ public class ProcedureSpecEditor extends Sprite { public function inputNames():Array { var result:Array = []; for each (var o:* in row) { - if (o is BlockArg) result.push(BlockArg(o).field.text); + if (o is BlockArg) result.push(uniqueName(result, BlockArg(o).field.text)); } return result; } private function addButtonsAndLabels():void { - shapeLabels = [ - makeLabel("Doesn't report", 14), - makeLabel('Reports number or text', 14), - makeLabel('Reports true or false', 14), - ]; - shapeButtons = [ - new IconButton(function():void { setShape(BlockShape.CmdShape) }, null), - new IconButton(function():void { setShape(BlockShape.NumberShape) }, null), - new IconButton(function():void { setShape(BlockShape.BooleanShape) }, null) - ]; buttonLabels = [ makeLabel('Add number input:', 14), makeLabel('Add string input:', 14), @@ -207,26 +185,10 @@ public class ProcedureSpecEditor extends Sprite { new Button('', function():void { appendObj(makeNumberArg()) }), new Button('', function():void { appendObj(makeStringArg()) }), new Button('', function():void { appendObj(makeBooleanArg()) }), - new Button('text', function():void { appendObj(makeTextField('')) }) + new Button(Translator.map('text'), function():void { appendObj(makeTextField('')) }) ]; - shapeButtons[0].setOn(true); - const lightGray:int = 0xA0A0A0; - var icon:BlockShape; - - shapeIcons = []; - icon = new BlockShape(BlockShape.CmdShape, Specs.procedureColor); - icon.setWidthAndTopHeight(34, 18, true); - shapeIcons.push(icon); - - icon = new BlockShape(BlockShape.NumberShape, Specs.procedureColor); - icon.setWidthAndTopHeight(34, 18, true); - shapeIcons.push(icon); - - icon = new BlockShape(BlockShape.BooleanShape, Specs.procedureColor); - icon.setWidthAndTopHeight(34, 18, true); - shapeIcons.push(icon); icon = new BlockShape(BlockShape.NumberShape, lightGray); icon.setWidthAndTopHeight(25, 14, true); @@ -236,9 +198,12 @@ public class ProcedureSpecEditor extends Sprite { icon.setWidthAndTopHeight(22, 14, true); buttons[1].setIcon(icon); - icon = new BlockShape(BlockShape.BooleanShape, lightGray); + var icon:BlockShape = new BlockShape(BlockShape.BooleanShape, lightGray); icon.setWidthAndTopHeight(25, 14, true); buttons[2].setIcon(icon); + + for each (var label:TextField in buttonLabels) addChild(label); + for each (var b:Button in buttons) addChild(b); } private function addwarpCheckbox():void { @@ -259,7 +224,7 @@ public class ProcedureSpecEditor extends Sprite { private function toggleButtons(ignore:*):void { var buttonsShowing:Boolean = buttons[0].parent != null; - showButtons(!buttonsShowing); + showButtons(!buttonsShowing) } private function deleteItem(ignore:*):void { @@ -276,21 +241,15 @@ public class ProcedureSpecEditor extends Sprite { } private function showButtons(showParams:Boolean):void { - var label:TextField, b:Button, ib:IconButton, shape:BlockShape; + var label:TextField, b:Button; if (showParams) { for each (label in buttonLabels) addChild(label); - if (!isEdit) for each (label in shapeLabels) addChild(label); for each (b in buttons) addChild(b); - if (!isEdit) for each (ib in shapeButtons) addChild(ib); - if (!isEdit) for each (shape in shapeIcons) addChild(shape); addChild(warpCheckbox); addChild(warpLabel); } else { for each (label in buttonLabels) if (label.parent) removeChild(label); - for each (label in shapeLabels) if (label.parent) removeChild(label); for each (b in buttons) if (b.parent) removeChild(b); - for each (ib in shapeButtons) if (b.parent) removeChild(b); - for each (shape in shapeIcons) if (shape.parent) removeChild(shape); if (warpCheckbox.parent) removeChild(warpCheckbox); if (warpLabel.parent) removeChild(warpLabel); } @@ -302,19 +261,6 @@ public class ProcedureSpecEditor extends Sprite { if (parent is DialogBox) DialogBox(parent).fixLayout(); } - private function setShape(shape:int):void { - this.shape = shape; - var ob:IconButton = shapeButtons[shape == BlockShape.BooleanShape ? 2 : shape == BlockShape.NumberShape ? 1 : 0]; - for each (var ib:IconButton in shapeButtons) { - ib.setOn(ib == ob); - } - var k:int = getChildIndex(blockShape); - removeChildAt(k); - blockShape = new BlockShape(shape, Specs.procedureColor); - addChildAt(blockShape, k); - fixLayout(); - } - private function makeBooleanArg():BlockArg { var result:BlockArg = new BlockArg('b', 0xFFFFFF, true); result.setArgValue(unusedArgName('boolean')); @@ -349,10 +295,9 @@ public class ProcedureSpecEditor extends Sprite { addChild(o); if (stage) { if (o is TextField) stage.focus = TextField(o); - if (o is BlockArg) stage.focus = BlockArg(o).field; + if (o is BlockArg) BlockArg(o).startEditing(); } fixLayout(); - if (parent is DialogBox) DialogBox(parent).fixLayout(); } private function makeTextField(contents:String):TextField { @@ -361,7 +306,7 @@ public class ProcedureSpecEditor extends Sprite { result.backgroundColor = labelColor; result.background = true; result.type = TextFieldType.INPUT; - result.defaultTextFormat = new TextFormat(CSS.font, 12, 0xFFFFFF); + result.defaultTextFormat = Block.blockLabelFormat; if (contents.length > 0) { result.width = 1000; result.text = contents; @@ -384,11 +329,11 @@ public class ProcedureSpecEditor extends Sprite { row = newRow; } - private function fixLayout():void { + private function fixLayout(updateDelete:Boolean = true):void { removeDeletedElementsFromRow(); blockShape.x = 10; blockShape.y = 10; - var nextX:int = blockShape.x + (shape == BlockShape.BooleanShape ? 14 : 6); + var nextX:int = blockShape.x + 6; var nextY:int = blockShape.y + 5; var maxH:int = 0; for each (var o:DisplayObject in row) maxH = Math.max(maxH, o.height); @@ -398,43 +343,39 @@ public class ProcedureSpecEditor extends Sprite { nextX += o.width + 4; if ((o is BlockArg) && (BlockArg(o).type == 's')) nextX -= 2; } - var blockW:int = Math.max(40, nextX + (shape == BlockShape.BooleanShape ? 12 : 4) - blockShape.x); + var blockW:int = Math.max(40, nextX + 4 - blockShape.x); blockShape.setWidthAndTopHeight(blockW, maxH + 11, true); moreButton.x = 0; - moreButton.y = blockShape.y + blockShape.height + (shape == BlockShape.CmdShape ? 12 : 15); + moreButton.y = blockShape.y + blockShape.height + 12; moreLabel.x = 10; moreLabel.y = moreButton.y - 4; - var rowY:int = blockShape.y + blockShape.height + (shape == BlockShape.CmdShape ? 30 : 33); + var labelX:int = blockShape.x + 45; + var buttonX:int = 240; + for each (var l:TextField in buttonLabels) { + buttonX = Math.max(buttonX, labelX + l.textWidth + 10); + } + + var rowY:int = blockShape.y + blockShape.height + 30; for (var i:int = 0; i < buttons.length; i++) { - buttonLabels[i].x = blockShape.x + 45; + var label:TextField = buttonLabels[i]; + buttonLabels[i].x = labelX; buttonLabels[i].y = rowY; - buttons[i].x = 240; + buttons[i].x = buttonX; buttons[i].y = rowY - 4; rowY += 30; } - if (!isEdit) { - for (i = 0; i < shapeButtons.length; i++) { - shapeButtons[i].x = blockShape.x + 46; - shapeButtons[i].y = rowY + 4; - shapeIcons[i].x = shapeButtons[i].x + shapeButtons[i].width + 8; - shapeIcons[i].y = rowY; - shapeLabels[i].x = shapeIcons[i].x + shapeIcons[i].width + 8; - shapeLabels[i].y = rowY; - rowY += 30; - } - } - warpCheckbox.x = blockShape.x + 46; warpCheckbox.y = rowY + 4; warpLabel.x = warpCheckbox.x + 18; warpLabel.y = warpCheckbox.y - 3; - updateDeleteButton(); + if (updateDelete) updateDeleteButton(); + if (parent is DialogBox) DialogBox(parent).fixLayout(); } /* Editing Parameter Names */ @@ -483,10 +424,24 @@ public class ProcedureSpecEditor extends Sprite { private function setFocus(o:DisplayObject):void { if (!stage) return; if (o is TextField) stage.focus = TextField(o); - if (o is BlockArg) stage.focus = BlockArg(o).field; + if (o is BlockArg) BlockArg(o).startEditing(); + } + + private function uniqueName(taken:Array, name:String):String { + if (taken.indexOf(name) == -1) return name; + var e:Array = /\d+$/.exec(name); + var n:String = e ? e[0] : ""; + var base:String = name.slice(0, name.length - n.length); + var i:int = int(n || "1") + 1; + while (taken.indexOf(base + i) != -1) { + i++; + } + return base + i; } private function focusChange(evt:FocusEvent):void { + var params:Array = []; + var change:Boolean = false; // Update label fields to show focus. for each (var o:DisplayObject in row) { if (o is TextField) { @@ -494,9 +449,17 @@ public class ProcedureSpecEditor extends Sprite { var hasFocus:Boolean = (stage != null) && (tf == stage.focus); tf.textColor = hasFocus ? 0 : 0xFFFFFF; tf.backgroundColor = hasFocus ? selectedLabelColor : labelColor; + } else if (o is BlockArg) { + tf = BlockArg(o).field; + if (params.indexOf(tf.text) != -1) { + BlockArg(o).setArgValue(uniqueName(params, tf.text)); + change = true; + } + params.push(tf.text); } } - if (evt.type == FocusEvent.FOCUS_IN) updateDeleteButton(); + if (change) fixLayout(false); + else if (evt.type == FocusEvent.FOCUS_IN) updateDeleteButton(); } private function updateDeleteButton():void { @@ -522,4 +485,4 @@ public class ProcedureSpecEditor extends Sprite { deleteButton.y = -6; } -}} \ No newline at end of file +}} From 3c49c89a9e183e9b59c84e566145b53e505d1392 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Sat, 11 Jun 2016 11:33:05 +1000 Subject: [PATCH 064/141] Revert "Revert "Fully Implement Custom Reporters"" --- src/Specs.as | 5 + src/blocks/Block.as | 46 +--- src/blocks/BlockIO.as | 13 +- src/blocks/BlockShape.as | 22 +- src/extensions/ExtensionManager.as | 65 +++-- src/interpreter/Interpreter.as | 380 ++++++++++++++++------------ src/interpreter/Thread.as | 47 ++-- src/primitives/ListPrims.as | 51 ++-- src/primitives/LooksPrims.as | 101 ++++---- src/primitives/MotionAndPenPrims.as | 102 ++++---- src/primitives/Primitives.as | 103 ++++---- src/primitives/SensingPrims.as | 69 ++--- src/primitives/SoundPrims.as | 208 +++++++-------- src/primitives/VideoMotionPrims.as | 12 +- src/scratch/BlockMenus.as | 3 +- src/scratch/PaletteBuilder.as | 13 +- src/scratch/ScratchRuntime.as | 10 +- src/ui/ProcedureSpecEditor.as | 157 +++++++----- 18 files changed, 727 insertions(+), 680 deletions(-) diff --git a/src/Specs.as b/src/Specs.as index 059127699..a454b2485 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -36,6 +36,8 @@ public class Specs { public static const CHANGE_VAR:String = "changeVar:by:"; public static const GET_LIST:String = "contentsOfList:"; public static const CALL:String = "call"; + public static const CALL_BOOLEAN:String = "callb"; + public static const CALL_NUMBER:String = "callr"; public static const PROCEDURE_DEF:String = "procDef"; public static const GET_PARAM:String = "getParam"; @@ -403,6 +405,9 @@ public class Specs { ["show list %m.list", " ", 12, "showList:"], ["hide list %m.list", " ", 12, "hideList:"], + // custom blocks + ["report %s", "f", 10, "report", ""], + // Sharp // --HTTP-- ["%m.httpMethod %s", " ", 13, "httpBlock:", "GET", "https://api.scratch.mit.edu"], diff --git a/src/blocks/Block.as b/src/blocks/Block.as index 2ef4f7d85..03a31f5c5 100644 --- a/src/blocks/Block.as +++ b/src/blocks/Block.as @@ -64,21 +64,18 @@ public class Block extends Sprite { private static var useEmbeddedFont:Boolean = false; public static var MenuHandlerFunction:Function; // optional function to handle block and blockArg menus - - public var isCustomReporter:Boolean = false; - public var isCustomBoolean:Boolean = false; - - public var isReturnBlock:Boolean = false; public var spec:String; public var type:String; public var op:String = ""; public var opFunction:Function; + public var isSpecialOp:Boolean = false; public var args:Array = []; public var defaultArgValues:Array = []; public var parameterIndex:int = -1; // cache of parameter index, used by GET_PARAM block public var parameterNames:Array; // used by procedure definition hats; null for other blocks public var warpProcFlag:Boolean; // used by procedure definition hats to indicate warp speed + public var procedureType:String; // used by procedure definition hats; " ", "r", or "b" public var rightToLeft:Boolean; public var isHat:Boolean = false; @@ -120,7 +117,6 @@ public class Block extends Sprite { this.spec = Translator.map(spec); this.type = type; this.op = op; - if(op == "call" && type == "r" || type == "b") isReturnBlock = true; if ((Specs.CALL == op) || (Specs.GET_LIST == op) || @@ -137,14 +133,14 @@ public class Block extends Sprite { if ((type == " ") || (type == "") || (type == "w")) { base = new BlockShape(BlockShape.CmdShape, color); indentTop = 3; - } else if (type == "b") { - base = new BlockShape(BlockShape.BooleanShape, color); + } else if (type == "b" || type == "ob") { + base = new BlockShape(type == "ob" ? BlockShape.BooleanOutlineShape : BlockShape.BooleanShape, color); isReporter = true; indentLeft = 9; indentRight = 7; - } else if (type == "r" || type == "R") { + } else if (type == "r" || type == "R" || type == "or") { this.type = 'r'; - base = new BlockShape(BlockShape.NumberShape, color); + base = new BlockShape(type == "or" ? BlockShape.NumberOutlineShape : BlockShape.NumberShape, color); isReporter = true; forceAsync = (type == 'r') && Scratch.app.extensionManager.shouldForceAsync(op); isRequester = (type == 'R') || forceAsync; @@ -171,7 +167,7 @@ public class Block extends Sprite { base = new BlockShape(BlockShape.FinalCmdShape, color); isTerminal = true; indentTop = 5; - } else if (type == "o") { // cmd outline for proc definition + } else if (type == "o" || type == "o ") { // cmd outline for proc definition base = new BlockShape(BlockShape.CmdOutlineShape, color); base.filters = []; // no bezel indentTop = 3; @@ -187,25 +183,6 @@ public class Block extends Sprite { addEventListener(FocusEvent.KEY_FOCUS_CHANGE, focusChange); } - public static const CUSTOM_COMMAND:Number = 0; - public static const CUSTOM_REPORTER:Number = 1; - public static const CUSTOM_BOOLEAN:Number = 2; - - public function setCustomBlockType(bType:Number = CUSTOM_COMMAND):void{ - if(bType == CUSTOM_COMMAND){ - isCustomBoolean = false; - isCustomReporter = false; - }else if(bType == CUSTOM_REPORTER){ - isCustomBoolean = false; - isCustomReporter = true; - }else if(bType == CUSTOM_BOOLEAN){ - isCustomBoolean = true; - isCustomReporter = false; - }else{ - setCustomBlockType(CUSTOM_COMMAND); - } - } - public function setSpec(newSpec:String, defaultArgs:Array = null):void { for each (var o:DisplayObject in labelsAndArgs) { if (o.parent != null) o.parent.removeChild(o); @@ -305,7 +282,7 @@ public class Block extends Sprite { // Create a block representing a procedure declaration to be embedded in a // procedure definition header block. For each formal parameter, embed a // reporter for that parameter. - var b:Block = new Block(spec, "o", Specs.procedureColor, 'proc_declaration'); + var b:Block = new Block(spec, "o" + procedureType, Specs.procedureColor, 'proc_declaration'); if (!parameterNames) parameterNames = []; for (var i:int = 0; i < parameterNames.length; i++) { var argType:String = (typeof(defaultArgValues[i]) == 'boolean') ? 'b' : 'r'; @@ -512,7 +489,7 @@ public class Block extends Sprite { for (i = 0; i < labelsAndArgs.length; i++) { item = labelsAndArgs[i]; // Next line moves the argument of if and if-else blocks right slightly: - if ((i == 1) && !(argTypes[i] == 'label')) x = Math.max(x, 30); + if (!isReporter && i == 1 && !(argTypes[i] == 'label')) x = Math.max(x, 30); item.x = x; maxH = Math.max(maxH, item.height); x += item.width + 2; @@ -526,7 +503,7 @@ public class Block extends Sprite { if ((item is BlockArg) && (!BlockArg(item).numberType)) item.y += 1; } - if ([' ', '', 'o'].indexOf(type) >= 0) x = Math.max(x, minCommandWidth); // minimum width for command blocks + if ([' ', '', 'o ', 'o'].indexOf(type) >= 0) x = Math.max(x, minCommandWidth); // minimum width for command blocks if (['c', 'cf', 'e'].indexOf(type) >= 0) x = Math.max(x, minLoopWidth); // minimum width for C and E blocks if (['h'].indexOf(type) >= 0) x = Math.max(x, minHatWidth); // minimum width for hat blocks if (elseLabel) x = Math.max(x, indentLeft + elseLabel.width + 2); @@ -599,12 +576,13 @@ public class Block extends Sprite { public function duplicate(forClone:Boolean, forStage:Boolean = false):Block { var newSpec:String = spec; if (op == 'whenClicked') newSpec = forStage ? 'when Stage clicked' : 'when this sprite clicked'; - var dup:Block = new Block(newSpec, type, (int)(forClone ? -1 : base.color), op); + var dup:Block = new Block(newSpec, procedureType ? procedureType : type, (int)(forClone ? -1 : base.color), op); dup.isRequester = isRequester; dup.forceAsync = forceAsync; dup.parameterNames = parameterNames; dup.defaultArgValues = defaultArgValues; dup.warpProcFlag = warpProcFlag; + dup.procedureType = procedureType; if (forClone) { dup.copyArgsForClone(args); } else { diff --git a/src/blocks/BlockIO.as b/src/blocks/BlockIO.as index e79fe029f..d80848292 100644 --- a/src/blocks/BlockIO.as +++ b/src/blocks/BlockIO.as @@ -70,8 +70,12 @@ public class BlockIO { if (b.op == Specs.GET_LIST) return [Specs.GET_LIST, b.spec]; // list reporter if (b.op == Specs.GET_PARAM) return [Specs.GET_PARAM, b.spec, b.type]; // parameter reporter if (b.op == Specs.PROCEDURE_DEF) // procedure definition - return [Specs.PROCEDURE_DEF, b.spec, b.parameterNames, b.defaultArgValues, b.warpProcFlag]; - if (b.op == Specs.CALL) result = [Specs.CALL, b.spec]; // procedure call - arguments follow spec + return [Specs.PROCEDURE_DEF, b.spec, b.parameterNames, b.defaultArgValues, b.warpProcFlag, b.procedureType]; + if (b.op == Specs.CALL) { + // procedure call - arguments follow spec + // because procedures used to only be commands, they didn't store their type in the array format; to maintain backwards compatibility, we store the type by splitting Specs.CALL into separate selectors for each type + result = [b.type == 'b' ? Specs.CALL_BOOLEAN : b.type == 'r' ? Specs.CALL_NUMBER : Specs.CALL, b.spec]; + } for each (var a:* in b.normalizedArgs()) { // Note: arguments are always saved in normalized (i.e. left-to-right) order if (a is Block) result.push(blockToArray(a)); @@ -101,8 +105,8 @@ public class BlockIO { b = convertOldCmd(cmd); if (b) { b.fixArgLayout(); return b } - if (cmd[0] == Specs.CALL) { - b = new Block(cmd[1], '', Specs.procedureColor, Specs.CALL); + if (cmd[0] == Specs.CALL || cmd[0] == Specs.CALL_BOOLEAN || cmd[0] == Specs.CALL_NUMBER) { + b = new Block(cmd[1], cmd[0] == Specs.CALL_BOOLEAN ? 'b' : cmd[0] == Specs.CALL_NUMBER ? 'r' : '', Specs.procedureColor, Specs.CALL); cmd.splice(0, 1); } else { var spec:Array = specForCmd(cmd, undefinedBlockType); @@ -191,6 +195,7 @@ public class BlockIO { b.parameterNames = cmd[2]; b.defaultArgValues = cmd[3]; if (cmd.length > 4) b.warpProcFlag = cmd[4]; + if (cmd.length > 5) b.procedureType = cmd[5]; b.setSpec(cmd[1]); b.fixArgLayout(); return b; diff --git a/src/blocks/BlockShape.as b/src/blocks/BlockShape.as index 0aa3cd98a..d44a4019d 100644 --- a/src/blocks/BlockShape.as +++ b/src/blocks/BlockShape.as @@ -42,6 +42,8 @@ public class BlockShape extends Shape { public static const FinalLoopShape:int = 10; // E-shaped blocks public static const IfElseShape:int = 11; + public static const BooleanOutlineShape:int = 12; + public static const NumberOutlineShape:int = 13; // Geometry public static const NotchDepth:int = 3; @@ -187,6 +189,8 @@ public class BlockShape extends Shape { case CmdShape: case FinalCmdShape: drawFunction = drawCmdShape; break; case CmdOutlineShape: drawFunction = drawCmdOutlineShape; break; + case BooleanOutlineShape: drawFunction = drawBooleanOutlineShape; break; + case NumberOutlineShape: drawFunction = drawNumberOutlineShape; break; case LoopShape: case FinalLoopShape: drawFunction = drawLoopShape; break; case IfElseShape: drawFunction = drawIfElseShape; break; @@ -207,6 +211,13 @@ public class BlockShape extends Shape { g.lineTo(w - centerY, topH); } + private function drawBooleanOutlineShape(g:Graphics):void { + g.endFill(); + g.lineStyle(2, 0xFFFFFF, 0.2); + drawBooleanShape(g); + g.lineTo(topH / 2, topH); + } + private function drawNumberShape(g:Graphics):void { var centerY:int = topH / 2; g.moveTo(centerY, topH); @@ -217,6 +228,13 @@ public class BlockShape extends Shape { curve(w, centerY, w - centerY, topH); } + private function drawNumberOutlineShape(g:Graphics):void { + g.endFill(); + g.lineStyle(2, 0xFFFFFF, 0.2); + drawNumberShape(g); + g.lineTo(topH / 2, topH); + } + private function drawCmdShape(g:Graphics):void { drawTop(g); drawRightAndBottom(g, topH, (shape != FinalCmdShape)); @@ -335,7 +353,7 @@ public class BlockShape extends Shape { } private function curve(p1x:int, p1y:int, p2x:int, p2y:int, roundness:Number = 0.42):void { - // Compute the Bezier control point by following an orthogonal vector from the midpoint + // Compute the Bezier control point by following an orthogal vector from the midpoint // of the line between p1 and p2 scaled by roundness * dist(p1, p2). The default roundness // approximates a circular arc. Negative roundness gives a concave curve. @@ -346,4 +364,4 @@ public class BlockShape extends Shape { graphics.curveTo(cx, cy, p2x, p2y); } -}} +}} \ No newline at end of file diff --git a/src/extensions/ExtensionManager.as b/src/extensions/ExtensionManager.as index 5dfd07455..607400c81 100644 --- a/src/extensions/ExtensionManager.as +++ b/src/extensions/ExtensionManager.as @@ -391,18 +391,17 @@ public class ExtensionManager { // Execution //------------------------------ - public function primExtensionOp(b:Block):* { + public function primExtensionOp(args:Array):* { + var activeThread:Thread = app.interp.activeThread; + var b:Block = activeThread.block; var unpackedOp:Array = unpackExtensionAndOp(b.op); var extName:String = unpackedOp[0]; var ext:ScratchExtension = extensionDict[extName]; if (ext == null) return 0; // unknown extension var primOrVarName:String = unpackedOp[1]; - var args:Array = []; - for (var i:int = 0; i < b.args.length; i++) { - args.push(app.interp.arg(b, i)); - } var value:*; + if(b.isHat && b.isAsyncHat){ if(b.requestState == 0){ request(extName, primOrVarName, args, b); @@ -442,26 +441,22 @@ public class ExtensionManager { return; } else if (b.isReporter) { - if(b.isRequester) { - if(b.requestState == 2) { + if (b.isRequester) { + if (b.requestState == 2) { b.requestState = 0; - return b.response; - } - else if(b.requestState == 0) { + activeThread.popState(); + activeThread.values.push(b.response); + return; + } else if(b.requestState == 0) { request(extName, primOrVarName, args, b); } - - // Returns null if we just made a request or we're still waiting - return null; - } - else { + } else { var sensorName:String = primOrVarName; - if(ext.port > 0) { // we were checking ext.isInternal before, should we? + if (ext.port > 0) { // we were checking ext.isInternal before, should we? sensorName = encodeURIComponent(sensorName); for each (var a:* in args) sensorName += '/' + encodeURIComponent(a); // append menu args value = ext.stateVars[sensorName]; - } - else if(Scratch.app.jsEnabled) { + } else if(Scratch.app.jsEnabled) { // JavaScript if (Scratch.app.isOffline) { throw new IllegalOperationError("JS reporters must be requesters in Offline."); @@ -472,7 +467,9 @@ public class ExtensionManager { } if (value == undefined) value = 0; // default to zero if missing if ('b' == b.type) value = (ext.port>0 ? 'true' == value : true == value); // coerce value to a boolean - return value; + activeThread.popState(); + activeThread.values.push(value); + return } } else { if ('w' == b.type) { @@ -484,12 +481,13 @@ public class ExtensionManager { app.interp.doYield(); justStartedWait = true; - if(ext.port == 0) { + if (ext.port == 0) { activeThread.firstTime = false; - if(app.jsEnabled) + if (app.jsEnabled) { app.externalCall('ScratchExtensions.runAsync', null, ext.name, primOrVarName, args, id); - else + } else { ext.busy.pop(); + } return; } @@ -501,6 +499,10 @@ public class ExtensionManager { } else { activeThread.tmp = 0; activeThread.firstTime = true; + var block:Block = activeThread.block; + activeThread.popState(); + if (block.nextBlock) + activeThread.pushStateForBlock(block.nextBlock); } return; } @@ -514,22 +516,13 @@ public class ExtensionManager { if (ext == null) return; // unknown extension if (ext.port > 0) { var activeThread:Thread = app.interp.activeThread; - if(activeThread && op != 'reset_all') { - if(activeThread.firstTime) { - httpCall(ext, op, args); - activeThread.firstTime = false; - app.interp.doYield(); - } - else { - activeThread.firstTime = true; - } - } - else { httpCall(ext, op, args); - } + activeThread.firstTime = false; + app.interp.doYield(); } else { + if (op == 'reset_all') op = 'resetAll'; if (Scratch.app.jsEnabled) { - if (op == 'reset_all') { + if (op == 'resetAll') { app.externalCall('ScratchExtensions.stop', null, ext.name); } else { @@ -726,4 +719,4 @@ public class ExtensionManager { } return false; } -}} +}} \ No newline at end of file diff --git a/src/interpreter/Interpreter.as b/src/interpreter/Interpreter.as index 379214324..68823ac4b 100644 --- a/src/interpreter/Interpreter.as +++ b/src/interpreter/Interpreter.as @@ -80,6 +80,7 @@ public class Interpreter { private var app:Scratch; private var primTable:Dictionary; // maps opcodes to functions + private var specialTable:Dictionary; // blocks that require special op functions private var threads:Array = []; // all threads private var yield:Boolean; // set true to indicate that active thread should yield control private var startTime:int; // start time for stepThreads() @@ -95,6 +96,10 @@ public class Interpreter { protected var debugFunc:Function; + static private var yieldBlock:Block = new Block('', '', 0, 'yield'); + static private var returnBlock:Block = new Block('', '', 0, 'doReturn', [0]); + static private var report0Block:Block = new Block('%s', '', 0, 'report', [0]); + public function Interpreter(app:Scratch) { this.app = app; initPrims(); @@ -145,9 +150,9 @@ public class Interpreter { var reporter:Block = b; var interp:Interpreter = this; b = new Block("%s", "", -1); - b.opFunction = function(b:Block):void { + b.opFunction = function(b:Array):void { var p:Point = reporter.localToGlobal(new Point(0, 0)); - app.showBubble(String(interp.arg(b, 0)), p.x, p.y, reporter.getRect(app.stage).width); + app.showBubble(String(b[0]), p.x, p.y, reporter.getRect(app.stage).width); }; b.args[0] = reporter; } @@ -263,36 +268,21 @@ public class Interpreter { return; } } + yield = false; while (true) { if (activeThread == warpThread) currentMSecs = getTimer(); evalCmd(activeThread.block); - if (yield) { - if (activeThread == warpThread) { - if ((currentMSecs - startTime) > warpMSecs) return; - yield = false; - continue; - } else return; - } - - if (activeThread.block != null) - activeThread.block = activeThread.block.nextBlock; - - while (activeThread.block == null) { // end of block sequence - if (!activeThread.popState()) return; // end of script - if ((activeThread.block == warpBlock) && activeThread.firstTime) { // end of outer warp block - clearWarpBlock(); - activeThread.block = activeThread.block.nextBlock; - continue; - } - if (activeThread.isLoop) { - if (activeThread == warpThread) { - if ((currentMSecs - startTime) > warpMSecs) return; - } else return; - } else { - if (activeThread.block.op == Specs.CALL) activeThread.firstTime = true; // in case set false by call - activeThread.block = activeThread.block.nextBlock; + if (activeThread.block == null) { + //click on reporter shows value in log + if (activeThread.values.length) { + app.jsThrowError(activeThread.values[0]); } + return; + } + if (yield) { + if (activeThread != warpThread || currentMSecs - startTime > warpMSecs) return; + yield = false; } } } @@ -303,74 +293,75 @@ public class Interpreter { } /* Evaluation */ - public function evalCmd(b:Block):* { - if (!b) return 0; // arg() and friends can pass null if arg index is out of range + public function evalCmd(b:Block):void { + var op:String = b.op; if (b.opFunction == null) { - if (ExtensionManager.hasExtensionPrefix(op)) b.opFunction = app.extensionManager.primExtensionOp; - else b.opFunction = (primTable[op] == undefined) ? primNoop : primTable[op]; - } - - // TODO: Optimize this into a cached check if the args *could* block at all - if(b.args.length && checkBlockingArgs(b)) { - doYield(); - return null; + if (ExtensionManager.hasExtensionPrefix(op)) { + b.isSpecialOp = true; + b.opFunction = app.extensionManager.primExtensionOp; + } else if (specialTable[op]){ + b.isSpecialOp = true; + b.opFunction = specialTable[op]; + } + else { + b.opFunction = (primTable[op] == undefined) ? primNoop : primTable[op]; + } } // Debug code if(debugFunc != null) debugFunc(b); - - return b.opFunction(b); - } - // Returns true if the thread needs to yield while data is requested - public function checkBlockingArgs(b:Block):Boolean { - // Do any of the arguments request data? If so, start any requests and yield. - var shouldYield:Boolean = false; - var args:Array = b.args; - for(var i:uint=0; i 0) { activeThread.tmp--; // decrement count - startCmdList(b.subStack1, true); + startCmdList(block.subStack1, true); } else { + activeThread.popState(); activeThread.firstTime = true; + if (block.nextBlock) activeThread.pushStateForBlock(block.nextBlock); } } + - private function primCodeSection(b:Block):void{ - if (activeThread.firstTime) { - var repeatCount:Number = 1; // clip to range: 0 to 2^31-1 - activeThread.tmp = repeatCount; - activeThread.firstTime = false; - } - if (activeThread.tmp > 0) { - activeThread.tmp--; // decrement count - startCmdList(b.subStack1, true); - } else { - activeThread.firstTime = true; - } + private function primCodeSection(b:Array):void { + var block:Block = activeThread.block; + activeThread.popState(); + activeThread.firstTime = true; + if (block.nextBlock) activeThread.pushStateForBlock(block.nextBlock); + startCmdList(block.subStack1, false); } - private function primStop(b:Block):void { - var type:String = arg(b, 0); + private function primStop(b:Array):void { + var type:String = b[0]; if (type == 'all') { app.runtime.stopAll(); yield = true } - if (type == 'this script') primReturn(b); + if (type == 'this script') primReturn([0]); if (type == 'other scripts in sprite') stopThreadsFor(activeThread.target, true); if (type == 'other scripts in stage') stopThreadsFor(activeThread.target, true); } - private function primWait(b:Block):void { + private function primWait(b:Array):void { if (activeThread.firstTime) { - startTimer(numarg(b, 0)); + startTimer(numarg(b[0])); redraw(); } else checkTimer(); } @@ -650,47 +679,52 @@ public class Interpreter { // Procedure call/return - private function primCall(b:Block):* { + private function primCall(b:Array):void { // Call a procedure. Handle recursive calls and "warp" procedures. - // The activeThread.firstTime flag is used to mark the first call - // to a procedure running in warp mode. activeThread.firstTime is - // false for subsequent calls to warp mode procedures. + + var block:Block = activeThread.block; // Lookup the procedure and cache for future use var obj:ScratchObj = activeThread.target; - var spec:String = b.spec; + var insideLoop:* = null; + var spec:String = block.spec; var proc:Block = obj.procCache[spec]; if (!proc) { proc = obj.lookupProcedure(spec); obj.procCache[spec] = proc; } - if (!proc) return; + if (!proc) { + if (activeThread.block.type == 'o ') activeThread.values.push(0); + activeThread.popState(); + if (block.nextBlock) activeThread.pushStateForBlock(block.nextBlock); + return; + } if (warpThread) { - activeThread.firstTime = false; - if ((currentMSecs - startTime) > warpMSecs) yield = true; + if (currentMSecs - startTime > warpMSecs) yield = true; } else { if (proc.warpProcFlag) { // Start running in warp mode. - warpBlock = b; + warpBlock = block; warpThread = activeThread; - activeThread.firstTime = true; - } - else if (activeThread.isRecursiveCall(b, proc)) { + } else if (activeThread.isRecursiveCall(block, proc)) { yield = true; } } - var argCount:int = proc.parameterNames.length; - var argList:Array = []; - for (var i:int = 0; i < argCount; ++i) argList.push(arg(b, i)); - startCmdList(proc, false, argList); + activeThread.pushStateForBlock(report0Block); + activeThread.args = b; + startCmdList(proc); } - private function primReturn(b:Block):void { + private function primReturn(b:Array):void { // Return from the innermost procedure. If not in a procedure, stop the thread. - if (!activeThread.returnFromProcedure()) { + var call:Block = activeThread.returnFromProcedure(); + if (call) { + if (call.isReporter) { + activeThread.values.push(b[0]); + } + } else { activeThread.stop(); - yield = true; } } @@ -698,49 +732,59 @@ public class Interpreter { // Optimization: to avoid the cost of looking up the variable every time, // a reference to the Variable object is cached in the target object. - private function primVarGet(b:Block):* { - var target:ScratchObj = app.runtime.currentDoObj ? app.runtime.currentDoObj : activeThread.target; - - var v:Variable = target.varCache[b.spec]; + private function primVarGet(b:Array):void { + var block:Block = activeThread.block; + activeThread.popState(); + var v:Variable = activeThread.target.varCache[block.spec]; if (v == null) { - v = target.varCache[b.spec] = target.lookupOrCreateVar(b.spec); - if (v == null) return 0; + v = activeThread.target.varCache[block.spec] = activeThread.target.lookupOrCreateVar(block.spec); + if (v == null) { + activeThread.values.push(0); + return; + } } - // XXX: Do we need a get() for persistent variables here ? - return v.value; + activeThread.values.push(v.value); } - protected function primVarSet(b:Block):Variable { - var name:String = arg(b, 0); - var v:Variable = activeThread.target.varCache[name]; + protected function primVarSet(b:Array):Variable { + var v:Variable = activeThread.target.varCache[b[0]]; if (!v) { - v = activeThread.target.varCache[name] = activeThread.target.lookupOrCreateVar(name); + v = activeThread.target.varCache[b.spec] = activeThread.target.lookupOrCreateVar(b[0]); if (!v) return null; } var oldvalue:* = v.value; - v.value = arg(b, 1); + v.value = b[1]; return v; } - protected function primVarChange(b:Block):Variable { - var name:String = arg(b, 0); + protected function primVarChange(b:Array):Variable { + var name:String = b[0]; var v:Variable = activeThread.target.varCache[name]; if (!v) { v = activeThread.target.varCache[name] = activeThread.target.lookupOrCreateVar(name); if (!v) return null; } - v.value = Number(v.value) + numarg(b, 1); + v.value = Number(v.value) + b[1]; return v; } - private function primGetParam(b:Block):* { - if (b.parameterIndex < 0) { - var proc:Block = b.topBlock(); - if (proc.parameterNames) b.parameterIndex = proc.parameterNames.indexOf(b.spec); - if (b.parameterIndex < 0) return 0; + private function primGetParam(b:Array):* { + var block:Block = activeThread.block; + activeThread.popState(); + if (!block.isReporter) return; + if (block.parameterIndex < 0) { + var proc:Block = block.topBlock(); + if (proc.parameterNames) block.parameterIndex = proc.parameterNames.indexOf(block.spec); + if (block.parameterIndex < 0) { + activeThread.values.push(0); + return; + } + } + if (activeThread.args == null || block.parameterIndex >= activeThread.args.length) { + activeThread.values.push(0); + return; } - if ((activeThread.args == null) || (b.parameterIndex >= activeThread.args.length)) return 0; - return activeThread.args[b.parameterIndex]; + activeThread.values.push(activeThread.args[block.parameterIndex]); } }} diff --git a/src/interpreter/Thread.as b/src/interpreter/Thread.as index 8179c3a67..3aee1e321 100644 --- a/src/interpreter/Thread.as +++ b/src/interpreter/Thread.as @@ -36,13 +36,13 @@ public class Thread { // the following state is pushed and popped when running substacks public var block:Block; - public var isLoop:Boolean; public var firstTime:Boolean; // used by certain control structures public var tmp:int; // used by repeat and wait + public var values:Array; // the evaluated inputs public var args:Array; // arguments to a user-defined procedure // the stack - public var stack:Vector.; + private var stack:Vector.; private var sp:int; public function Thread(b:Block, targetObj:*, startupDelay:int = 0) { @@ -51,34 +51,35 @@ public class Thread { topBlock = b; startDelayCount = startupDelay; // initForBlock - block = b; - isLoop = false; + block = null; firstTime = true; tmp = 0; + values = []; + pushStateForBlock(b); } public function pushStateForBlock(b:Block):void { if (sp >= (stack.length - 1)) growStack(); var old:StackFrame = stack[sp++]; old.block = block; - old.isLoop = isLoop; old.firstTime = firstTime; old.tmp = tmp; + old.values = values; old.args = args; // initForBlock block = b; - isLoop = false; firstTime = true; tmp = 0; + values = []; } public function popState():Boolean { if (sp == 0) return false; var old:StackFrame = stack[--sp]; block = old.block; - isLoop = old.isLoop; firstTime = old.firstTime; tmp = old.tmp; + values = old.values; args = old.args; return true; } @@ -87,6 +88,7 @@ public class Thread { public function stop():void { block = null; + values = []; stack = new Vector.(4); stack[0] = new StackFrame(); stack[1] = new StackFrame(); @@ -99,7 +101,7 @@ public class Thread { var callCount:int = 5; // maximum number of enclosing procedure calls to examine for (var i:int = sp - 1; i >= 0; i--) { var b:Block = stack[i].block; - if (b.op == Specs.CALL) { + if (b && b.op == Specs.CALL) { if (procCall == b) return true; if (procHat == target.procCache[b.spec]) return true; } @@ -108,26 +110,33 @@ public class Thread { return false; } - public function returnFromProcedure():Boolean { + public function returnFromProcedure():Block { + if (block && block.op == Specs.CALL) { + var b:Block = block; + popState(); + if (b.nextBlock) pushStateForBlock(b.nextBlock); + return block; + } for (var i:int = sp - 1; i >= 0; i--) { - if (stack[i].block.op == Specs.CALL) { - sp = i + 1; // 'hack' the stack pointer, but don't do the final popState here - block = null; // make it do the final popState through the usual stepActiveThread mechanism - return true; + b = stack[i].block; + if (b && b.op == Specs.CALL) { + sp = i; + popState(); + if (b.nextBlock) pushStateForBlock(b.nextBlock); + return b; } } - return false; + return null; } private function initForBlock(b:Block):void { block = b; - isLoop = false; firstTime = true; tmp = 0; } private function growStack():void { - // The stack is an array of Thread instances, pre-allocated for efficiency. + // The stack is an array of StackFrame instances, pre-allocated for efficiency. // When growing, the current size is doubled. var s:int = stack.length; var n:int = s + s; @@ -142,9 +151,9 @@ import blocks.*; import interpreter.*; class StackFrame { - public var block:Block; - internal var isLoop:Boolean; + internal var block:Block; internal var firstTime:Boolean; internal var tmp:int; + internal var values:Array; internal var args:Array; -} +} \ No newline at end of file diff --git a/src/primitives/ListPrims.as b/src/primitives/ListPrims.as index 10a7675ab..20c68bde0 100644 --- a/src/primitives/ListPrims.as +++ b/src/primitives/ListPrims.as @@ -39,7 +39,7 @@ public class ListPrims { this.interp = interpreter; } - public function addPrimsTo(primTable:Dictionary):void { + public function addPrimsTo(primTable:Dictionary, specialTable:Dictionary):void { primTable[Specs.GET_LIST] = primContents; primTable['append:toList:'] = primAppend; primTable['deleteLine:ofList:'] = primDelete; @@ -50,7 +50,7 @@ public class ListPrims { primTable['list:contains:'] = primContains; } - private function primContents(b:Block):String { + private function primContents(b:Array):String { var list:ListWatcher = interp.targetObj().lookupOrCreateList(b.spec); if (!list) return ''; var allSingleLetters:Boolean = true; @@ -63,10 +63,10 @@ public class ListPrims { return (list.contents.join(allSingleLetters ? '' : ' ')); } - private function primAppend(b:Block):void { - var list:ListWatcher = listarg(b, 1); + private function primAppend(b:Array):void { + var list:ListWatcher = listarg(b[1]); if (!list) return; - listAppend(list, interp.arg(b, 0)); + listAppend(list, b[0]); if (list.visible) list.updateWatcher(list.contents.length, false, interp); } @@ -74,9 +74,9 @@ public class ListPrims { list.contents.push(item); } - private function primDelete(b:Block):void { - var which:* = interp.arg(b, 0); - var list:ListWatcher = listarg(b, 1); + private function primDelete(b:Array):void { + var which:* = b[0]; + var list:ListWatcher = listarg(b[1]); if (!list) return; var len:int = list.contents.length; if (which == 'all') { @@ -100,9 +100,9 @@ public class ListPrims { } private function primInsert(b:Block):void { - var val:* = interp.arg(b, 0); - var where:* = interp.arg(b, 1); - var list:ListWatcher = listarg(b, 2); + var val:* = b[0]; + var where:* = b[1]; + var list:ListWatcher = listarg(b[2]); if (!list) return; if (where == 'last') { listAppend(list, val); @@ -119,12 +119,12 @@ public class ListPrims { list.contents.splice(i - 1, 0, item); } - private function primReplace(b:Block):void { - var list:ListWatcher = listarg(b, 1); + private function primReplace(b:Array):void { + var list:ListWatcher = listarg(b[1]); if (!list) return; - var i:int = computeIndex(interp.arg(b, 0), list.contents.length); + var i:int = computeIndex(b[0], list.contents.length); if (i < 0) return; - listReplace(list, i, interp.arg(b, 2)); + listReplace(list, i, b[2]); if (list.visible) list.updateWatcher(i, false, interp); } @@ -132,25 +132,25 @@ public class ListPrims { list.contents[i - 1] = item; } - private function primGetItem(b:Block):* { - var list:ListWatcher = listarg(b, 1); + private function primGetItem(b:Array):* { + var list:ListWatcher = listarg(b[1]); if (!list) return ''; - var i:int = computeIndex(interp.arg(b, 0), list.contents.length); + var i:int = computeIndex(b[0], list.contents.length); if (i < 0) return ''; if (list.visible) list.updateWatcher(i, true, interp); return list.contents[i - 1]; } - private function primLength(b:Block):Number { - var list:ListWatcher = listarg(b, 0); + private function primLength(b:Array):Number { + var list:ListWatcher = listarg(b[0]); if (!list) return 0; return list.contents.length; } - private function primContains(b:Block):Boolean { - var list:ListWatcher = listarg(b, 0); + private function primContains(b:Array):Boolean { + var list:ListWatcher = listarg(b[0]); if (!list) return false; - var item:* = interp.arg(b, 1); + var item:* = b[1]; if (list.contents.indexOf(item) >= 0) return true; for each (var el:* in list.contents) { // use Scratch comparison operator (Scratch considers the string '123' equal to the number 123) @@ -159,8 +159,7 @@ public class ListPrims { return false; } - private function listarg(b:Block, i:int):ListWatcher { - var listName:String = interp.arg(b, i); + private function listarg(listName:String):ListWatcher { if (listName.length == 0) return null; var obj:ScratchObj = interp.targetObj(); var result:ListWatcher = obj.listCache[listName]; @@ -183,4 +182,4 @@ public class ListPrims { return i; } -}} +}} \ No newline at end of file diff --git a/src/primitives/LooksPrims.as b/src/primitives/LooksPrims.as index 75aadaf8f..d47471272 100644 --- a/src/primitives/LooksPrims.as +++ b/src/primitives/LooksPrims.as @@ -38,7 +38,7 @@ public class LooksPrims { this.interp = interpreter; } - public function addPrimsTo(primTable:Dictionary):void { + public function addPrimsTo(primTable:Dictionary, specialTable:Dictionary):void { primTable['lookLike:'] = primShowCostume; primTable['nextCostume'] = primNextCostume; primTable['costumeIndex'] = primCostumeIndex; @@ -49,12 +49,12 @@ public class LooksPrims { primTable['backgroundIndex'] = primSceneIndex; primTable['sceneName'] = primSceneName; primTable['nextScene'] = function(b:*):* { startScene('next backdrop', false) }; - primTable['startScene'] = function(b:*):* { startScene(interp.arg(b, 0), false) }; - primTable['startSceneAndWait'] = function(b:*):* { startScene(interp.arg(b, 0), true) }; + primTable['startScene'] = function(b:*):* { startScene(b[0], false) }; + primTable['startSceneAndWait'] = function(b:*):* { startScene(b[0], true) }; - primTable['say:duration:elapsed:from:'] = function(b:*):* { showBubbleAndWait(b, 'talk') }; + specialTable['say:duration:elapsed:from:'] = function(b:*):* { showBubbleAndWait(b, 'talk') }; primTable['say:'] = function(b:*):* { showBubble(b, 'talk') }; - primTable['think:duration:elapsed:from:'] = function(b:*):* { showBubbleAndWait(b, 'think') }; + specialTable['think:duration:elapsed:from:'] = function(b:*):* { showBubbleAndWait(b, 'think') }; primTable['think:'] = function(b:*):* { showBubble(b, 'think') }; primTable['changeGraphicEffect:by:'] = primChangeEffect; @@ -84,16 +84,16 @@ public class LooksPrims { primTable['setRotationStyle'] = primSetRotationStyle; } - private function primNextCostume(b:Block):void { + private function primNextCostume(b:Array):void { var s:ScratchObj = interp.targetObj(); if (s != null) s.showCostume(s.currentCostumeIndex + 1); if (s.visible) interp.redraw(); } - private function primShowCostume(b:Block):void { + private function primShowCostume(b:Array):void { var s:ScratchObj = interp.targetObj(); if (s == null) return; - var arg:* = interp.arg(b, 0); + var arg:* = b[0]; if (typeof(arg) == 'number') { s.showCostume(arg - 1); } else { @@ -113,21 +113,21 @@ public class LooksPrims { if (s.visible) interp.redraw(); } - private function primCostumeIndex(b:Block):Number { + private function primCostumeIndex(b:Array):Number { var s:ScratchObj = interp.targetObj(); return (s == null) ? 1 : s.costumeNumber(); } - private function primCostumeName(b:Block):String { + private function primCostumeName(b:Array):String { var s:ScratchObj = interp.targetObj(); return (s == null) ? '' : s.currentCostume().costumeName; } - private function primSceneIndex(b:Block):Number { + private function primSceneIndex(b:Array):Number { return app.stagePane.costumeNumber(); } - private function primSceneName(b:Block):String { + private function primSceneName(b:Array):String { return app.stagePane.currentCostume().costumeName; } @@ -149,14 +149,13 @@ public class LooksPrims { var costumes:Array = app.stagePane.costumes; return costumes[(i + costumes.length) % costumes.length].costumeName; } - - private function showBubbleAndWait(b:Block, type:String):void { + private function showBubbleAndWait(b:Array, type:String):void { var text:*, secs:Number; var s:ScratchSprite = interp.targetSprite(); if (s == null) return; if (interp.activeThread.firstTime) { - text = interp.arg(b, 0); - secs = interp.numarg(b, 1); + text = b[0]; + secs = interp.numarg(b[1]); s.showBubble(text, type, b); if (s.visible) interp.redraw(); interp.startTimer(secs); @@ -167,25 +166,25 @@ public class LooksPrims { } } - private function showBubble(b:Block, type:String = null):void { + private function showBubble(b:Array, type:String = null):void { var text:*, secs:Number; var s:ScratchSprite = interp.targetSprite(); if (s == null) return; if (type == null) { // combined talk/think/shout/whisper command - type = interp.arg(b, 0); - text = interp.arg(b, 1); + type = b[0]; + text = b[1]; } else { // talk or think command - text = interp.arg(b, 0); + text = b[0]; } s.showBubble(text, type, b); if (s.visible) interp.redraw(); } - private function primChangeEffect(b:Block):void { + private function primChangeEffect(b:Array):void { var s:ScratchObj = interp.targetObj(); if (s == null) return; - var filterName:String = interp.arg(b, 0); - var delta:Number = interp.numarg(b, 1); + var filterName:String = b[0]; + var delta:Number = interp.numarg(b[1]); if(delta == 0) return; var newValue:Number = s.filterPack.getFilterSetting(filterName) + delta; @@ -194,52 +193,52 @@ public class LooksPrims { if (s.visible || s == Scratch.app.stagePane) interp.redraw(); } - private function primSetEffect(b:Block):void { + private function primSetEffect(b:Array):void { var s:ScratchObj = interp.targetObj(); if (s == null) return; - var filterName:String = interp.arg(b, 0); - var newValue:Number = interp.numarg(b, 1); + var filterName:String = b[0]; + var newValue:Number = interp.numarg(b[1]); if(s.filterPack.setFilter(filterName, newValue)) s.applyFilters(); if (s.visible || s == Scratch.app.stagePane) interp.redraw(); } - private function primClearEffects(b:Block):void { + private function primClearEffects(b:Array):void { var s:ScratchObj = interp.targetObj(); s.clearFilters(); s.applyFilters(); if (s.visible || s == Scratch.app.stagePane) interp.redraw(); } - private function primChangeSize(b:Block):void { + private function primChangeSize(b:Array):void { var s:ScratchSprite = interp.targetSprite(); if (s == null) return; var oldScale:Number = s.scaleX; - s.setSize(s.getSize() + interp.numarg(b, 0)); + s.setSize(s.getSize() + interp.numarg(b[0])); if (s.visible && (s.scaleX != oldScale)) interp.redraw(); } - private function primSetRotationStyle(b:Block):void { + private function primSetRotationStyle(b:Array):void { var s:ScratchSprite = interp.targetSprite(); - var newStyle:String = interp.arg(b, 0) as String; + var newStyle:String = b[0] as String; if ((s == null) || (newStyle == null)) return; s.setRotationStyle(newStyle); } - private function primSetSize(b:Block):void { + private function primSetSize(b:Array):void { var s:ScratchSprite = interp.targetSprite(); if (s == null) return; - s.setSize(interp.numarg(b, 0)); + s.setSize(interp.numarg(b[0])); if (s.visible) interp.redraw(); } - private function primSize(b:Block):Number { + private function primSize(b:Array):Number { var s:ScratchSprite = interp.targetSprite(); if (s == null) return 100; return Math.round(s.getSize()); // reporter returns rounded size, as in Scratch 1.4 } - private function primShow(b:Block):void { + private function primShow(b:Array):void { var s:ScratchSprite = interp.targetSprite(); if (s == null) return; s.visible = true; @@ -248,7 +247,7 @@ public class LooksPrims { if (s.visible) interp.redraw(); } - private function primHide(b:Block):void { + private function primHide(b:Array):void { var s:ScratchSprite = interp.targetSprite(); if ((s == null) || !s.visible) return; s.visible = false; @@ -256,8 +255,8 @@ public class LooksPrims { s.updateBubble(); interp.redraw(); } - - private function primHideAll(b:Block):void { + + private function primHideAll(b:Array):void { // Hide all sprites and delete all clones. Only works from the stage. if (!interp.targetObj().isStage) return; app.stagePane.deleteClones(); @@ -271,17 +270,17 @@ public class LooksPrims { interp.redraw(); } - private function primGoFront(b:Block):void { + private function primGoFront(b:Array):void { var s:ScratchSprite = interp.targetSprite(); if ((s == null) || (s.parent == null)) return; s.parent.setChildIndex(s, s.parent.numChildren - 1); if (s.visible) interp.redraw(); } - private function primGoBack(b:Block):void { + private function primGoBack(b:Array):void { var s:ScratchSprite = interp.targetSprite(); if ((s == null) || (s.parent == null)) return; - var newIndex:int = s.parent.getChildIndex(s) - interp.numarg(b, 0); + var newIndex:int = s.parent.getChildIndex(s) - interp.numarg(b[0]); newIndex = Math.max(minSpriteLayer(), Math.min(newIndex, s.parent.numChildren - 1)); if (newIndex > 0 && newIndex < s.parent.numChildren) { @@ -296,27 +295,27 @@ public class LooksPrims { return stg.getChildIndex(stg.videoImage ? stg.videoImage : stg.penLayer) + 1; } - private function primSetVideoState(b:Block):void { - app.stagePane.setVideoState(interp.arg(b, 0)); + private function primSetVideoState(b:Array):void { + app.stagePane.setVideoState(b[0]); } - private function primSetVideoTransparency(b:Block):void { - app.stagePane.setVideoTransparency(interp.numarg(b, 0)); + private function primSetVideoTransparency(b:Array):void { + app.stagePane.setVideoTransparency(interp.numarg(b[0])); app.stagePane.setVideoState('on'); } - private function primScrollAlign(b:Block):void { + private function primScrollAlign(b:Array):void { if (!interp.targetObj().isStage) return; - app.stagePane.scrollAlign(interp.arg(b, 0)); + app.stagePane.scrollAlign(b[0]); } - private function primScrollRight(b:Block):void { + private function primScrollRight(b:Array):void { if (!interp.targetObj().isStage) return; - app.stagePane.scrollRight(interp.numarg(b, 0)); + app.stagePane.scrollRight(interp.numarg(b[0])); } - private function primScrollUp(b:Block):void { + private function primScrollUp(b:Array):void { if (!interp.targetObj().isStage) return; - app.stagePane.scrollUp(interp.numarg(b, 0)); + app.stagePane.scrollUp(interp.numarg(b[0])); } }} diff --git a/src/primitives/MotionAndPenPrims.as b/src/primitives/MotionAndPenPrims.as index f101ede15..26800036e 100644 --- a/src/primitives/MotionAndPenPrims.as +++ b/src/primitives/MotionAndPenPrims.as @@ -43,7 +43,7 @@ public class MotionAndPenPrims { this.interp = interpreter; } - public function addPrimsTo(primTable:Dictionary):void { + public function addPrimsTo(primTable:Dictionary, specialTable:Dictionary):void { primTable["forward:"] = primMove; primTable["turnRight:"] = primTurnRight; primTable["turnLeft:"] = primTurnLeft; @@ -51,7 +51,7 @@ public class MotionAndPenPrims { primTable["pointTowards:"] = primPointTowards; primTable["gotoX:y:"] = primGoTo; primTable["gotoSpriteOrMouse:"] = primGoToSpriteOrMouse; - primTable["glideSecs:toX:y:elapsed:from:"] = primGlide; + specialTable["glideSecs:toX:y:elapsed:from:"] = primGlide; primTable["changeXposBy:"] = primChangeX; primTable["xpos:"] = primSetX; @@ -77,41 +77,41 @@ public class MotionAndPenPrims { primTable["stampCostume"] = primStamp; } - private function primMove(b:Block):void { + private function primMove(b:Array):void { var s:ScratchSprite = interp.targetSprite(); if (s == null) return; var radians:Number = (Math.PI * (90 - s.direction)) / 180; - var d:Number = interp.numarg(b, 0); + var d:Number = interp.numarg(b[0]); moveSpriteTo(s, s.scratchX + (d * Math.cos(radians)), s.scratchY + (d * Math.sin(radians))); } - private function primTurnRight(b:Block):void { + private function primTurnRight(b:Array):void { var s:ScratchSprite = interp.targetSprite(); if (s != null) { - s.setDirection(s.direction + interp.numarg(b, 0)); + s.setDirection(s.direction + interp.numarg(b[0])); if (s.visible) interp.redraw(); } } - private function primTurnLeft(b:Block):void { + private function primTurnLeft(b:Array):void { var s:ScratchSprite = interp.targetSprite(); if (s != null) { - s.setDirection(s.direction - interp.numarg(b, 0)); + s.setDirection(s.direction - interp.numarg(b[0])); if (s.visible) interp.redraw(); } } - private function primSetDirection(b:Block):void { + private function primSetDirection(b:Array):void { var s:ScratchSprite = interp.targetSprite(); if (s != null) { - s.setDirection(interp.numarg(b, 0)); + s.setDirection(interp.numarg(b[0])); if (s.visible) interp.redraw(); } } - private function primPointTowards(b:Block):void { + private function primPointTowards(b:Array):void { var s:ScratchSprite = interp.targetSprite(); - var p:Point = mouseOrSpritePosition(interp.arg(b, 0)); + var p:Point = mouseOrSpritePosition(b[0]); if ((s == null) || (p == null)) return; var dx:Number = p.x - s.scratchX; var dy:Number = p.y - s.scratchY; @@ -120,25 +120,25 @@ public class MotionAndPenPrims { if (s.visible) interp.redraw(); } - private function primGoTo(b:Block):void { + private function primGoTo(b:Array):void { var s:ScratchSprite = interp.targetSprite(); - if (s != null) moveSpriteTo(s, interp.numarg(b, 0), interp.numarg(b, 1)); + if (s != null) moveSpriteTo(s, interp.numarg(b[0]), interp.numarg(b[1])); } - private function primGoToSpriteOrMouse(b:Block):void { + private function primGoToSpriteOrMouse(b:Array):void { var s:ScratchSprite = interp.targetSprite(); - var p:Point = mouseOrSpritePosition(interp.arg(b, 0)); + var p:Point = mouseOrSpritePosition(b[0]); if ((s == null) || (p == null)) return; moveSpriteTo(s, p.x, p.y); } - private function primGlide(b:Block):void { + private function primGlide(b:Array):void { var s:ScratchSprite = interp.targetSprite(); if (s == null) return; if (interp.activeThread.firstTime) { - var secs:Number = interp.numarg(b, 0); - var destX:Number = interp.numarg(b, 1); - var destY:Number = interp.numarg(b, 2); + var secs:Number = interp.numarg(b[0]); + var destX:Number = interp.numarg(b[1]); + var destY:Number = interp.numarg(b[2]); if (secs <= 0) { moveSpriteTo(s, destX, destY); return; @@ -179,27 +179,27 @@ public class MotionAndPenPrims { return null; } - private function primChangeX(b:Block):void { + private function primChangeX(b:Array):void { var s:ScratchSprite = interp.targetSprite(); - if (s != null) moveSpriteTo(s, s.scratchX + interp.numarg(b, 0), s.scratchY); + if (s != null) moveSpriteTo(s, s.scratchX + interp.numarg(b[0]), s.scratchY); } - private function primSetX(b:Block):void { + private function primSetX(b:Array):void { var s:ScratchSprite = interp.targetSprite(); - if (s != null) moveSpriteTo(s, interp.numarg(b, 0), s.scratchY); + if (s != null) moveSpriteTo(s, interp.numarg(b[0]), s.scratchY); } - private function primChangeY(b:Block):void { + private function primChangeY(b:Array):void { var s:ScratchSprite = interp.targetSprite(); - if (s != null) moveSpriteTo(s, s.scratchX, s.scratchY + interp.numarg(b, 0)); + if (s != null) moveSpriteTo(s, s.scratchX, s.scratchY + interp.numarg(b[0])); } - private function primSetY(b:Block):void { + private function primSetY(b:Array):void { var s:ScratchSprite = interp.targetSprite(); - if (s != null) moveSpriteTo(s, s.scratchX, interp.numarg(b, 0)); + if (s != null) moveSpriteTo(s, s.scratchX, interp.numarg(b[0])); } - private function primBounceOffEdge(b:Block):void { + private function primBounceOffEdge(b:Array):void { var s:ScratchSprite = interp.targetSprite(); if (s == null) return; if (!turnAwayFromEdge(s)) return; @@ -207,17 +207,17 @@ public class MotionAndPenPrims { if (s.visible) interp.redraw(); } - private function primXPosition(b:Block):Number { + private function primXPosition(b:Array):Number { var s:ScratchSprite = interp.targetSprite(); return (s != null) ? snapToInteger(s.scratchX) : 0; } - private function primYPosition(b:Block):Number { + private function primYPosition(b:Array):Number { var s:ScratchSprite = interp.targetSprite(); return (s != null) ? snapToInteger(s.scratchY) : 0; } - private function primDirection(b:Block):Number { + private function primDirection(b:Array):Number { var s:ScratchSprite = interp.targetSprite(); return (s != null) ? snapToInteger(s.direction) : 0; } @@ -229,12 +229,12 @@ public class MotionAndPenPrims { return (delta < 1e-9) ? rounded : n; } - private function primClear(b:Block):void { + private function primClear(b:Array):void { app.stagePane.clearPenStrokes(); interp.redraw(); } - private function primPenDown(b:Block):void { + private function primPenDown(b:Array):void { var s:ScratchSprite = interp.targetSprite(); if (s != null) s.penIsDown = true; touch(s, s.scratchX, s.scratchY); @@ -252,47 +252,47 @@ public class MotionAndPenPrims { app.stagePane.penActivity = true; } - private function primPenUp(b:Block):void { + private function primPenUp(b:Array):void { var s:ScratchSprite = interp.targetSprite(); if (s != null) s.penIsDown = false; } - private function primSetPenColor(b:Block):void { + private function primSetPenColor(b:Array):void { var s:ScratchSprite = interp.targetSprite(); - if (s != null) s.setPenColor(interp.numarg(b, 0)); + if (s != null) s.setPenColor(interp.numarg(b[0])); } - private function primSetPenHue(b:Block):void { + private function primSetPenHue(b:Array):void { var s:ScratchSprite = interp.targetSprite(); - if (s != null) s.setPenHue(interp.numarg(b, 0)); + if (s != null) s.setPenHue(interp.numarg(b[0])); } - private function primChangePenHue(b:Block):void { + private function primChangePenHue(b:Array):void { var s:ScratchSprite = interp.targetSprite(); - if (s != null) s.setPenHue(s.penHue + interp.numarg(b, 0)); + if (s != null) s.setPenHue(s.penHue + interp.numarg(b[0])); } - private function primSetPenShade(b:Block):void { + private function primSetPenShade(b:Array):void { var s:ScratchSprite = interp.targetSprite(); - if (s != null) s.setPenShade(interp.numarg(b, 0)); + if (s != null) s.setPenShade(interp.numarg(b[0])); } - private function primChangePenShade(b:Block):void { + private function primChangePenShade(b:Array):void { var s:ScratchSprite = interp.targetSprite(); - if (s != null) s.setPenShade(s.penShade + interp.numarg(b, 0)); + if (s != null) s.setPenShade(s.penShade + interp.numarg(b[0])); } - private function primSetPenSize(b:Block):void { + private function primSetPenSize(b:Array):void { var s:ScratchSprite = interp.targetSprite(); - if (s != null) s.setPenSize(Math.max(1, Math.min(960, Math.round(interp.numarg(b, 0))))); + if (s != null) s.setPenSize(Math.max(1, Math.min(960, Math.round(interp.numarg(b[0]))))); } - private function primChangePenSize(b:Block):void { + private function primChangePenSize(b:Array):void { var s:ScratchSprite = interp.targetSprite(); - if (s != null) s.setPenSize(s.penWidth + interp.numarg(b, 0)); + if (s != null) s.setPenSize(s.penWidth + interp.numarg(b[0])); } - - private function primStamp(b:Block):void { + + private function primStamp(b:Array):void { var s:ScratchSprite = interp.targetSprite(); // In 3D mode, get the alpha from the ghost filter // Otherwise, it can be easily accessed from the color transform. diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index d085b25b3..b625fda6d 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -48,31 +48,31 @@ public class Primitives { this.interp = interpreter; } - public function addPrimsTo(primTable:Dictionary):void { + public function addPrimsTo(primTable:Dictionary, specialTable:Dictionary):void { // operators - primTable["+"] = function(b:*):* { return interp.numarg(b, 0) + interp.numarg(b, 1) }; - primTable["-"] = function(b:*):* { return interp.numarg(b, 0) - interp.numarg(b, 1) }; - primTable["*"] = function(b:*):* { return interp.numarg(b, 0) * interp.numarg(b, 1) }; - primTable["/"] = function(b:*):* { return interp.numarg(b, 0) / interp.numarg(b, 1) }; + primTable["+"] = function(b:*):* { return interp.numarg(b[0]) + interp.numarg(b[1]) }; + primTable["-"] = function(b:*):* { return interp.numarg(b[0]) - interp.numarg(b[1]) }; + primTable["*"] = function(b:*):* { return interp.numarg(b[0]) * interp.numarg(b[1]) }; + primTable["/"] = function(b:*):* { return interp.numarg(b[0]) / interp.numarg(b[1]) }; primTable["randomFrom:to:"] = primRandom; - primTable["<"] = function(b:*):* { return compare(interp.arg(b, 0), interp.arg(b, 1)) < 0 }; - primTable["="] = function(b:*):* { return compare(interp.arg(b, 0), interp.arg(b, 1)) == 0 }; - primTable[">"] = function(b:*):* { return compare(interp.arg(b, 0), interp.arg(b, 1)) > 0 }; - primTable["&"] = function(b:*):* { return interp.arg(b, 0) && interp.arg(b, 1) }; - primTable["|"] = function(b:*):* { return interp.arg(b, 0) || interp.arg(b, 1) }; - primTable["not"] = function(b:*):* { return !interp.arg(b, 0) }; - primTable["abs"] = function(b:*):* { return Math.abs(interp.numarg(b, 0)) }; - primTable["sqrt"] = function(b:*):* { return Math.sqrt(interp.numarg(b, 0)) }; - primTable["power:of:"] = function(b:*):* { return Math.pow(interp.numarg(b, 0), interp.numarg(b, 1)) }; + primTable["<"] = function(b:*):* { return compare(b[0], b[1]) < 0 }; + primTable["="] = function(b:*):* { return compare(b[0], b[1]) == 0 }; + primTable[">"] = function(b:*):* { return compare(b[0], b[1]) > 0 }; + primTable["&"] = function(b:*):* { return interp.boolarg(b[0]) && interp.boolarg(b[1]) }; + primTable["|"] = function(b:*):* { return interp.boolarg(b[0]) || interp.boolarg(b[1]) }; + primTable["not"] = function(b:*):* { return !interp.boolarg(b[0]) }; + primTable["abs"] = function(b:*):* { return Math.abs(interp.numarg(b[0])) }; + primTable["sqrt"] = function(b:*):* { return Math.sqrt(interp.numarg(b[0])) }; + primTable["power:of:"] = function(b:*):* { return Math.pow(interp.numarg(b[0]), interp.numarg(b[1])) }; primTable["reverseString:"] = primReverseString; primTable["splitStringFrom:"] = primSplit; - primTable["concatenate:with:"] = function(b:*):* { return ("" + interp.arg(b, 0) + interp.arg(b, 1)).substr(0, 10240); }; + primTable["concatenate:with:"] = function(b:*):* { return ("" + b[0] + b[1]).substr(0, 10240); }; primTable["letter:of:"] = primLetterOf; - primTable["stringLength:"] = function(b:*):* { return String(interp.arg(b, 0)).length }; + primTable["stringLength:"] = function(b:*):* { return String(b[0]).length }; primTable["%"] = primModulo; - primTable["rounded"] = function(b:*):* { return Math.round(interp.numarg(b, 0)) }; + primTable["rounded"] = function(b:*):* { return Math.round(interp.numarg(b[0])) }; primTable["computeFunction:of:"] = primMathFunction; primTable["chooseConstant:"] = primGetConstant; @@ -95,54 +95,49 @@ public class Primitives { primTable["httpBlock:"] = primHttp; primTable["httpReturn:"] = function(b:*):* {return httpReturn}; - new LooksPrims(app, interp).addPrimsTo(primTable); - new MotionAndPenPrims(app, interp).addPrimsTo(primTable); - new SoundPrims(app, interp).addPrimsTo(primTable); - new VideoMotionPrims(app, interp).addPrimsTo(primTable); - addOtherPrims(primTable); + new LooksPrims(app, interp).addPrimsTo(primTable, specialTable); + new MotionAndPenPrims(app, interp).addPrimsTo(primTable, specialTable); + new SoundPrims(app, interp).addPrimsTo(primTable, specialTable); + new VideoMotionPrims(app, interp).addPrimsTo(primTable, specialTable); + addOtherPrims(primTable, specialTable); } - protected function addOtherPrims(primTable:Dictionary):void { - new SensingPrims(app, interp).addPrimsTo(primTable); - new ListPrims(app, interp).addPrimsTo(primTable); + protected function addOtherPrims(primTable:Dictionary, specialTable:Dictionary):void { + new SensingPrims(app, interp).addPrimsTo(primTable, specialTable); + new ListPrims(app, interp).addPrimsTo(primTable, specialTable); } - private function primRandom(b:Block):Number { - var n1:Number = interp.numarg(b, 0); - var n2:Number = interp.numarg(b, 1); + private function primRandom(b:Array):Number { + var n1:Number = interp.numarg(b[0]); + var n2:Number = interp.numarg(b[1]); var low:Number = (n1 <= n2) ? n1 : n2; var hi:Number = (n1 <= n2) ? n2 : n1; if (low == hi) return low; - // if both low and hi are ints, truncate the result to an int - var ba1:BlockArg = b.args[0] as BlockArg; - var ba2:BlockArg = b.args[1] as BlockArg; - var int1:Boolean = ba1 ? ba1.numberType == BlockArg.NT_INT : int(n1) == n1; - var int2:Boolean = ba2 ? ba2.numberType == BlockArg.NT_INT : int(n2) == n2; - if (int1 && int2) + if ((int(low) == low) && (int(hi) == hi)) { return low + int(Math.random() * ((hi + 1) - low)); - + } return (Math.random() * (hi - low)) + low; } - private function primLetterOf(b:Block):String { - var s:String = interp.arg(b, 1); - var i:int = interp.numarg(b, 0) - 1; + private function primLetterOf(b:Array):String { + var s:String = b[1]; + var i:int = interp.numarg(b[0]) - 1; if ((i < 0) || (i >= s.length)) return ""; return s.charAt(i); } - private function primModulo(b:Block):Number { - var n:Number = interp.numarg(b, 0); - var modulus:Number = interp.numarg(b, 1); + private function primModulo(b:Array):Number { + var n:Number = interp.numarg(b[0]); + var modulus:Number = interp.numarg(b[1]); var result:Number = n % modulus; if (result / modulus < 0) result += modulus; return result; } - private function primMathFunction(b:Block):Number { - var op:* = interp.arg(b, 0); - var n:Number = interp.numarg(b, 1); + private function primMathFunction(b:Array):Number { + var op:* = b[0]; + var n:Number = interp.numarg(b[1]); switch(op) { case "abs": return Math.abs(n); case "floor": return Math.floor(n); @@ -190,8 +185,8 @@ public class Primitives { return 1; } - private function primCreateCloneOf(b:Block):void { - var objName:String = interp.arg(b, 0); + private function primCreateCloneOf(b:Array):void { + var objName:String = b[0]; var proto:ScratchSprite = app.stagePane.spriteNamed(objName); if ('_myself_' == objName) proto = interp.activeThread.target; if (!proto) return; @@ -213,7 +208,7 @@ public class Primitives { app.runtime.cloneCount++; } - private function primDeleteClone(b:Block):void { + private function primDeleteClone(b:Array):void { var clone:ScratchSprite = interp.targetSprite(); if ((clone == null) || (!clone.isClone) || (clone.parent == null)) return; if (clone.bubble && clone.bubble.parent) clone.bubble.parent.removeChild(clone.bubble); @@ -221,9 +216,9 @@ public class Primitives { app.interp.stopThreadsFor(clone); app.runtime.cloneCount--; } - - private function primReverseString(b:Block):String { - var reverse:String = interp.arg(b, 0); + + private function primReverseString(b:Array):String { + var reverse:String = b[0]; var result:String = ""; var i:int; for(i = reverse.length; i > 0; i--) { @@ -233,8 +228,8 @@ public class Primitives { } - private function primGetConstant(b:Block):Number { - var pickConstant:* = interp.arg(b, 0); + private function primGetConstant(b:Array):Number { + var pickConstant:* = b[0]; switch(pickConstant) { case "Pi": return Math.PI; case "E": return Math.E; @@ -253,10 +248,10 @@ public class Primitives { } // Sharp --- HTTP - private function primHttp(b:Block):void { + private function primHttp(b:Array):void { if(httpRequestsActive == httpRequestsAllowed) return; httpRequestsActive++; - var url:String = interp.arg(b, 1); + var url:String = b[0]; var req:URLRequest = new URLRequest(url); req.method = URLRequestMethod.GET; diff --git a/src/primitives/SensingPrims.as b/src/primitives/SensingPrims.as index a4ea745ff..cac184325 100644 --- a/src/primitives/SensingPrims.as +++ b/src/primitives/SensingPrims.as @@ -43,13 +43,13 @@ public class SensingPrims { this.interp = interpreter; } - public function addPrimsTo(primTable:Dictionary):void { + public function addPrimsTo(primTable:Dictionary, specialTable:Dictionary):void { // sensing primTable['touching:'] = primTouching; primTable['touchingColor:'] = primTouchingColor; primTable['color:sees:'] = primColorSees; - primTable['doAsk'] = primAsk; + specialTable['doAsk'] = primAsk; primTable['answer'] = function(b:*):* { return app.runtime.lastAnswer }; primTable['mousePressed'] = function(b:*):* { return app.gh.mouseIsDown }; @@ -63,12 +63,12 @@ public class SensingPrims { primTable['soundLevel'] = function(b:*):* { return app.runtime.soundLevel() }; primTable['isLoud'] = function(b:*):* { return app.runtime.isLoud() }; primTable['timestamp'] = primTimestamp; - primTable['timeAndDate'] = function(b:*):* { return app.runtime.getTimeString(interp.arg(b, 0)) }; + primTable['timeAndDate'] = function(b:*):* { return app.runtime.getTimeString(b[0]) }; //primTable['getUserName'] = function(b:*):* { return '' }; // sensor - primTable['sensor:'] = function(b:*):* { return app.runtime.getSensor(interp.arg(b, 0)) }; - primTable['sensorPressed:'] = function(b:*):* { return app.runtime.getBooleanSensor(interp.arg(b, 0)) }; + primTable['sensor:'] = function(b:*):* { return app.runtime.getSensor(b[0]) }; + primTable['sensorPressed:'] = function(b:*):* { return app.runtime.getBooleanSensor(b[0]) }; // variable and list watchers primTable['showVariable:'] = primShowWatcher; @@ -85,18 +85,18 @@ public class SensingPrims { } // Sharp - private function primNotify(b:Block):void{ + private function primNotify(b:Array):void{ if(dialogBoxActive == dialogBoxAllowed) return; dialogBoxActive++; - DialogBox.notify(interp.arg(b,1),interp.arg(b,0),null,false, function(d:*):*{ dialogBoxActive--; }); + DialogBox.notify(b[1],b[0],null,false, function(d:*):*{ dialogBoxActive--; }); } // TODO: move to stage static private var stageRect:Rectangle = new Rectangle(0, 0, 480, 360); - private function primTouching(b:Block):Boolean { + private function primTouching(b:Array):Boolean { var s:ScratchSprite = interp.targetSprite(); if (s == null) return false; - var arg:* = interp.arg(b, 0); + var arg:* = b[0]; if ('_edge_' == arg) { if(stageRect.containsRect(s.getBounds(s.parent))) return false; @@ -132,12 +132,12 @@ public class SensingPrims { // private var testSpr:Sprite; // private var myBMTest:Bitmap; // private var stageBMTest:Bitmap; - private function primTouchingColor(b:Block):Boolean { + private function primTouchingColor(b:Array):Boolean { // Note: Attempted to switch app.stage.quality to LOW to disable anti-aliasing, which // can create false colors. Unfortunately, that caused serious performance issues. var s:ScratchSprite = interp.targetSprite(); if (s == null) return false; - var c:int = interp.arg(b, 0) | 0xFF000000; + var c:int = b[0] | 0xFF000000; var myBM:BitmapData = s.bitmap(true); var stageBM:BitmapData = stageBitmapWithoutSpriteFilteredByColor(s, c); // if(s.objName == 'sensor') { @@ -160,13 +160,13 @@ public class SensingPrims { return myBM.hitTest(new Point(0, 0), 1, stageBM, new Point(0, 0), 1); } - private function primColorSees(b:Block):Boolean { + private function primColorSees(b:Array):Boolean { // Note: Attempted to switch app.stage.quality to LOW to disable anti-aliasing, which // can create false colors. Unfortunately, that caused serious performance issues. var s:ScratchSprite = interp.targetSprite(); if (s == null) return false; - var c1:int = interp.arg(b, 0) | 0xFF000000; - var c2:int = interp.arg(b, 1) | 0xFF000000; + var c1:int = b[0] | 0xFF000000; + var c2:int = b[1] | 0xFF000000; var myBM:BitmapData = bitmapFilteredByColor(s.bitmap(true), c1); var stageBM:BitmapData = stageBitmapWithoutSpriteFilteredByColor(s, c2); // if(!testSpr) { @@ -215,7 +215,7 @@ public class SensingPrims { return app.stagePane.getBitmapWithoutSpriteFilteredByColor(s, c); } - private function primAsk(b:Block):void { + private function primAsk(b:Array):void { if (app.runtime.askPromptShowing()) { // wait if (1) some other sprite is asking (2) this question is answered (when firstTime is false) interp.doYield(); @@ -223,7 +223,7 @@ public class SensingPrims { } var obj:ScratchObj = interp.targetObj(); if (interp.activeThread.firstTime) { - var question:String = interp.arg(b, 0); + var question:String = b[0]; if ((obj is ScratchSprite) && (obj.visible)) { ScratchSprite(obj).showBubble(question, 'talk', true); app.runtime.showAskPrompt(''); @@ -234,12 +234,15 @@ public class SensingPrims { interp.doYield(); } else { if ((obj is ScratchSprite) && (obj.visible)) ScratchSprite(obj).hideBubble(); - interp.activeThread.firstTime = true; + var block:Block = interp.activeThread.block; + interp.activeThread.popState(); + interp.activeThread.firstTime = true; + if (block.nextBlock) interp.activeThread.pushStateForBlock(block.nextBlock); } } - private function primKeyPressed(b:Block):Boolean { - var key:String = interp.arg(b, 0); + private function primKeyPressed(b:Array):Boolean { + var key:String = b[0]; if (key == 'any') { for each (var k:Boolean in app.runtime.keyIsDown) { if (k) return true; @@ -256,18 +259,18 @@ public class SensingPrims { return app.runtime.keyIsDown[ch]; } - private function primDistanceTo(b:Block):Number { + private function primDistanceTo(b:Array):Number { var s:ScratchSprite = interp.targetSprite(); - var p:Point = mouseOrSpritePosition(interp.arg(b, 0)); + var p:Point = mouseOrSpritePosition(b[0]); if ((s == null) || (p == null)) return 10000; var dx:Number = p.x - s.scratchX; var dy:Number = p.y - s.scratchY; return Math.sqrt((dx * dx) + (dy * dy)); } - private function primGetAttribute(b:Block):* { - var attribute:String = interp.arg(b, 0); - var obj:ScratchObj = app.stagePane.objNamed(String(interp.arg(b, 1))); + private function primGetAttribute(b:Array):* { + var attribute:String = b[0]; + var obj:ScratchObj = app.stagePane.objNamed(String(b[1])); if (!(obj is ScratchObj)) return 0; if (obj is ScratchSprite) { var s:ScratchSprite = ScratchSprite(obj); @@ -300,27 +303,27 @@ public class SensingPrims { return null; } - private function primShowWatcher(b:Block):* { + private function primShowWatcher(b:Array):* { var obj:ScratchObj = interp.targetObj(); - if (obj) app.runtime.showVarOrListFor(interp.arg(b, 0), false, obj); + if (obj) app.runtime.showVarOrListFor(b[0], false, obj); } - private function primHideWatcher(b:Block):* { + private function primHideWatcher(b:Array):* { var obj:ScratchObj = interp.targetObj(); - if (obj) app.runtime.hideVarOrListFor(interp.arg(b, 0), false, obj); + if (obj) app.runtime.hideVarOrListFor(b[0], false, obj); } - private function primShowListWatcher(b:Block):* { + private function primShowListWatcher(b:Array):* { var obj:ScratchObj = interp.targetObj(); - if (obj) app.runtime.showVarOrListFor(interp.arg(b, 0), true, obj); + if (obj) app.runtime.showVarOrListFor(b[0], true, obj); } - private function primHideListWatcher(b:Block):* { + private function primHideListWatcher(b:Array):* { var obj:ScratchObj = interp.targetObj(); - if (obj) app.runtime.hideVarOrListFor(interp.arg(b, 0), true, obj); + if (obj) app.runtime.hideVarOrListFor(b[0], true, obj); } - private function primTimestamp(b:Block):* { + private function primTimestamp(b:Array):* { const millisecondsPerDay:int = 24 * 60 * 60 * 1000; const epoch:Date = new Date(2000, 0, 1); // Jan 1, 2000 (Note: Months are zero-based.) var now:Date = new Date(); diff --git a/src/primitives/SoundPrims.as b/src/primitives/SoundPrims.as index e25ad3d5b..caf463da3 100644 --- a/src/primitives/SoundPrims.as +++ b/src/primitives/SoundPrims.as @@ -39,16 +39,16 @@ public class SoundPrims { this.interp = interpreter; } - public function addPrimsTo(primTable:Dictionary):void { + public function addPrimsTo(primTable:Dictionary, specialTable:Dictionary):void { primTable["playSound:"] = primPlaySound; - primTable["doPlaySoundAndWait"] = primPlaySoundUntilDone; + specialTable["doPlaySoundAndWait"] = primPlaySoundUntilDone; primTable["stopAllSounds"] = function(b:*):* { ScratchSoundPlayer.stopAllSounds() }; - primTable["drum:duration:elapsed:from:"] = primPlayDrum; // Scratch 1.4 drum numbers - primTable["playDrum"] = primPlayDrum; - primTable["rest:elapsed:from:"] = primPlayRest; + specialTable["drum:duration:elapsed:from:"] = primPlayDrum; // Scratch 1.4 drum numbers + specialTable["playDrum"] = primPlayDrum; + specialTable["rest:elapsed:from:"] = primPlayRest; - primTable["noteOn:duration:elapsed:from:"] = primPlayNote; + specialTable["noteOn:duration:elapsed:from:"] = primPlayNote; primTable["midiInstrument:"] = primSetInstrument; // Scratch 1.4 instrument numbers primTable["instrument:"] = primSetInstrument; @@ -56,121 +56,96 @@ public class SoundPrims { primTable["setVolumeTo:"] = primSetVolume; primTable["volume"] = primVolume; - primTable["changeTempoBy:"] = function(b:*):* { - app.stagePane.setTempo(app.stagePane.tempoBPM + interp.numarg(b, 0)); - interp.redraw(); - }; - primTable["setTempoTo:"] = function(b:*):* { - app.stagePane.setTempo(interp.numarg(b, 0)); - interp.redraw(); - }; + primTable["changeTempoBy:"] = function(b:*):* { app.stagePane.setTempo(app.stagePane.tempoBPM + interp.numarg(b[0])) }; + primTable["setTempoTo:"] = function(b:*):* { app.stagePane.setTempo(interp.numarg(b[0])) }; primTable["tempo"] = function(b:*):* { return app.stagePane.tempoBPM }; } - private function primPlaySound(b:Block):void { - if(Scratch.app.sharpSettings.data.allowSound){ - var snd:ScratchSound = interp.targetObj().findSound(interp.arg(b, 0)); - if (snd != null) playSound(snd, interp.targetObj()); - } + private function primPlaySound(b:Array):void { + var snd:ScratchSound = interp.targetObj().findSound(b[0]); + if (snd != null) playSound(snd, interp.targetObj()); } - private function primPlaySoundUntilDone(b:Block):void { - if(Scratch.app.sharpSettings.data.allowSound){ - var activeThread:Thread = interp.activeThread; - if (activeThread.firstTime) { - var snd:ScratchSound = interp.targetObj().findSound(interp.arg(b, 0)); - if (snd == null) return; - activeThread.tmpObj = playSound(snd, interp.targetObj()); - activeThread.firstTime = false; - } - var player:ScratchSoundPlayer = ScratchSoundPlayer(activeThread.tmpObj); - if ((player == null) || (player.atEnd())) { // finished playing - activeThread.tmp = 0; - activeThread.firstTime = true; - } else { - interp.doYield(); - } + private function primPlaySoundUntilDone(b:Array):void { + var activeThread:Thread = interp.activeThread; + if (activeThread.firstTime) { + var snd:ScratchSound = interp.targetObj().findSound(b[0]); + if (snd == null) return; + activeThread.tmpObj = playSound(snd, interp.targetObj()); + activeThread.firstTime = false; + } + var player:ScratchSoundPlayer = ScratchSoundPlayer(activeThread.tmpObj); + if ((player == null) || player.atEnd()) { // finished playing + activeThread.tmp = 0; + activeThread.firstTime = true; + var block:Block = activeThread.block; + activeThread.popState(); + if (block.nextBlock) activeThread.pushStateForBlock(block.nextBlock); + } else { + interp.doYield(); } } - private function primPlayNote(b:Block):void { - if(Scratch.app.sharpSettings.data.allowSound){ - var s:ScratchObj = interp.targetObj(); - if (s == null) return; - if (interp.activeThread.firstTime) { - var key:Number = interp.numarg(b, 0); - var secs:Number = beatsToSeconds(interp.numarg(b, 1)); - interp.activeThread.tmpObj = playNote(s.instrument, key, secs, s); - interp.startTimer(secs); - } else { - interp.checkTimer(); - } + private function primPlayNote(b:Array):void { + var s:ScratchObj = interp.targetObj(); + if (s == null) return; + if (interp.activeThread.firstTime) { + var key:Number = interp.numarg(b[0]); + var secs:Number = beatsToSeconds(interp.numarg(b[1])); + interp.activeThread.tmpObj = playNote(s.instrument, key, secs, s); + interp.startTimer(secs); + } else { + interp.checkTimer(); } } - private function primPlayDrum(b:Block):void { - if(Scratch.app.sharpSettings.data.allowSound){ - var s:ScratchObj = interp.targetObj(); - if (s == null) return; - if (interp.activeThread.firstTime) { - var drum:int = Math.round(interp.numarg(b, 0)); - var isMIDI:Boolean = (b.op == 'drum:duration:elapsed:from:'); - var secs:Number = beatsToSeconds(interp.numarg(b, 1)); - playDrum(drum, isMIDI, 10, s); // always play entire drum sample - interp.startTimer(secs); - } else { - interp.checkTimer(); - } + private function primPlayDrum(b:Array):void { + var s:ScratchObj = interp.targetObj(); + if (s == null) return; + if (interp.activeThread.firstTime) { + var drum:int = Math.round(interp.numarg(b[0])); + var isMIDI:Boolean = (b.op == 'drum:duration:elapsed:from:'); + var secs:Number = beatsToSeconds(interp.numarg(b[1])); + playDrum(drum, isMIDI, 10, s); // always play entire drum sample + interp.startTimer(secs); + } else { + interp.checkTimer(); } } private function playSound(s:ScratchSound, client:ScratchObj):ScratchSoundPlayer { - if(Scratch.app.sharpSettings.data.allowSound){ - var player:ScratchSoundPlayer = s.sndplayer(); - player.client = client; - player.startPlaying(); - return player; - }else{ - return null; - } + var player:ScratchSoundPlayer = s.sndplayer(); + player.client = client; + player.startPlaying(); + return player; } private function playDrum(drum:int, isMIDI:Boolean, secs:Number, client:ScratchObj):ScratchSoundPlayer { - if(Scratch.app.sharpSettings.data.allowSound){ - var player:NotePlayer = SoundBank.getDrumPlayer(drum, isMIDI, secs); - if (player == null) return null; - player.client = client; - player.setDuration(secs); - player.startPlaying(); - return player; - }else{ - return null; - } + var player:NotePlayer = SoundBank.getDrumPlayer(drum, isMIDI, secs); + if (player == null) return null; + player.client = client; + player.setDuration(secs); + player.startPlaying(); + return player; } private function playNote(instrument:int, midiKey:Number, secs:Number, client:ScratchObj):ScratchSoundPlayer { - if(Scratch.app.sharpSettings.data.allowSound){ - var player:NotePlayer = SoundBank.getNotePlayer(instrument, midiKey); - if (player == null) return null; - player.client = client; - player.setNoteAndDuration(midiKey, secs); - player.startPlaying(); - return player; - }else{ - return null; - } + var player:NotePlayer = SoundBank.getNotePlayer(instrument, midiKey); + if (player == null) return null; + player.client = client; + player.setNoteAndDuration(midiKey, secs); + player.startPlaying(); + return player; } - private function primPlayRest(b:Block):void { - if(Scratch.app.sharpSettings.data.allowSound){ - var s:ScratchObj = interp.targetObj(); - if (s == null) return; - if (interp.activeThread.firstTime) { - var secs:Number = beatsToSeconds(interp.numarg(b, 0)); - interp.startTimer(secs); - } else { - interp.checkTimer(); - } + private function primPlayRest(b:Array):void { + var s:ScratchObj = interp.targetObj(); + if (s == null) return; + if (interp.activeThread.firstTime) { + var secs:Number = beatsToSeconds(interp.numarg(b[0])); + interp.startTimer(secs); + } else { + interp.checkTimer(); } } @@ -178,36 +153,28 @@ public class SoundPrims { return (beats * 60) / app.stagePane.tempoBPM; } - private function primSetInstrument(b:Block):void { - if(Scratch.app.sharpSettings.data.allowSound){ - // Set Scratch 2.0 instrument. - var instr:int = interp.numarg(b, 0) - 1; - if (b.op == 'midiInstrument:') { - // map old to new instrument number - instr = instrumentMap[instr] - 1; // maps to -1 if out of range - } - instr = Math.max(0, Math.min(instr, SoundBank.instrumentNames.length - 1)); - if (interp.targetObj()) interp.targetObj().instrument = instr; + private function primSetInstrument(b:Array):void { + // Set Scratch 2.0 instrument. + var instr:int = interp.numarg(b[0]) - 1; + if (b.op == 'midiInstrument:') { + // map old to new instrument number + instr = instrumentMap[instr] - 1; // maps to -1 if out of range } + instr = Math.max(0, Math.min(instr, SoundBank.instrumentNames.length - 1)); + if (interp.targetObj()) interp.targetObj().instrument = instr; } - private function primChangeVolume(b:Block):void { + private function primChangeVolume(b:Array):void { var s:ScratchObj = interp.targetObj(); - if (s != null) { - s.setVolume(s.volume + interp.numarg(b, 0)); - interp.redraw(); - } + if (s != null) s.setVolume(s.volume + interp.numarg(b[0])); } - private function primSetVolume(b:Block):void { + private function primSetVolume(b:Array):void { var s:ScratchObj = interp.targetObj(); - if (s != null) { - s.setVolume(interp.numarg(b, 0)); - interp.redraw(); - } + if (s != null) s.setVolume(interp.numarg(b[0])); } - private function primVolume(b:Block):Number { + private function primVolume(b:Array):Number { var s:ScratchObj = interp.targetObj(); return (s != null) ? s.volume : 0; } @@ -279,5 +246,4 @@ public class SoundPrims { // Telephone Ring, Helicopter, Applause, Gunshot 21, 21, 21, 21 ]; - -}} +}} \ No newline at end of file diff --git a/src/primitives/VideoMotionPrims.as b/src/primitives/VideoMotionPrims.as index 6bf77bf42..12b958348 100644 --- a/src/primitives/VideoMotionPrims.as +++ b/src/primitives/VideoMotionPrims.as @@ -65,15 +65,15 @@ public class VideoMotionPrims { frameBuffer = new BitmapData(WIDTH, HEIGHT); } - public function addPrimsTo(primTable:Dictionary):void { + public function addPrimsTo(primTable:Dictionary, specialTable:Dictionary):void { primTable['senseVideoMotion'] = primVideoMotion; readMotionSensor = getMotionOn; } - private function primVideoMotion(b:Block):Number { - var motionType:String = interp.arg(b, 0); - var obj:ScratchObj = app.stagePane.objNamed(String(interp.arg(b, 1))); - if ('this sprite' == interp.arg(b, 1)) obj = interp.targetObj(); + private function primVideoMotion(b:Array):Number { + var motionType:String = b[0]; + var obj:ScratchObj = app.stagePane.objNamed(String(b[1])); + if ('this sprite' == b[1]) obj = interp.targetObj(); return getMotionOn(motionType, obj); } @@ -282,4 +282,4 @@ public class VideoMotionPrims { analysisDone = true; } -}} +}} \ No newline at end of file diff --git a/src/scratch/BlockMenus.as b/src/scratch/BlockMenus.as index bc5656c6d..430c47e21 100644 --- a/src/scratch/BlockMenus.as +++ b/src/scratch/BlockMenus.as @@ -589,7 +589,7 @@ public class BlockMenus implements DragClient { } var d:DialogBox = new DialogBox(editSpec2); d.addTitle('Edit Block'); - d.addWidget(new ProcedureSpecEditor(block.spec, block.parameterNames, block.warpProcFlag)); + d.addWidget(new ProcedureSpecEditor(block.spec, block.parameterNames, block.warpProcFlag, block.procedureType, true)); d.addAcceptCancelButtons('OK'); d.showOnStage(app.stage, true); ProcedureSpecEditor(d.widget).setInitialFocus(); @@ -603,6 +603,7 @@ public class BlockMenus implements DragClient { block.parameterNames = ProcedureSpecEditor(dialog.widget).inputNames(); block.defaultArgValues = ProcedureSpecEditor(dialog.widget).defaultArgValues(); block.warpProcFlag = ProcedureSpecEditor(dialog.widget).warpFlag(); + block.procedureType = ProcedureSpecEditor(dialog.widget).type(); block.setSpec(newSpec); if (block.nextBlock) block.nextBlock.allBlocksDo(function(b:Block):void { if (b.op == Specs.GET_PARAM) b.parameterIndex = -1; // parameters may have changed; clear cached indices diff --git a/src/scratch/PaletteBuilder.as b/src/scratch/PaletteBuilder.as index 5890cec14..10e22d343 100644 --- a/src/scratch/PaletteBuilder.as +++ b/src/scratch/PaletteBuilder.as @@ -129,13 +129,11 @@ public class PaletteBuilder { var catColor:int = Specs.blockColor(Specs.procedureColor); addItem(new Button(Translator.map('Make a Block'), makeNewBlock, false, '/help/studio/tips/blocks/make-a-block/')); var definitions:Array = app.viewedObj().procedureDefinitions(); + addBlocksForCategory(10, Specs.procedureColor); if (definitions.length > 0) { nextY += 5; for each (var proc:Block in definitions) { - //if(!proc.isCustomReporter && !proc.isCustomBoolean) var b:Block = new Block(proc.spec, ' ', Specs.procedureColor, Specs.CALL, proc.defaultArgValues); - //if(proc.isCustomReporter && !proc.isCustomBoolean) var b:Block = new Block(proc.spec, 'r', Specs.procedureColor, Specs.CALL, proc.defaultArgValues); - //if(!proc.isCustomReporter && proc.isCustomBoolean) var b:Block = new Block(proc.spec, 'b', Specs.procedureColor, Specs.CALL, proc.defaultArgValues); - var b:Block = new Block(proc.spec, ' ', Specs.procedureColor, Specs.CALL, proc.defaultArgValues); + var b:Block = new Block(proc.spec, proc.procedureType, Specs.procedureColor, Specs.CALL, proc.defaultArgValues); addItem(b); } nextY += 5; @@ -257,10 +255,7 @@ public class PaletteBuilder { newHat.parameterNames = specEditor.inputNames(); newHat.defaultArgValues = specEditor.defaultArgValues(); newHat.warpProcFlag = specEditor.warpFlag(); - //if(specEditor.returnValuesCheckbox.isOn() && !specEditor.returnBooleanCheckbox.isOn()) newHat.setCustomBlockType(Block.CUSTOM_REPORTER); - //if(specEditor.returnValuesCheckbox.isOn() && specEditor.returnBooleanCheckbox.isOn()) newHat.setCustomBlockType(Block.CUSTOM_BOOLEAN); - //if(!specEditor.returnValuesCheckbox.isOn() && !specEditor.returnBooleanCheckbox.isOn()) newHat.setCustomBlockType(Block.CUSTOM_COMMAND); - newHat.setCustomBlockType(Block.CUSTOM_COMMAND); + newHat.procedureType = specEditor.type(); newHat.setSpec(spec); newHat.x = 10 - app.scriptsPane.x + Math.random() * 100; newHat.y = 10 - app.scriptsPane.y + Math.random() * 100; @@ -271,7 +266,7 @@ public class PaletteBuilder { app.setSaveNeeded(); } - var specEditor:ProcedureSpecEditor = new ProcedureSpecEditor('', [], false); + var specEditor:ProcedureSpecEditor = new ProcedureSpecEditor('', [], false, ' ', false); var d:DialogBox = new DialogBox(addBlockHat); d.addTitle('New Block'); d.addWidget(specEditor); diff --git a/src/scratch/ScratchRuntime.as b/src/scratch/ScratchRuntime.as index 6d914f136..9874c68f5 100644 --- a/src/scratch/ScratchRuntime.as +++ b/src/scratch/ScratchRuntime.as @@ -660,8 +660,8 @@ public class ScratchRuntime { if (!hat.isHat || !hat.nextBlock) return; // skip disconnected hats if ('whenSensorGreaterThan' == hat.op) { - var sensorName:String = interp.arg(hat, 0); - var threshold:Number = interp.numarg(hat, 1); + var sensorName:String = (hat.args[0] as BlockArg).argValue; + var threshold:Number = Number((hat.args[1] as BlockArg).argValue) || 0; if (('loudness' == sensorName && soundLevel() > threshold) || ('timer' == sensorName && timer() > threshold) || ('video motion' == sensorName && target.visible && VideoMotionPrims.readMotionSensor('motion', target) > threshold)) { @@ -672,7 +672,7 @@ public class ScratchRuntime { activeHats.push(hat); } } else if ('whenSensorConnected' == hat.op) { - if (getBooleanSensor(interp.arg(hat, 0))) { + if (getBooleanSensor((hat.args[0] as BlockArg).argValue)) { if (triggeredHats.indexOf(hat) == -1) { // not already trigged // only start the stack if it is not already running if (!interp.isRunning(hat, target)) interp.toggleThread(hat, target); @@ -687,7 +687,7 @@ public class ScratchRuntime { var numArgs:uint = hat.args.length; var finalArgs:Array = new Array(numArgs); for (var i:uint = 0; i < numArgs; ++i) - finalArgs[i] = interp.arg(hat, i); + finalArgs[i] = (hat.args[i] as BlockArg).argValue; processExtensionReporter(hat, target, extName, op, finalArgs); } @@ -752,7 +752,7 @@ public class ScratchRuntime { var op:String = b.op; if (op == Specs.GET_PARAM) b.parameterIndex = -1; // need to invalidate index cache if (('senseVideoMotion' == op) || - (('whenSensorGreaterThan' == op) && ('video motion' == interp.arg(b, 0)))) { + (('whenSensorGreaterThan' == op) && ('video motion' == (b.args[0] as BlockArg).argValue))) { app.libraryPart.showVideoButton(); } diff --git a/src/ui/ProcedureSpecEditor.as b/src/ui/ProcedureSpecEditor.as index 477e85120..79f486295 100644 --- a/src/ui/ProcedureSpecEditor.as +++ b/src/ui/ProcedureSpecEditor.as @@ -30,12 +30,17 @@ package ui { public class ProcedureSpecEditor extends Sprite { + private var isEdit:Boolean; private var base:Shape; + private var shape:int; private var blockShape:BlockShape; private var row:Array = []; private var moreLabel:TextField; private var moreButton:IconButton; + private var shapeLabels:Array = []; + private var shapeIcons:Array = []; + private var shapeButtons:Array = []; private var buttonLabels:Array = []; private var buttons:Array = []; @@ -48,11 +53,14 @@ public class ProcedureSpecEditor extends Sprite { private const labelColor:int = 0x8738bf; // 0x6c36b3; // 0x9c35b3; private const selectedLabelColor:int = 0xefa6ff; - public function ProcedureSpecEditor(originalSpec:String, inputNames:Array, warpFlag:Boolean) { + public function ProcedureSpecEditor(originalSpec:String, inputNames:Array, warpFlag:Boolean, type:String, isEdit:Boolean) { + this.isEdit = isEdit; + addChild(base = new Shape()); setWidthHeight(350, 10); - blockShape = new BlockShape(BlockShape.CmdShape, Specs.procedureColor); + shape = type == "b" ? BlockShape.BooleanShape : type == "r" ? BlockShape.NumberShape : BlockShape.CmdShape; + blockShape = new BlockShape(shape, Specs.procedureColor); blockShape.setWidthAndTopHeight(100, 25, true); addChild(blockShape); @@ -84,7 +92,9 @@ public class ProcedureSpecEditor extends Sprite { 'Add string input:', 'Add boolean input:', 'Add label text:', - 'text', + "Doesn't report", + 'Reports number or text', + 'Reports true or false', ]; } @@ -111,7 +121,7 @@ public class ProcedureSpecEditor extends Sprite { clearRow(); var i:int = 0; for each (var s:String in ReadStream.tokenize(spec)) { - if (s.length >= 2 && s.charAt(0) == '%') { // argument spec + if ((s.length >= 2) && (s.charAt(0) == '%')) { // argument spec var argSpec:String = s.charAt(1); var arg:BlockArg = null; if (argSpec == 'b') arg = makeBooleanArg(); @@ -123,11 +133,9 @@ public class ProcedureSpecEditor extends Sprite { } } else { if ((row.length > 0) && (row[row.length - 1] is TextField)) { - var tf:TextField = row[row.length - 1]; - tf.appendText(' ' + ReadStream.unescape(s)); - fixLabelWidth(tf); + TextField(row[row.length - 1]).appendText(' ' + s); } else { - addElement(makeTextField(ReadStream.unescape(s))); + addElement(makeTextField(s)); } } } @@ -138,7 +146,7 @@ public class ProcedureSpecEditor extends Sprite { public function spec():String { var result:String = ''; for each (var o:* in row) { - if (o is TextField) result += ReadStream.escape(TextField(o).text); + if (o is TextField) result += TextField(o).text; if (o is BlockArg) result += '%' + BlockArg(o).type; if ((result.length > 0) && (result.charAt(result.length - 1) != ' ')) result += ' '; } @@ -146,6 +154,10 @@ public class ProcedureSpecEditor extends Sprite { return result; } + public function type():String { + return shape == BlockShape.BooleanShape ? "b" : shape == BlockShape.NumberShape ? "r" : " "; + } + public function defaultArgValues():Array { var result:Array = []; for each (var el:* in row) { @@ -169,12 +181,22 @@ public class ProcedureSpecEditor extends Sprite { public function inputNames():Array { var result:Array = []; for each (var o:* in row) { - if (o is BlockArg) result.push(uniqueName(result, BlockArg(o).field.text)); + if (o is BlockArg) result.push(BlockArg(o).field.text); } return result; } private function addButtonsAndLabels():void { + shapeLabels = [ + makeLabel("Doesn't report", 14), + makeLabel('Reports number or text', 14), + makeLabel('Reports true or false', 14), + ]; + shapeButtons = [ + new IconButton(function():void { setShape(BlockShape.CmdShape) }, null), + new IconButton(function():void { setShape(BlockShape.NumberShape) }, null), + new IconButton(function():void { setShape(BlockShape.BooleanShape) }, null) + ]; buttonLabels = [ makeLabel('Add number input:', 14), makeLabel('Add string input:', 14), @@ -185,10 +207,26 @@ public class ProcedureSpecEditor extends Sprite { new Button('', function():void { appendObj(makeNumberArg()) }), new Button('', function():void { appendObj(makeStringArg()) }), new Button('', function():void { appendObj(makeBooleanArg()) }), - new Button(Translator.map('text'), function():void { appendObj(makeTextField('')) }) + new Button('text', function():void { appendObj(makeTextField('')) }) ]; + shapeButtons[0].setOn(true); + const lightGray:int = 0xA0A0A0; + var icon:BlockShape; + + shapeIcons = []; + icon = new BlockShape(BlockShape.CmdShape, Specs.procedureColor); + icon.setWidthAndTopHeight(34, 18, true); + shapeIcons.push(icon); + + icon = new BlockShape(BlockShape.NumberShape, Specs.procedureColor); + icon.setWidthAndTopHeight(34, 18, true); + shapeIcons.push(icon); + + icon = new BlockShape(BlockShape.BooleanShape, Specs.procedureColor); + icon.setWidthAndTopHeight(34, 18, true); + shapeIcons.push(icon); icon = new BlockShape(BlockShape.NumberShape, lightGray); icon.setWidthAndTopHeight(25, 14, true); @@ -198,12 +236,9 @@ public class ProcedureSpecEditor extends Sprite { icon.setWidthAndTopHeight(22, 14, true); buttons[1].setIcon(icon); - var icon:BlockShape = new BlockShape(BlockShape.BooleanShape, lightGray); + icon = new BlockShape(BlockShape.BooleanShape, lightGray); icon.setWidthAndTopHeight(25, 14, true); buttons[2].setIcon(icon); - - for each (var label:TextField in buttonLabels) addChild(label); - for each (var b:Button in buttons) addChild(b); } private function addwarpCheckbox():void { @@ -224,7 +259,7 @@ public class ProcedureSpecEditor extends Sprite { private function toggleButtons(ignore:*):void { var buttonsShowing:Boolean = buttons[0].parent != null; - showButtons(!buttonsShowing) + showButtons(!buttonsShowing); } private function deleteItem(ignore:*):void { @@ -241,15 +276,21 @@ public class ProcedureSpecEditor extends Sprite { } private function showButtons(showParams:Boolean):void { - var label:TextField, b:Button; + var label:TextField, b:Button, ib:IconButton, shape:BlockShape; if (showParams) { for each (label in buttonLabels) addChild(label); + if (!isEdit) for each (label in shapeLabels) addChild(label); for each (b in buttons) addChild(b); + if (!isEdit) for each (ib in shapeButtons) addChild(ib); + if (!isEdit) for each (shape in shapeIcons) addChild(shape); addChild(warpCheckbox); addChild(warpLabel); } else { for each (label in buttonLabels) if (label.parent) removeChild(label); + for each (label in shapeLabels) if (label.parent) removeChild(label); for each (b in buttons) if (b.parent) removeChild(b); + for each (ib in shapeButtons) if (b.parent) removeChild(b); + for each (shape in shapeIcons) if (shape.parent) removeChild(shape); if (warpCheckbox.parent) removeChild(warpCheckbox); if (warpLabel.parent) removeChild(warpLabel); } @@ -261,6 +302,19 @@ public class ProcedureSpecEditor extends Sprite { if (parent is DialogBox) DialogBox(parent).fixLayout(); } + private function setShape(shape:int):void { + this.shape = shape; + var ob:IconButton = shapeButtons[shape == BlockShape.BooleanShape ? 2 : shape == BlockShape.NumberShape ? 1 : 0]; + for each (var ib:IconButton in shapeButtons) { + ib.setOn(ib == ob); + } + var k:int = getChildIndex(blockShape); + removeChildAt(k); + blockShape = new BlockShape(shape, Specs.procedureColor); + addChildAt(blockShape, k); + fixLayout(); + } + private function makeBooleanArg():BlockArg { var result:BlockArg = new BlockArg('b', 0xFFFFFF, true); result.setArgValue(unusedArgName('boolean')); @@ -295,9 +349,10 @@ public class ProcedureSpecEditor extends Sprite { addChild(o); if (stage) { if (o is TextField) stage.focus = TextField(o); - if (o is BlockArg) BlockArg(o).startEditing(); + if (o is BlockArg) stage.focus = BlockArg(o).field; } fixLayout(); + if (parent is DialogBox) DialogBox(parent).fixLayout(); } private function makeTextField(contents:String):TextField { @@ -306,7 +361,7 @@ public class ProcedureSpecEditor extends Sprite { result.backgroundColor = labelColor; result.background = true; result.type = TextFieldType.INPUT; - result.defaultTextFormat = Block.blockLabelFormat; + result.defaultTextFormat = new TextFormat(CSS.font, 12, 0xFFFFFF); if (contents.length > 0) { result.width = 1000; result.text = contents; @@ -329,11 +384,11 @@ public class ProcedureSpecEditor extends Sprite { row = newRow; } - private function fixLayout(updateDelete:Boolean = true):void { + private function fixLayout():void { removeDeletedElementsFromRow(); blockShape.x = 10; blockShape.y = 10; - var nextX:int = blockShape.x + 6; + var nextX:int = blockShape.x + (shape == BlockShape.BooleanShape ? 14 : 6); var nextY:int = blockShape.y + 5; var maxH:int = 0; for each (var o:DisplayObject in row) maxH = Math.max(maxH, o.height); @@ -343,39 +398,43 @@ public class ProcedureSpecEditor extends Sprite { nextX += o.width + 4; if ((o is BlockArg) && (BlockArg(o).type == 's')) nextX -= 2; } - var blockW:int = Math.max(40, nextX + 4 - blockShape.x); + var blockW:int = Math.max(40, nextX + (shape == BlockShape.BooleanShape ? 12 : 4) - blockShape.x); blockShape.setWidthAndTopHeight(blockW, maxH + 11, true); moreButton.x = 0; - moreButton.y = blockShape.y + blockShape.height + 12; + moreButton.y = blockShape.y + blockShape.height + (shape == BlockShape.CmdShape ? 12 : 15); moreLabel.x = 10; moreLabel.y = moreButton.y - 4; - var labelX:int = blockShape.x + 45; - var buttonX:int = 240; - for each (var l:TextField in buttonLabels) { - buttonX = Math.max(buttonX, labelX + l.textWidth + 10); - } - - var rowY:int = blockShape.y + blockShape.height + 30; + var rowY:int = blockShape.y + blockShape.height + (shape == BlockShape.CmdShape ? 30 : 33); for (var i:int = 0; i < buttons.length; i++) { - var label:TextField = buttonLabels[i]; - buttonLabels[i].x = labelX; + buttonLabels[i].x = blockShape.x + 45; buttonLabels[i].y = rowY; - buttons[i].x = buttonX; + buttons[i].x = 240; buttons[i].y = rowY - 4; rowY += 30; } + if (!isEdit) { + for (i = 0; i < shapeButtons.length; i++) { + shapeButtons[i].x = blockShape.x + 46; + shapeButtons[i].y = rowY + 4; + shapeIcons[i].x = shapeButtons[i].x + shapeButtons[i].width + 8; + shapeIcons[i].y = rowY; + shapeLabels[i].x = shapeIcons[i].x + shapeIcons[i].width + 8; + shapeLabels[i].y = rowY; + rowY += 30; + } + } + warpCheckbox.x = blockShape.x + 46; warpCheckbox.y = rowY + 4; warpLabel.x = warpCheckbox.x + 18; warpLabel.y = warpCheckbox.y - 3; - if (updateDelete) updateDeleteButton(); - if (parent is DialogBox) DialogBox(parent).fixLayout(); + updateDeleteButton(); } /* Editing Parameter Names */ @@ -424,24 +483,10 @@ public class ProcedureSpecEditor extends Sprite { private function setFocus(o:DisplayObject):void { if (!stage) return; if (o is TextField) stage.focus = TextField(o); - if (o is BlockArg) BlockArg(o).startEditing(); - } - - private function uniqueName(taken:Array, name:String):String { - if (taken.indexOf(name) == -1) return name; - var e:Array = /\d+$/.exec(name); - var n:String = e ? e[0] : ""; - var base:String = name.slice(0, name.length - n.length); - var i:int = int(n || "1") + 1; - while (taken.indexOf(base + i) != -1) { - i++; - } - return base + i; + if (o is BlockArg) stage.focus = BlockArg(o).field; } private function focusChange(evt:FocusEvent):void { - var params:Array = []; - var change:Boolean = false; // Update label fields to show focus. for each (var o:DisplayObject in row) { if (o is TextField) { @@ -449,17 +494,9 @@ public class ProcedureSpecEditor extends Sprite { var hasFocus:Boolean = (stage != null) && (tf == stage.focus); tf.textColor = hasFocus ? 0 : 0xFFFFFF; tf.backgroundColor = hasFocus ? selectedLabelColor : labelColor; - } else if (o is BlockArg) { - tf = BlockArg(o).field; - if (params.indexOf(tf.text) != -1) { - BlockArg(o).setArgValue(uniqueName(params, tf.text)); - change = true; - } - params.push(tf.text); } } - if (change) fixLayout(false); - else if (evt.type == FocusEvent.FOCUS_IN) updateDeleteButton(); + if (evt.type == FocusEvent.FOCUS_IN) updateDeleteButton(); } private function updateDeleteButton():void { @@ -485,4 +522,4 @@ public class ProcedureSpecEditor extends Sprite { deleteButton.y = -6; } -}} +}} \ No newline at end of file From e036966a23888df2d93058b8b33e98370e07c795 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Sat, 11 Jun 2016 12:16:45 +1000 Subject: [PATCH 065/141] Fix --- src/primitives/Primitives.as | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index b625fda6d..c1f9db61b 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -236,12 +236,12 @@ public class Primitives { } return 0; } - private function primSplit(b:Block):String { - var a:String = interp.arg(b, 0); + private function primSplit(b:Array):String { + var a:String = b[0]; var result:String = ""; var i:int; - var j:int = interp.numarg(b, 2); - for(i = interp.numarg(b, 1); i < j + 1; i++) { + var j:int = b[2]; + for(i = b[1]; i < j + 1; i++) { result += a.charAt(i -1); } return result; From d2d8a83f11aae2a18e66d287c2b662283312b86b Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Sat, 11 Jun 2016 12:20:21 +1000 Subject: [PATCH 066/141] Fix --- src/primitives/Primitives.as | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index c1f9db61b..230b04376 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -240,8 +240,8 @@ public class Primitives { var a:String = b[0]; var result:String = ""; var i:int; - var j:int = b[2]; - for(i = b[1]; i < j + 1; i++) { + var j:int = interp.numarg(b[2]); + for(i = interp.numarg(b[1]); i < j + 1; i++) { result += a.charAt(i -1); } return result; From 9105aa599828f61ee761ed5fb0c03806edee8141 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Sat, 11 Jun 2016 15:55:56 +1000 Subject: [PATCH 067/141] Fix rabbit icon --- src/ui/ProcedureSpecEditor.as | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ui/ProcedureSpecEditor.as b/src/ui/ProcedureSpecEditor.as index 79f486295..d566948d3 100644 --- a/src/ui/ProcedureSpecEditor.as +++ b/src/ui/ProcedureSpecEditor.as @@ -145,6 +145,7 @@ public class ProcedureSpecEditor extends Sprite { public function spec():String { var result:String = ''; + if(warpFlag()) result = "@rabbit "; for each (var o:* in row) { if (o is TextField) result += TextField(o).text; if (o is BlockArg) result += '%' + BlockArg(o).type; From 6cdcab5d0a85402de317d45dba272e9dda479a9b Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Sat, 11 Jun 2016 16:57:39 +1000 Subject: [PATCH 068/141] Credit for NoMod for custom reporters --- src/Scratch.as | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Scratch.as b/src/Scratch.as index 8ed44f2e4..5b519d96b 100644 --- a/src/Scratch.as +++ b/src/Scratch.as @@ -278,7 +278,7 @@ public class Scratch extends Sprite { handleStartupParameters(); initSettings(); - if(isOffline) DialogBox.notify("Welcome to Sharp!", "Website: http://SharpScratchMod.github.io\nGitHub: https://github.com/SharpScratchMod/Sharp\n\nCredits:\nDrKat123 - Developer, Owner\nMrcomputer1 - Developer, Owner\nscratchyone - Developer"); + if(isOffline) DialogBox.notify("Welcome to Sharp!", "Website: http://SharpScratchMod.github.io\nGitHub: https://github.com/SharpScratchMod/Sharp\n\nCredits:\nDrKat123 - Developer, Owner\nMrcomputer1 - Developer, Owner\nscratchyone - Developer\n\nOther important credits:\nNoMod-Programming - Custom reporters"); } protected function handleStartupParameters():void { @@ -1129,7 +1129,7 @@ public class Scratch extends Sprite { protected function addHelpMenuItems(b:*, m:Menu):void { function helpMenuItemCredits(){ - DialogBox.notify("Credits", "*Owner\n\nDrKat123*, Mrcomputer1*, scratchyone"); + DialogBox.notify("Credits", "*Owner, # Non-Sharp Member\n\nDrKat123*, Mrcomputer1*, scratchyone\n\nNoMod-Programming#"); } function helpMenuItemReportBug(){ DialogBox.reportBugDialog(); From 47e71581f2cddbd270d2e28f15a62a85583f914a Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Sat, 11 Jun 2016 17:39:23 +1000 Subject: [PATCH 069/141] HTTP warning --- src/Scratch.as | 11 +++++++++++ src/blocks/BlockIO.as | 1 + src/ui/parts/StagePart.as | 23 +++++++++++++++++++++++ 3 files changed, 35 insertions(+) diff --git a/src/Scratch.as b/src/Scratch.as index 5b519d96b..5554bbbce 100644 --- a/src/Scratch.as +++ b/src/Scratch.as @@ -160,6 +160,7 @@ public class Scratch extends Sprite { private var lastTab:String = 'scripts'; protected var wasEdited:Boolean; // true if the project was edited and autosaved private var _usesUserNameBlock:Boolean = false; + private var _usesHTTPBlock:Boolean = false; protected var languageChanged:Boolean; // set when language changed // UI Elements @@ -671,6 +672,16 @@ public class Scratch extends Sprite { _usesUserNameBlock = value; stagePart.refresh(); } + + public function get usesHTTPBlock():Boolean { + return _usesHTTPBlock; + } + + public function set usesHTTPBlock(value:Boolean):void { + _usesHTTPBlock = value; + stagePart.refresh(); + } + public function updatePalette(clearCaches:Boolean = true):void { // Note: updatePalette() is called after changing variable, list, or procedure diff --git a/src/blocks/BlockIO.as b/src/blocks/BlockIO.as index d80848292..b36d9c9da 100644 --- a/src/blocks/BlockIO.as +++ b/src/blocks/BlockIO.as @@ -97,6 +97,7 @@ public class BlockIO { // Make a block from an array of form: * if (cmd[0] == 'getUserName') Scratch.app.usesUserNameBlock = true; + if (cmd[0] == 'httpBlock:') Scratch.app.usesHTTPBlock = true; var special:Block = specialCmd(cmd, forStage); if (special) { special.fixArgLayout(); return special } diff --git a/src/ui/parts/StagePart.as b/src/ui/parts/StagePart.as index 3846e7177..3a7d4a565 100644 --- a/src/ui/parts/StagePart.as +++ b/src/ui/parts/StagePart.as @@ -64,6 +64,7 @@ public class StagePart extends UIPart { private var playButton:Sprite; // YouTube-like play button in center of screen; used by Kiosk version private var userNameWarning:Sprite; // Container for privacy warning message for projects that use username block + private var httpWarning:Sprite; private var runButtonOnTicks:int; // x-y readouts @@ -160,6 +161,7 @@ public class StagePart extends UIPart { drawStageSizeButton(); } if (userNameWarning) userNameWarning.visible = app.usesUserNameBlock; + if (httpWarning) httpWarning.visible = app.usesHTTPBlock; updateProjectInfo(); } @@ -536,6 +538,27 @@ public class StagePart extends UIPart { userNameWarning.visible = false; // Don't show this by default } + + public function addHTTPWarning():void{ + httpWarning = new Sprite(); + var g:Graphics = httpWarning.graphics; + g.clear(); + g.beginFill(CSS.white); + g.drawRoundRect(10, 30, playButton.width - 20, 70, 15, 15); + g.endFill(); + httpWarning.alpha = 0.9; + + const versionFormat:TextFormat = new TextFormat(CSS.font, 16, 0x000000); + var httpWarningText:TextField = makeLabel("This project sends HTTP requests, through the “http” block. It is recommended that you watch what you enter into the project as It might be sent with HTTP to any website.", versionFormat, 15, 45); + httpWarningText.width = httpWarning.width - 10; + httpWarningText.multiline = true; + httpWarningText.wordWrap = true; + + httpWarning.addChild(httpWarningText); + playButton.addChild(httpWarning); + + httpWarning.visible = false; + } public function playButtonPressed(evt:MouseEvent):void { if(app.loadInProgress) { From 23acd93945e1d7fb932b72051b0b40214041e709 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Sat, 11 Jun 2016 21:07:50 +1000 Subject: [PATCH 070/141] ask and confirm blocks --- src/Specs.as | 4 ++++ src/primitives/SensingPrims.as | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/Specs.as b/src/Specs.as index a454b2485..1c202d8a4 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -291,6 +291,8 @@ public class Specs { ["answer", "r", 7, "answer"], ["-"], ["notify %s title %s", " ", 7, "notify:", "Hi!", "Hello!"], + ["ask %s with dialog %s", " ", 7, "askBox:", "What's your name?", "IDK"], + ["confirm %s", " ", 107, "confirm:", "Is Mrcomputer1 awesome?"], ["-"], ["key %m.key pressed?", "b", 7, "keyPressed:", "space"], ["mouse down?", "b", 7, "mousePressed"], @@ -327,6 +329,8 @@ public class Specs { ["answer", "r", 107, "answer"], ["-"], ["notify %s title %s", " ", 107, "notify:", "Hi!", "Hello!"], + ["ask %s with dialog %s", " ", 107, "askBox:", "What's your name?", "IDK"], + ["confirm %s", " ", 107, "confirm:", "Is Mrcomputer1 awesome?"], ["-"], ["key %m.key pressed?", "b", 107, "keyPressed:", "space"], ["mouse down?", "b", 107, "mousePressed"], diff --git a/src/primitives/SensingPrims.as b/src/primitives/SensingPrims.as index cac184325..70d0b7c33 100644 --- a/src/primitives/SensingPrims.as +++ b/src/primitives/SensingPrims.as @@ -78,6 +78,8 @@ public class SensingPrims { // Sharp primTable["notify:"] = primNotify; + primTable["askBox:"] = primAskBox; + primTable["confirm:"] = primConfirm; primTable["isInEditor:"] = function(b:*):* { return app.editMode }; primTable["isInFullscreen:"] = function(b:*):* { return app.isFullScreen }; primTable["usingTurboMode:"] = function(b:*):* { return interp.turboMode }; @@ -90,6 +92,25 @@ public class SensingPrims { dialogBoxActive++; DialogBox.notify(b[1],b[0],null,false, function(d:*):*{ dialogBoxActive--; }); } + private function primAskBox(b:Array):void{ + if(dialogBoxActive == dialogBoxAllowed) return; + dialogBoxActive++; + DialogBox.ask(b[0], b[1], null, function(ans:*):*{ + app.runtime.lastAnswer = ans; + dialogBoxActive--; + }); + } + private function primConfirm(b:Array):void{ + if(dialogBoxActive == dialogBoxAllowed) return; + dialogBoxActive++; + DialogBox.confirm(b[0], null, function(d:*):*{ + app.runtime.lastAnswer = "true"; + dialogBoxActive--; + }, function(d:*):*{ + app.runtime.lastAnswer = "false"; + dialogBoxActive--; + }); + } // TODO: move to stage static private var stageRect:Rectangle = new Rectangle(0, 0, 480, 360); From e70966b3f1424c6ad8571f22dfc7946d60ca733c Mon Sep 17 00:00:00 2001 From: Alexander Liu Date: Tue, 14 Jun 2016 14:54:50 +0700 Subject: [PATCH 071/141] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b0425ee78..2da3468df 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,6 @@ Version | Code Name | LTS | Released | Still supported | Suppo ------------------ | ---------------- | --- | -------- | --------------- | --------------- | ----------------------------- 1.0.0 (Release) | Katana | NO | NO | --NOT YET-- | --NOT YET-- | 1.0.0 Beta | Chainsaw | NO | NO | --NOT YET-- | --NOT YET-- | -1.1.0 Alpha | Sawtooth | NO | NO | --NOT YET-- | --NOT YET-- | -1.0.1 Alpha | Butterknife | NO | NO | --NOT YET-- | --NOT YET-- | Will replace 1.0.0 Alpha support +1.1.0 Alpha | Sawtooth | NO | YES | YES | --TBA-- | +1.0.1 Alpha | Butterknife | NO | YES | YES | --TBA-- | Will replace 1.0.0 Alpha support 1.0.0 Alpha | Butterknife | NO | YES | YES | 30 Oct 2016 | From aa4272ab6cce33969bcd7ec8c24e4c9c1c999325 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Wed, 15 Jun 2016 13:45:49 +1000 Subject: [PATCH 072/141] Update --- src/scratch/BlockMenus.as | 1 + 1 file changed, 1 insertion(+) diff --git a/src/scratch/BlockMenus.as b/src/scratch/BlockMenus.as index 430c47e21..ec95456fe 100644 --- a/src/scratch/BlockMenus.as +++ b/src/scratch/BlockMenus.as @@ -146,6 +146,7 @@ public class BlockMenus implements DragClient { handler.varMenu(evt); handler.videoMotionTypeMenu(evt); handler.videoStateMenu(evt); + handler.httpMethodMenu(evt); } return [ 'up arrow', 'down arrow', 'right arrow', 'left arrow', 'space', 'any', From 8d6e35667cecb5404a643fb55745b0445cdf5983 Mon Sep 17 00:00:00 2001 From: Scratchyone Date: Wed, 15 Jun 2016 20:38:17 -0400 Subject: [PATCH 073/141] Enabled already added 'Drop Anywhere' feature --- src/scratch/ScratchRuntime.as | 53 ++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/src/scratch/ScratchRuntime.as b/src/scratch/ScratchRuntime.as index 9874c68f5..88d8cb6d1 100644 --- a/src/scratch/ScratchRuntime.as +++ b/src/scratch/ScratchRuntime.as @@ -74,6 +74,7 @@ public class ScratchRuntime { public var cloneCount:int; public var edgeTriggersEnabled:Boolean = false; // initially false, becomes true when project first run public var currentDoObj:ScratchObj = null; + public var canDropAnywhere:Boolean = true; private var microphone:Microphone; private var timerBase:uint; @@ -172,7 +173,7 @@ public class ScratchRuntime { processEdgeTriggeredHats(); interp.stepThreads(); app.stagePane.commitPenStrokes(); - + if (ready==ReadyLabel.COUNTDOWN || ready==ReadyLabel.READY) { app.stagePane.countdown(count); } @@ -187,7 +188,7 @@ public class ScratchRuntime { private var videoPosition:int; private var videoSeconds:Number; private var videoAlreadyDone:int; - + private var projectSound:Boolean; private var micSound:Boolean; private var showCursor:Boolean; @@ -196,14 +197,14 @@ public class ScratchRuntime { private var videoWidth:int; private var videoHeight:int; public var ready:int=ReadyLabel.NOT_READY; - + private var micBytes:ByteArray; private var micPosition:int = 0; private var mic:Microphone; private var micReady:Boolean; - + private var timeout:int; - + private function saveFrame():void { saveSound(); var t:Number = getTimer()*.001-videoSeconds; @@ -282,7 +283,7 @@ public class ScratchRuntime { videoFrames.push(f); } } - + private function saveSound():void { var floats:Array = []; if (micSound && micBytes.length>0) { @@ -323,17 +324,17 @@ public class ScratchRuntime { videoSounds.push(combinedStream); combinedStream = null; } - - private function micSampleDataHandler(event:SampleDataEvent):void - { - while(event.data.bytesAvailable) + + private function micSampleDataHandler(event:SampleDataEvent):void + { + while(event.data.bytesAvailable) { - var sample:Number = event.data.readFloat(); - micBytes.writeFloat(sample); + var sample:Number = event.data.readFloat(); micBytes.writeFloat(sample); - } - } - + micBytes.writeFloat(sample); + } + } + public function startVideo(editor:RecordingSpecEditor):void { projectSound = editor.soundFlag(); micSound = editor.microphoneFlag(); @@ -345,10 +346,10 @@ public class ScratchRuntime { } micReady = true; if (micSound) { - mic = Microphone.getMicrophone(); + mic = Microphone.getMicrophone(); mic.setSilenceLevel(0); - mic.gain = editor.getMicVolume(); - mic.rate = 44; + mic.gain = editor.getMicVolume(); + mic.rate = 44; micReady=false; } if (fullEditor) { @@ -380,7 +381,7 @@ public class ScratchRuntime { baFlvEncoder.start(); waitAndStart(); } - + public function exportToVideo():void { var specEditor:RecordingSpecEditor = new RecordingSpecEditor(); function startCountdown():void { @@ -388,7 +389,7 @@ public class ScratchRuntime { } DialogBox.close("Record Project Video",null,specEditor,"Start",app.stage,startCountdown); } - + public function stopVideo():void { if (recording) videoTimer.dispatchEvent(new TimerEvent(TimerEvent.TIMER)); else if (ready==ReadyLabel.COUNTDOWN || ReadyLabel.READY) { @@ -397,7 +398,7 @@ public class ScratchRuntime { app.stagePane.countdown(0); } } - + public function finishVideoExport(event:TimerEvent):void { stopRecording(); stopAll(); @@ -406,7 +407,7 @@ public class ScratchRuntime { clearTimeout(timeout); timeout = setTimeout(saveRecording,1); } - + public function waitAndStart():void { if (!micReady && !mic.hasEventListener(StatusEvent.STATUS)) { micBytes = new ByteArray(); @@ -438,7 +439,7 @@ public class ScratchRuntime { videoTimer.addEventListener(TimerEvent.TIMER, finishVideoExport); videoTimer.start(); } - + public function stopRecording():void { recording = false; videoTimer.stop(); @@ -472,7 +473,7 @@ public class ScratchRuntime { videoSounds[videoPosition]=null; videoPosition++; } - if (app.lp) app.lp.setProgress(Math.min((videoPosition-videoAlreadyDone) / (videoFrames.length-videoAlreadyDone), 1)); + if (app.lp) app.lp.setProgress(Math.min((videoPosition-videoAlreadyDone) / (videoFrames.length-videoAlreadyDone), 1)); clearTimeout(timeout); timeout = setTimeout(saveRecording, 1); return; @@ -505,7 +506,7 @@ public class ScratchRuntime { } DialogBox.close("Video Finished!","To save, click the button below.",null,"Save and Download",app.stage,saveFile,releaseVideo,null,true); } - + private function roundToTens(x:Number):Number { return int((x)*10)/10.; } @@ -802,7 +803,7 @@ public class ScratchRuntime { } Scratch.loadSingleFile(fileLoadHandler, filter); } - + public function loadProjectFromURL(url:String, p:*):void { function doInstall(e:Event):void { installProjectFromFile(p['sharp_pid'], ByteArray(e.target.data)); From 2c53029d3ae3ca041faa186bcb424de4ee43bcb6 Mon Sep 17 00:00:00 2001 From: Scratchyone Date: Wed, 15 Jun 2016 20:40:05 -0400 Subject: [PATCH 074/141] Enabled already added 'Drop Anywhere' feature again --- src/scratch/ScratchRuntime.as | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scratch/ScratchRuntime.as b/src/scratch/ScratchRuntime.as index 88d8cb6d1..f09b5e338 100644 --- a/src/scratch/ScratchRuntime.as +++ b/src/scratch/ScratchRuntime.as @@ -74,7 +74,7 @@ public class ScratchRuntime { public var cloneCount:int; public var edgeTriggersEnabled:Boolean = false; // initially false, becomes true when project first run public var currentDoObj:ScratchObj = null; - public var canDropAnywhere:Boolean = true; + public var app.sharpSettings.data.hackMode:Boolean = true; private var microphone:Microphone; private var timerBase:uint; From 2fc6695a9db20917f7b935c39658b2c71f9edb8d Mon Sep 17 00:00:00 2001 From: Scratchyone Date: Wed, 15 Jun 2016 20:45:54 -0400 Subject: [PATCH 075/141] Enabled already added 'Drop Anywhere' feature again --- src/scratch/ScratchRuntime.as | 1 - src/uiwidgets/ScriptsPane.as | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/scratch/ScratchRuntime.as b/src/scratch/ScratchRuntime.as index f09b5e338..4e5610216 100644 --- a/src/scratch/ScratchRuntime.as +++ b/src/scratch/ScratchRuntime.as @@ -74,7 +74,6 @@ public class ScratchRuntime { public var cloneCount:int; public var edgeTriggersEnabled:Boolean = false; // initially false, becomes true when project first run public var currentDoObj:ScratchObj = null; - public var app.sharpSettings.data.hackMode:Boolean = true; private var microphone:Microphone; private var timerBase:uint; diff --git a/src/uiwidgets/ScriptsPane.as b/src/uiwidgets/ScriptsPane.as index cf267c42d..1ed49221c 100644 --- a/src/uiwidgets/ScriptsPane.as +++ b/src/uiwidgets/ScriptsPane.as @@ -366,10 +366,8 @@ return true; // xxx disable this check for now; it was causing confusion at Scra } private function dropCompatible(droppedBlock:Block, target:DisplayObject):Boolean { - if(app.sharpSettings.data.hackMode){ return true; //Credit liam4: This line of code was taken from their mod - } - + const menusThatAcceptReporters:Array = [ 'broadcast', 'costume', 'backdrop', 'scene', 'sound', 'spriteOnly', 'spriteOrMouse', 'location', 'spriteOrStage', 'touching']; From 36d7c8747ab31dec09233212582591f481d65fb8 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Thu, 16 Jun 2016 12:50:03 +1000 Subject: [PATCH 076/141] Re-added hack mode but with default value true --- src/Scratch.as | 15 ++++++++++++--- src/uiwidgets/ScriptsPane.as | 4 +++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/Scratch.as b/src/Scratch.as index 722548cee..4a0306950 100644 --- a/src/Scratch.as +++ b/src/Scratch.as @@ -81,17 +81,18 @@ public class Scratch extends Sprite { // Sharp settings store public var sharpSettings:SharedObject; - private var sharpSettingsVersion:int = 1; + private var sharpSettingsVersion:int = 2; private function initSettings():void{ if(!sharpSettings.data.hasOwnProperty("_settingsVersion")){ trace("Creating default setting values"); sharpSettings.data._settingsVersion = sharpSettingsVersion; sharpSettings.data.allowSound = true; sharpSettings.data.alwaysTurboMode = false; - sharpSettings.data.hackMode = false; + sharpSettings.data.hackMode = true; sharpSettings.data.cloneLimit = 300; + saveSettings(); }else{ - + updateSettings(); } prepareSettings(); } @@ -113,7 +114,15 @@ public class Scratch extends Sprite { /*if(sharpSettings.data._settingsVersion == (version to update from)){ trace("Updating settings from " + sharpSettings.data._settingsVersion + " to (version to update to)"); // do updates + trace("Updated!"); }*/ + if(sharpSettings.data._settingsVersion == 1){ + trace("Updating settings from " + sharpSettings.data._settingsVersion + " to 2"); + sharpSettings.data.hachMode = true; + sharpSettings.data._settingsVersion = 2; + saveSettings(); + trace("Updated!"); + } updateSettings(); //Runs to see if there are more updates } } diff --git a/src/uiwidgets/ScriptsPane.as b/src/uiwidgets/ScriptsPane.as index 1ed49221c..fa61587f6 100644 --- a/src/uiwidgets/ScriptsPane.as +++ b/src/uiwidgets/ScriptsPane.as @@ -366,8 +366,10 @@ return true; // xxx disable this check for now; it was causing confusion at Scra } private function dropCompatible(droppedBlock:Block, target:DisplayObject):Boolean { + if(app.sharpSettings.data.hackMode){ return true; //Credit liam4: This line of code was taken from their mod - + } + const menusThatAcceptReporters:Array = [ 'broadcast', 'costume', 'backdrop', 'scene', 'sound', 'spriteOnly', 'spriteOrMouse', 'location', 'spriteOrStage', 'touching']; From a20c10eac0b0ab448f042456deec622aabfd7aa2 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Fri, 17 Jun 2016 18:45:29 +1000 Subject: [PATCH 077/141] File stuff --- src/Specs.as | 6 ++++++ src/primitives/Primitives.as | 35 ++++++++++++++++++++++++++++++++++- src/ui/PaletteSelector.as | 2 +- 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/Specs.as b/src/Specs.as index 1c202d8a4..b25dcbc44 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -75,6 +75,7 @@ public class Specs { [11, "Parameter", parameterColor], [12, "List", listColor], [13, "HTTP", 0x55af40], + [14, "Files", 0x333399], [20, "Extension", extensionsColor], ]; @@ -416,6 +417,11 @@ public class Specs { // --HTTP-- ["%m.httpMethod %s", " ", 13, "httpBlock:", "GET", "https://api.scratch.mit.edu"], ["http return", "r", 13, "httpReturn:"], + // --Files-- + ["save %s to file %s", " ", 14, "saveFile:", ":)", "smileface.txt"], + ["load file", " ", 14, "loadFile:"], + ["loaded file name", "r", 14, "loadedFileName:"], + ["loaded file data", "r", 14, "loadedFileData:"], // Scratch diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index 230b04376..9034ab318 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -32,6 +32,7 @@ package primitives { import flash.net.*; import flash.events.Event; + import flash.utils.ByteArray; public class Primitives { @@ -42,7 +43,8 @@ public class Primitives { private var counter:int; private var httpReturn:String = ""; private var httpRequestsAllowed:int = 10; private var httpRequestsActive:int = 0; // TODO: Add "hidden" setting for HTTP requests allowed - + private var fileNameValue:String; private var fileDataValue:String; + public function Primitives(app:Scratch, interpreter:Interpreter) { this.app = app; this.interp = interpreter; @@ -94,6 +96,11 @@ public class Primitives { // Sharp -- HTTP primTable["httpBlock:"] = primHttp; primTable["httpReturn:"] = function(b:*):* {return httpReturn}; + // Sharp -- Files + primTable["saveFile:"] = primFileSave; + primTable["loadFile:"] = primFileLoad; + primTable["loadedFileName:"] = function(b:*):*{ return fileNameValue; }; + primTable["loadedFileData:"] = function(b:*):*{ return fileDataValue; }; new LooksPrims(app, interp).addPrimsTo(primTable, specialTable); new MotionAndPenPrims(app, interp).addPrimsTo(primTable, specialTable); @@ -265,4 +272,30 @@ public class Primitives { httpRequestsActive--; } } + //Sharp --- Files + private function primFileSave(b:Array):void{ + var file:FileReference = new FileReference(); + file.save(b[0], b[1]); + } + private function primFileLoad(b:Array):void{ + var fileName:String, data:ByteArray; + function fileLoaded(event:Event):void{ + var file:FileReference = FileReference(event.target); + fileName = file.name; + data = file.data; + + fileNameValue = fileName; + fileDataValue = data.readUTFBytes(data.bytesAvailable); + } + function fileSelected(event:Event):void{ + var file:FileReference = FileReference(fileList.fileList[0]); + file.addEventListener(Event.COMPLETE, fileLoaded); + file.load(); + } + var fileList:FileReferenceList = new FileReferenceList(); + fileList.addEventListener(Event.SELECT, fileSelected); + try{ + fileList.browse(null); + }catch(e:*){} + } }} diff --git a/src/ui/PaletteSelector.as b/src/ui/PaletteSelector.as index 945148225..b10404996 100644 --- a/src/ui/PaletteSelector.as +++ b/src/ui/PaletteSelector.as @@ -33,7 +33,7 @@ public class PaletteSelector extends Sprite { private static const categories:Array = [ 'Motion', 'Looks', 'Sound', 'Pen', 'Data', 'HTTP', // column 1 - 'Events', 'Control', 'Sensing', 'Operators', 'More Blocks']; // column 2 + 'Events', 'Control', 'Sensing', 'Operators', 'More Blocks', 'Files']; // column 2 public var selectedCategory:int = 0; private var app:Scratch; From 5adffb0dba4bbe6f8e1daa8210c7ba1bbe834f7c Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Fri, 17 Jun 2016 18:57:01 +1000 Subject: [PATCH 078/141] Something --- src/primitives/Primitives.as | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index 9034ab318..8ad1de638 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -258,7 +258,7 @@ public class Primitives { private function primHttp(b:Array):void { if(httpRequestsActive == httpRequestsAllowed) return; httpRequestsActive++; - var url:String = b[0]; + var url:String = b[1]; var req:URLRequest = new URLRequest(url); req.method = URLRequestMethod.GET; @@ -268,7 +268,7 @@ public class Primitives { loader.load(req); function onComplete(e:Event){ - httpReturn = e.target.data; + httpReturn = e.target.data.readUTFBytes(e.target.data.bytesAvailable); httpRequestsActive--; } } From c5ef376dc4e45d36b7c28b170362876a4c7176d3 Mon Sep 17 00:00:00 2001 From: DrKat123 Date: Wed, 22 Jun 2016 17:08:07 +0700 Subject: [PATCH 079/141] Commits --- package.json | 4 ++-- src/Specs.as | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 860d58f59..6a822e56c 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { - "name": "Scratch", + "name": "Sharp", "description": "Open source version of the Scratch 2.0 project editor.", "version": "1.0.0", - "homepage": "http://scratch.mit.edu/", + "homepage": "sharpscratchmod.cf", "main": "scratch-flash", "license": "GPL-2.0", "repository": { diff --git a/src/Specs.as b/src/Specs.as index b25dcbc44..1a6193064 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -318,7 +318,7 @@ public class Specs { ["-"], ["current %m.timeAndDate", "r", 7, "timeAndDate", "minute"], ["days since 2000", "r", 7, "timestamp"], - //["username", "r", 7, "getUserName"], + //["username", "r", 7, "getUserName"] //---- //NOTE: @@ -356,7 +356,7 @@ public class Specs { ["-"], ["current %m.timeAndDate", "r", 107, "timeAndDate", "minute"], ["days since 2000", "r", 107, "timestamp"], - ["username", "r", 107, "getUserName"], + //["username", "r", 107, "getUserName"], // operators ["%n + %n", "r", 8, "+", "", ""], @@ -390,6 +390,7 @@ public class Specs { ["reverse %s", "r", 8, "reverseString:", "hello"], ["split %s from letter %n to %n", "r", 8, "splitStringFrom:", "Foobar", "1", "3"], + // variables ["set %m.var to %s", " ", 9, SET_VAR], ["change %m.var by %n", " ", 9, CHANGE_VAR], From c37e36a31a8f715375c39283c29372635ef4aca4 Mon Sep 17 00:00:00 2001 From: DrKat123 Date: Wed, 22 Jun 2016 17:22:27 +0700 Subject: [PATCH 080/141] Digital Roots (attempt #2) --- src/Specs.as | 1 + src/primitives/Primitives.as | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Specs.as b/src/Specs.as index 1a6193064..6a844ee99 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -386,6 +386,7 @@ public class Specs { ["round %n", "r", 8, "rounded", ""], ["-"], ["%m.mathOp of %n", "r", 8, "computeFunction:of:", "sqrt", 9], + ["digital root of %n," "r", 8, "digitalRootOf:", "1234"], ["the constant %m.constantName", "r", 8, "chooseConstant:", "Pi"], ["reverse %s", "r", 8, "reverseString:", "hello"], ["split %s from letter %n to %n", "r", 8, "splitStringFrom:", "Foobar", "1", "3"], diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index 8ad1de638..d917c35e7 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -72,7 +72,7 @@ public class Primitives { primTable["concatenate:with:"] = function(b:*):* { return ("" + b[0] + b[1]).substr(0, 10240); }; primTable["letter:of:"] = primLetterOf; primTable["stringLength:"] = function(b:*):* { return String(b[0]).length }; - + primTable["digitalRootOf:"] = primDigitalRoot; primTable["%"] = primModulo; primTable["rounded"] = function(b:*):* { return Math.round(interp.numarg(b[0])) }; primTable["computeFunction:of:"] = primMathFunction; @@ -298,4 +298,11 @@ public class Primitives { fileList.browse(null); }catch(e:*){} } + private function primDigitalRoot(b:Array):Number{ + if(interp.numarg(b[0]) < 9){ + return interp.numarg(b[0]) + } else { + return interp.numarg(b[0]) - (9 * Math.floor((interp.numarg(b[0])-1)/9)); + } + } }} From f9de2a7cbb807f373ba1283635509103507d0848 Mon Sep 17 00:00:00 2001 From: DrKat123 Date: Wed, 22 Jun 2016 17:29:38 +0700 Subject: [PATCH 081/141] fixes for previous commit --- src/Specs.as | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Specs.as b/src/Specs.as index 6a844ee99..f889c3b47 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -386,7 +386,7 @@ public class Specs { ["round %n", "r", 8, "rounded", ""], ["-"], ["%m.mathOp of %n", "r", 8, "computeFunction:of:", "sqrt", 9], - ["digital root of %n," "r", 8, "digitalRootOf:", "1234"], + ["digital root of %n", "r", 8, "digitalRootOf:", "1234"], ["the constant %m.constantName", "r", 8, "chooseConstant:", "Pi"], ["reverse %s", "r", 8, "reverseString:", "hello"], ["split %s from letter %n to %n", "r", 8, "splitStringFrom:", "Foobar", "1", "3"], From b946fb0bf7973f760eb824c514d92696851dd92c Mon Sep 17 00:00:00 2001 From: DrKat123 Date: Wed, 22 Jun 2016 18:04:47 +0700 Subject: [PATCH 082/141] update version --- src/Scratch.as | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Scratch.as b/src/Scratch.as index 4a0306950..e5f2c99cc 100644 --- a/src/Scratch.as +++ b/src/Scratch.as @@ -76,7 +76,7 @@ import watchers.ListWatcher; public class Scratch extends Sprite { // Version - public static const versionString:String = 'Alpha 1.1.0 (Sawtooth) : Scratch v447.2'; + public static const versionString:String = 'Alpha 1.1.5 (Sawtooth) : Scratch v447.2'; public static var app:Scratch; // static reference to the app, used for debugging // Sharp settings store From 3840b3e2d8ef7c3ba2cff758d481a4917a087054 Mon Sep 17 00:00:00 2001 From: DrKat123 Date: Thu, 23 Jun 2016 13:33:57 +0700 Subject: [PATCH 083/141] updates --- README.md | 1 + src/Scratch.as | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2da3468df..e7ec8023c 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ Version | Code Name | LTS | Released | Still supported | Suppo ------------------ | ---------------- | --- | -------- | --------------- | --------------- | ----------------------------- 1.0.0 (Release) | Katana | NO | NO | --NOT YET-- | --NOT YET-- | 1.0.0 Beta | Chainsaw | NO | NO | --NOT YET-- | --NOT YET-- | +1.1.5 Alpha | Sawtooth | NO | YES | YES | --TBA-- | 1.1.0 Alpha | Sawtooth | NO | YES | YES | --TBA-- | 1.0.1 Alpha | Butterknife | NO | YES | YES | --TBA-- | Will replace 1.0.0 Alpha support 1.0.0 Alpha | Butterknife | NO | YES | YES | 30 Oct 2016 | diff --git a/src/Scratch.as b/src/Scratch.as index e5f2c99cc..38b203f19 100644 --- a/src/Scratch.as +++ b/src/Scratch.as @@ -620,7 +620,7 @@ public class Scratch extends Sprite { public function strings():Array { return [ 'a copy of the project file on your computer.', - 'Project not saved!', 'Save now', 'Not saved; project did not load.', + 'Project not saved!', 'Save now', 'Not saved; project didn\'t load.', 'Save project?', 'Don\'t save', 'Save now', 'Saved', 'Revert', 'Undo Revert', 'Reverting...', From 0caa72c31bc5309866d1983e6f01bda74e5946f8 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Fri, 24 Jun 2016 22:58:22 +1000 Subject: [PATCH 084/141] Update --- src/Specs.as | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Specs.as b/src/Specs.as index f889c3b47..2742abe52 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -293,7 +293,7 @@ public class Specs { ["-"], ["notify %s title %s", " ", 7, "notify:", "Hi!", "Hello!"], ["ask %s with dialog %s", " ", 7, "askBox:", "What's your name?", "IDK"], - ["confirm %s", " ", 107, "confirm:", "Is Mrcomputer1 awesome?"], + ["confirm %s", " ", 7, "confirm:", "Is Mrcomputer1 awesome?"], ["-"], ["key %m.key pressed?", "b", 7, "keyPressed:", "space"], ["mouse down?", "b", 7, "mousePressed"], From 05a4077b5a1333e828a0e845375aa7eb963e35fd Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Thu, 7 Jul 2016 22:25:29 +1000 Subject: [PATCH 085/141] Replace block --- src/Specs.as | 2 +- src/primitives/Primitives.as | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Specs.as b/src/Specs.as index 2742abe52..87bfc9467 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -389,9 +389,9 @@ public class Specs { ["digital root of %n", "r", 8, "digitalRootOf:", "1234"], ["the constant %m.constantName", "r", 8, "chooseConstant:", "Pi"], ["reverse %s", "r", 8, "reverseString:", "hello"], + ["replace %s in %s with %s", "r", 8, "blockReplace:", "Hi", "Hi", "Hello"], ["split %s from letter %n to %n", "r", 8, "splitStringFrom:", "Foobar", "1", "3"], - // variables ["set %m.var to %s", " ", 9, SET_VAR], ["change %m.var by %n", " ", 9, CHANGE_VAR], diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index d917c35e7..9e373307e 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -93,6 +93,7 @@ public class Primitives { primTable["inlineComment:"] = function(b:*):* {}; primTable["true"] = function(b:*):* {return true}; primTable["false"] = function(b:*):* {return false}; + primTable["blockReplace:"] = primStrReplace; // Sharp -- HTTP primTable["httpBlock:"] = primHttp; primTable["httpReturn:"] = function(b:*):* {return httpReturn}; @@ -254,6 +255,10 @@ public class Primitives { return result; } + // Sharp + private function primStrReplace(b:Array):String{ + return b[1].replace(new RegExp(b[0], "g"), b[2]); + } // Sharp --- HTTP private function primHttp(b:Array):void { if(httpRequestsActive == httpRequestsAllowed) return; From 6349c9860069cf17de9c0e29de476c749eddec8a Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Fri, 8 Jul 2016 17:06:31 +1000 Subject: [PATCH 086/141] Added split --- src/Specs.as | 2 ++ src/primitives/ListPrims.as | 18 ++++++++++++++++++ src/primitives/Primitives.as | 5 +++++ 3 files changed, 25 insertions(+) diff --git a/src/Specs.as b/src/Specs.as index 87bfc9467..b8d21f1c6 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -390,6 +390,8 @@ public class Specs { ["the constant %m.constantName", "r", 8, "chooseConstant:", "Pi"], ["reverse %s", "r", 8, "reverseString:", "hello"], ["replace %s in %s with %s", "r", 8, "blockReplace:", "Hi", "Hi", "Hello"], + ["split %s at %s and return to %m.list"," ", 8, "blockSplit:", "H i", " ", ""], + ["split %s at %s and return %n", "r", 8, "blockSplitReturn:", "H i", " ", 1], ["split %s from letter %n to %n", "r", 8, "splitStringFrom:", "Foobar", "1", "3"], // variables diff --git a/src/primitives/ListPrims.as b/src/primitives/ListPrims.as index 20c68bde0..7adf1da64 100644 --- a/src/primitives/ListPrims.as +++ b/src/primitives/ListPrims.as @@ -48,6 +48,7 @@ public class ListPrims { primTable['getLine:ofList:'] = primGetItem; primTable['lineCountOfList:'] = primLength; primTable['list:contains:'] = primContains; + primTable["blockSplit:"] = primSharpBlockSplit; } private function primContents(b:Array):String { @@ -69,6 +70,23 @@ public class ListPrims { listAppend(list, b[0]); if (list.visible) list.updateWatcher(list.contents.length, false, interp); } + /* + Sharp + */ + private function primSharpBlockSplit(b:Array):void{ + var list:ListWatcher = listarg(b[2]); + if (!list) return; + var s = b[0].split(b[1]); + var i = 0; + while(i != s.length){ + listAppend(list, s[i]); + i++; + } + if(list.visible) list.updateWatcher(list.contents.length, false, interp); + } + /* + /Sharp + */ protected function listAppend(list:ListWatcher, item:*):void { list.contents.push(item); diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index 9e373307e..71faaa3f4 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -33,6 +33,9 @@ package primitives { import flash.net.*; import flash.events.Event; import flash.utils.ByteArray; + + import mx.utils.Base64Encoder; + import mx.utils.Base64Decoder; public class Primitives { @@ -94,6 +97,8 @@ public class Primitives { primTable["true"] = function(b:*):* {return true}; primTable["false"] = function(b:*):* {return false}; primTable["blockReplace:"] = primStrReplace; + primTable["blockSplitReturn:"] = function(b:*):* {return b[0].split(b[1])[b[2]-1]}; + primTable["cleanStr:"] = primCleanStr; // Sharp -- HTTP primTable["httpBlock:"] = primHttp; primTable["httpReturn:"] = function(b:*):* {return httpReturn}; From b08c8d0beb8130115b138640174a1eb9d1cc0636 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Fri, 8 Jul 2016 17:22:18 +1000 Subject: [PATCH 087/141] Fix --- src/primitives/Primitives.as | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index 71faaa3f4..51d5de3e2 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -36,6 +36,7 @@ package primitives { import mx.utils.Base64Encoder; import mx.utils.Base64Decoder; + import public class Primitives { @@ -98,7 +99,6 @@ public class Primitives { primTable["false"] = function(b:*):* {return false}; primTable["blockReplace:"] = primStrReplace; primTable["blockSplitReturn:"] = function(b:*):* {return b[0].split(b[1])[b[2]-1]}; - primTable["cleanStr:"] = primCleanStr; // Sharp -- HTTP primTable["httpBlock:"] = primHttp; primTable["httpReturn:"] = function(b:*):* {return httpReturn}; From 668bd990351b21ea95f3ad3ae613f446479f0138 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Fri, 8 Jul 2016 17:22:43 +1000 Subject: [PATCH 088/141] Fix again --- src/primitives/Primitives.as | 1 - 1 file changed, 1 deletion(-) diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index 51d5de3e2..df4edf567 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -36,7 +36,6 @@ package primitives { import mx.utils.Base64Encoder; import mx.utils.Base64Decoder; - import public class Primitives { From 2eb5dc910d1ef964b61c485aca49e0b3461e1c5b Mon Sep 17 00:00:00 2001 From: DrKat123 Date: Sat, 25 Jun 2016 11:59:07 +0700 Subject: [PATCH 089/141] update --- src/svgutils/SVGExport.as | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/svgutils/SVGExport.as b/src/svgutils/SVGExport.as index 6fd540bef..161070e08 100644 --- a/src/svgutils/SVGExport.as +++ b/src/svgutils/SVGExport.as @@ -66,7 +66,8 @@ public class SVGExport { XML.ignoreComments = false; rootNode = new XML("\n" + - "\n"+ + "\n"+ + "\n"+ ""); setSVGWidthAndHeight(); for each (var subEl:SVGElement in rootEl.subElements) { From e872b531e1439515660974cc145dacc7f897c88a Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Fri, 22 Jul 2016 21:52:19 +1000 Subject: [PATCH 090/141] Added some buttons --- src/Scratch.as | 5 +++++ src/blocks/Block.as | 15 +++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/Scratch.as b/src/Scratch.as index 53f700628..ac14258f0 100644 --- a/src/Scratch.as +++ b/src/Scratch.as @@ -1176,6 +1176,11 @@ public class Scratch extends Sprite { m.addLine(); m.addItem('Credits', helpMenuItemCredits); m.addItem('About', helpMenuItemAbout); + if(b.lastEvent.shiftKey){ + m.addLine(); + m.addItem("Export blocks (commands.txt)", TranslatableStrings.exportCommands); + m.addItem("Export ui strings (uiStrings.txt)", TranslatableStrings.exportUIStrings); + } } public var fullscreenEditor:Boolean = false; diff --git a/src/blocks/Block.as b/src/blocks/Block.as index 03a31f5c5..9af82e3a0 100644 --- a/src/blocks/Block.as +++ b/src/blocks/Block.as @@ -843,7 +843,7 @@ public class Block extends Sprite { } public function showHelp():void { - var extName:String = ExtensionManager.unpackExtensionName(op); + /*var extName:String = ExtensionManager.unpackExtensionName(op); if (extName) { if (Scratch.app.extensionManager.isInternal(extName)) { Scratch.app.showTip('ext:' + extName); @@ -857,7 +857,18 @@ public class Block extends Sprite { } else { Scratch.app.showTip(op); - } + }*/ + var mappings = { + // Control - Sprite/Stage + "inlineComment:": "control:inlineComment", + "codeSection": "control:codeSection", + "doForLoop": "control:doForLoop", + "COUNT": "control:COUNT", + "CLR_COUNT": "control:CLR_COUNT", + "INCR_COUNT": "control:INCR_COUNT", + // Sensing + "notify:": "sensing:notify" + }; } public function duplicateStack(deltaX:Number, deltaY:Number):void { From 4e13fe1a504c15ea9afa5480714731b343f87d51 Mon Sep 17 00:00:00 2001 From: DrKat123 Date: Sun, 24 Jul 2016 15:50:24 +0700 Subject: [PATCH 091/141] Insignificant update 1 ignore --- src/Specs.as | 17 ++++++++--- src/primitives/Primitives.as | 56 +++++++++++++++++++++++++++++------- 2 files changed, 59 insertions(+), 14 deletions(-) diff --git a/src/Specs.as b/src/Specs.as index b8d21f1c6..7f10e6feb 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -373,7 +373,15 @@ public class Specs { ["-"], ["%b and %b", "b", 8, "&"], ["%b or %b", "b", 8, "|"], - ["not %b", "b", 8, "not"], + ["not %b", "b", 8, "~"], + //secret beta update blocks + //--- + ["%b nand %b", "b", 8, "nand"], + //["%b nor %b", "b", 8, "nor"], + ["%b xor %b", "b", 8, "xor"], + ["%b xnor %b", "b", 8, "xnor"], + //this is supposed to be a secret but if you did find this, well, congratulations + //you just spoiled the secret update ["-"], ["true", "b", 8, "true"], ["false", "b", 8, "false"], @@ -387,7 +395,7 @@ public class Specs { ["-"], ["%m.mathOp of %n", "r", 8, "computeFunction:of:", "sqrt", 9], ["digital root of %n", "r", 8, "digitalRootOf:", "1234"], - ["the constant %m.constantName", "r", 8, "chooseConstant:", "Pi"], + ["the constant %m.constantName", "r", 8, "chooseConstant:", "Pi"], ["reverse %s", "r", 8, "reverseString:", "hello"], ["replace %s in %s with %s", "r", 8, "blockReplace:", "Hi", "Hi", "Hello"], ["split %s at %s and return to %m.list"," ", 8, "blockSplit:", "H i", " ", ""], @@ -413,7 +421,7 @@ public class Specs { ["-"], ["show list %m.list", " ", 12, "showList:"], ["hide list %m.list", " ", 12, "hideList:"], - + // custom blocks ["report %s", "f", 10, "report", ""], @@ -426,7 +434,8 @@ public class Specs { ["load file", " ", 14, "loadFile:"], ["loaded file name", "r", 14, "loadedFileName:"], ["loaded file data", "r", 14, "loadedFileData:"], - + + // Scratch // obsolete blocks from Scratch 1.4 that may be used in older projects diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index df4edf567..b2acdc9ea 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -29,11 +29,11 @@ package primitives { import interpreter.*; import scratch.ScratchSprite; import translation.Translator; - + import flash.net.*; import flash.events.Event; import flash.utils.ByteArray; - + import mx.utils.Base64Encoder; import mx.utils.Base64Decoder; @@ -47,7 +47,7 @@ public class Primitives { private var httpReturn:String = ""; private var httpRequestsAllowed:int = 10; private var httpRequestsActive:int = 0; // TODO: Add "hidden" setting for HTTP requests allowed private var fileNameValue:String; private var fileDataValue:String; - + public function Primitives(app:Scratch, interpreter:Interpreter) { this.app = app; this.interp = interpreter; @@ -65,7 +65,16 @@ public class Primitives { primTable[">"] = function(b:*):* { return compare(b[0], b[1]) > 0 }; primTable["&"] = function(b:*):* { return interp.boolarg(b[0]) && interp.boolarg(b[1]) }; primTable["|"] = function(b:*):* { return interp.boolarg(b[0]) || interp.boolarg(b[1]) }; - primTable["not"] = function(b:*):* { return !interp.boolarg(b[0]) }; + primTable["~"] = function(b:*):* { return !interp.boolarg(b[0]) }; + + //testing functions for moar logic gates + //don't spoil the secret update! + //Shhh + //--- + primTable["nand"] = function(b:*):* { return !(interp.boolarg(b[0]) && interp.boolarg(b[1])) }; + primTable["nor"] = primLogicNor; + primTable["xor"] = primLogicXor; + primTable["xnor"] = primLogicXnor; primTable["abs"] = function(b:*):* { return Math.abs(interp.numarg(b[0])) }; primTable["sqrt"] = function(b:*):* { return Math.sqrt(interp.numarg(b[0])) }; primTable["power:of:"] = function(b:*):* { return Math.pow(interp.numarg(b[0]), interp.numarg(b[1])) }; @@ -91,7 +100,7 @@ public class Primitives { primTable["COUNT"] = function(b:*):* { return counter }; primTable["INCR_COUNT"] = function(b:*):* { counter++ }; primTable["CLR_COUNT"] = function(b:*):* { counter = 0 }; - + // Sharp primTable["inlineComment:"] = function(b:*):* {}; primTable["true"] = function(b:*):* {return true}; @@ -106,7 +115,7 @@ public class Primitives { primTable["loadFile:"] = primFileLoad; primTable["loadedFileName:"] = function(b:*):*{ return fileNameValue; }; primTable["loadedFileData:"] = function(b:*):*{ return fileDataValue; }; - + new LooksPrims(app, interp).addPrimsTo(primTable, specialTable); new MotionAndPenPrims(app, interp).addPrimsTo(primTable, specialTable); new SoundPrims(app, interp).addPrimsTo(primTable, specialTable); @@ -239,7 +248,7 @@ public class Primitives { return result; } - + private function primGetConstant(b:Array):Number { var pickConstant:* = b[0]; switch(pickConstant) { @@ -270,12 +279,12 @@ public class Primitives { var url:String = b[1]; var req:URLRequest = new URLRequest(url); req.method = URLRequestMethod.GET; - + var loader:URLLoader = new URLLoader(); loader.addEventListener(Event.COMPLETE, onComplete); loader.dataFormat = URLLoaderDataFormat.TEXT; loader.load(req); - + function onComplete(e:Event){ httpReturn = e.target.data.readUTFBytes(e.target.data.bytesAvailable); httpRequestsActive--; @@ -292,7 +301,7 @@ public class Primitives { var file:FileReference = FileReference(event.target); fileName = file.name; data = file.data; - + fileNameValue = fileName; fileDataValue = data.readUTFBytes(data.bytesAvailable); } @@ -314,4 +323,31 @@ public class Primitives { return interp.numarg(b[0]) - (9 * Math.floor((interp.numarg(b[0])-1)/9)); } } + + + private function primLogicNor(b:Array):Boolean{ + if((interp.boolarg(b[0]) == false) && (interp.boolarg(b[1]) == false)){ + return true; + } else { + return false; + }; + return false; + } + + private function primLogicXor(b:Array):Boolean{ + if(interp.boolarg(b[0]) !== interp.boolarg(b[1])){ + return true; + } else if (interp.boolarg(b[0]) == interp.boolarg(b[1])) { + return false; + //comment + } + + private function primLogicXnor(b:Array):Boolean{ + if (interp.boolarg(b[0]) == interp.boolarg(b[1])) { + return true; + } else { + return false; + } + return false; + } }} From 847a8835db54d7a1fdbd43194a3777aa63331cc4 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Mon, 25 Jul 2016 13:49:36 +1000 Subject: [PATCH 092/141] Updated translatable strings --- src/Scratch.as | 27 ++++++++++++------ src/primitives/Primitives.as | 4 ++- src/translation/TranslatableStrings.as | 2 ++ src/ui/parts/TopBarPart.as | 2 +- src/uiwidgets/DialogBox.as | 39 +++++++++++++++++--------- 5 files changed, 49 insertions(+), 25 deletions(-) diff --git a/src/Scratch.as b/src/Scratch.as index ac14258f0..4140e018b 100644 --- a/src/Scratch.as +++ b/src/Scratch.as @@ -118,7 +118,7 @@ public class Scratch extends Sprite { }*/ if(sharpSettings.data._settingsVersion == 1){ trace("Updating settings from " + sharpSettings.data._settingsVersion + " to 2"); - sharpSettings.data.hachMode = true; + sharpSettings.data.hackMode = true; sharpSettings.data._settingsVersion = 2; saveSettings(); trace("Updated!"); @@ -1147,18 +1147,27 @@ public class Scratch extends Sprite { runtime.stopVideo(); } + public function sharpStrings(){ + return [ + "Credits", "*Owner, # Non-Sharp Member", + "Based on Scratch 2.0 from the MIT Media Lab", + "Sharp Scratch mod by DrKat123, Mrcomputer1 and some others", + "About Sharp", "Report a bug", "Credits", "About" + ]; + } + protected function addHelpMenuItems(b:*, m:Menu):void { function helpMenuItemCredits(){ - DialogBox.notify("Credits", "*Owner, # Non-Sharp Member\n\nDrKat123*, Mrcomputer1*, scratchyone\n\nNoMod-Programming#"); + DialogBox.notify("Credits", Translator.map("*Owner, # Non-Sharp Member") + "\n\nDrKat123*, Mrcomputer1*, scratchyone\n\nNoMod-Programming#"); } function helpMenuItemReportBug(){ DialogBox.reportBugDialog(); } function helpMenuItemAbout(){ var aboutMsg:String = "Scratch\n" + - "Based on Scratch from the MIT Media Lab, 2.0 v446\n" + + Translator.map("Based on Scratch 2.0 from the MIT Media Lab") + "\n" + "\n" + - "Scratch is developed by the Lifelong Kindergarten Group at the MIT Media Lab\n" + + Translator.map("Scratch is developed by the Lifelong Kindergarten Group at the MIT Media Lab") + "\n" + "\n" + "https://scratch.mit.edu - https://github.com/llk/scratch-flash\n" + "\n" + @@ -1167,15 +1176,15 @@ public class Scratch extends Sprite { "\n" + "\n" + "Sharp\n" + - "Sharp Scratch mod by DrKat123, Mrcomputer1 and some others\n" + + Translator.map("Sharp Scratch mod by DrKat123, Mrcomputer1 and some others") + "\n" + "https://sharpscratchmod.github.io\n" + versionString; - DialogBox.notify("About Sharp", aboutMsg); + DialogBox.notify(Translator.map("About Sharp"), aboutMsg); } - m.addItem('Report a bug', helpMenuItemReportBug); + m.addItem(Translator.map('Report a bug'), helpMenuItemReportBug); m.addLine(); - m.addItem('Credits', helpMenuItemCredits); - m.addItem('About', helpMenuItemAbout); + m.addItem(Translator.map('Credits'), helpMenuItemCredits); + m.addItem(Translator.map('About'), helpMenuItemAbout); if(b.lastEvent.shiftKey){ m.addLine(); m.addItem("Export blocks (commands.txt)", TranslatableStrings.exportCommands); diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index b2acdc9ea..2232e16c2 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -339,7 +339,9 @@ public class Primitives { return true; } else if (interp.boolarg(b[0]) == interp.boolarg(b[1])) { return false; - //comment + } else { + return false; + } } private function primLogicXnor(b:Array):Boolean{ diff --git a/src/translation/TranslatableStrings.as b/src/translation/TranslatableStrings.as index 56cc745ad..032964b71 100644 --- a/src/translation/TranslatableStrings.as +++ b/src/translation/TranslatableStrings.as @@ -117,6 +117,7 @@ public class TranslatableStrings { addAll(ProjectIO.strings()); // Get the strings from the Scratch app instance so that the offline version can add strings addAll(Scratch.app.strings()); + addAll(Scratch.app.sharpStrings()); addAll(ScriptsPane.strings()); addAll(SoundEditor.strings()); addAll(SoundsPart.strings()); @@ -128,6 +129,7 @@ public class TranslatableStrings { addAll(VariableSettings.strings()); addAll(Watcher.strings()); addAll(CameraDialog.strings()); + addAll(DialogBox.sharpDialogStrings()); Menu.stringCollectionMode = false; export('uiStrings'); diff --git a/src/ui/parts/TopBarPart.as b/src/ui/parts/TopBarPart.as index ee9cb7706..bb611e0e9 100644 --- a/src/ui/parts/TopBarPart.as +++ b/src/ui/parts/TopBarPart.as @@ -95,7 +95,7 @@ public class TopBarPart extends UIPart { Scratch.app.showEditMenu(Menu.dummyButton()); Scratch.app.showHelpMenu(Menu.dummyButton()); } - return ['File', 'Edit', 'Tips', 'Duplicate', 'Delete', 'Grow', 'Shrink', 'Block help', 'Offline Editor']; + return ['File', 'Edit', "Help", 'Tips', 'Duplicate', 'Delete', 'Grow', 'Shrink', 'Block help', 'Offline Editor']; } protected function removeTextButtons():void { diff --git a/src/uiwidgets/DialogBox.as b/src/uiwidgets/DialogBox.as index d82162eda..076fe592e 100644 --- a/src/uiwidgets/DialogBox.as +++ b/src/uiwidgets/DialogBox.as @@ -62,6 +62,17 @@ public class DialogBox extends Sprite { addEventListener(KeyboardEvent.KEY_DOWN, keyDown); addEventListener(FocusEvent.KEY_FOCUS_CHANGE, focusChange); } + + public static function sharpDialogStrings():Array{ + return [ + "Title", "Content", + "Report Bug", "Cancel", + "Report a bug", "Settings", + "Allow sound", "Always in turbo mode", + "Hack mode", "Clone limit", "OK", "Reset Settings", + "Do you really want to reset settings?" + ]; + } public static function ask(question:String, defaultAnswer:String, stage:Stage = null, resultFunction:Function = null, context:Dictionary = null):void { function done():void { if (resultFunction != null) resultFunction(d.fields['answer'].text) } @@ -94,13 +105,13 @@ public class DialogBox extends Sprite { public static function reportBugDialog():void{ var d:DialogBox = new DialogBox(done); function done():void { - var request:URLRequest = new URLRequest("https://github.com/SharpScratchMod/Sharp/issues/new?title=" + d.fields['title'].text + "&body=" + d.fields["body"].text); + var request:URLRequest = new URLRequest("https://github.com/SharpScratchMod/Sharp/issues/new?title=" + d.fields['Title'].text + "&body=" + d.fields["Content"].text); navigateToURL(request, "_blank"); } d.addTitle("Report a bug"); - d.addField("title", 120, "", true, "Title"); - d.addField("body", 120, "", true, "Content"); - d.addButton("Report bug", d.accept); + d.addField("Title", 120, "", true); + d.addField("Content", 120, "", true); + d.addButton("Report Bug", d.accept); d.addButton("Cancel", d.cancel); d.showOnStage(Scratch.app.stage); } @@ -108,21 +119,21 @@ public class DialogBox extends Sprite { public static function settingsDialog():void{ var d:DialogBox = new DialogBox(done); function done():void { - Scratch.app.sharpSettings.data.allowSound = d.booleanFields['sound'].isOn(); - Scratch.app.sharpSettings.data.alwaysTurboMode = d.booleanFields['alwaysTurboMode'].isOn(); - if(d.booleanFields['alwaysTurboMode'].isOn() && !Scratch.app.turboModeIsActive) Scratch.app.toggleTurboMode(); - Scratch.app.sharpSettings.data.hackMode = d.booleanFields['hackMode'].isOn(); - Scratch.app.sharpSettings.data.cloneLimit = d.fields['cloneLimit'].text; + Scratch.app.sharpSettings.data.allowSound = d.booleanFields['Allow sound'].isOn(); + Scratch.app.sharpSettings.data.alwaysTurboMode = d.booleanFields['Always in turbo mode'].isOn(); + if(d.booleanFields['Always in turbo mode'].isOn() && !Scratch.app.turboModeIsActive) Scratch.app.toggleTurboMode(); + Scratch.app.sharpSettings.data.hackMode = d.booleanFields['Hack mode'].isOn(); + Scratch.app.sharpSettings.data.cloneLimit = d.fields['Clone limit'].text; Scratch.app.saveSettings(); } function resetSettings():void { - DialogBox.confirm("Do you really want to reset settings?", null, function():*{ Scratch.app.resetSettings(); }); + DialogBox.confirm(Translator.map("Do you really want to reset settings?"), null, function():*{ Scratch.app.resetSettings(); }); } d.addTitle("Settings"); - d.addBoolean("sound", Scratch.app.sharpSettings.data.allowSound, false, "Allow sound"); - d.addBoolean("alwaysTurboMode", Scratch.app.sharpSettings.data.alwaysTurboMode, false, "Always in turbo mode"); - d.addBoolean("hackMode", Scratch.app.sharpSettings.data.hackMode, false, "Hack mode"); - d.addField("cloneLimit", 120, Scratch.app.sharpSettings.data.cloneLimit, true, "Clone limit"); + d.addBoolean("Allow sound", Scratch.app.sharpSettings.data.allowSound, false); + d.addBoolean("Always in turbo mode", Scratch.app.sharpSettings.data.alwaysTurboMode, false); + d.addBoolean("Hack mode", Scratch.app.sharpSettings.data.hackMode, false); + d.addField("Clone limit", 120, Scratch.app.sharpSettings.data.cloneLimit, true); d.addButton("OK", d.accept); d.addButton("Cancel", d.cancel); d.addButton("Reset Settings", resetSettings); From 91827579f264a593ecff800db8eae6e21a91a2ce Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Thu, 4 Aug 2016 22:55:15 +1000 Subject: [PATCH 093/141] Added simple password blocks (Not for real use as uses MD5) --- src/Specs.as | 6 ++++++ src/primitives/SensingPrims.as | 35 +++++++++++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/Specs.as b/src/Specs.as index 7f10e6feb..52db814ad 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -291,6 +291,9 @@ public class Specs { ["ask %s and wait", " ", 7, "doAsk", "What's your name?"], ["answer", "r", 7, "answer"], ["-"], + ["password hash %s", "r", 7, "passwordHash:", ""], + ["password verify hash %s with %s", "b", 7, "passwordVerify:", ""], + ["-"], ["notify %s title %s", " ", 7, "notify:", "Hi!", "Hello!"], ["ask %s with dialog %s", " ", 7, "askBox:", "What's your name?", "IDK"], ["confirm %s", " ", 7, "confirm:", "Is Mrcomputer1 awesome?"], @@ -329,6 +332,9 @@ public class Specs { ["ask %s and wait", " ", 107, "doAsk", "What's your name?"], ["answer", "r", 107, "answer"], ["-"], + ["password hash %s", "r", 107, "passwordHash:", ""], + ["password verify hash %s with %s", "b", 107, "passwordVerify:", ""], + ["-"], ["notify %s title %s", " ", 107, "notify:", "Hi!", "Hello!"], ["ask %s with dialog %s", " ", 107, "askBox:", "What's your name?", "IDK"], ["confirm %s", " ", 107, "confirm:", "Is Mrcomputer1 awesome?"], diff --git a/src/primitives/SensingPrims.as b/src/primitives/SensingPrims.as index 70d0b7c33..33bfd33d5 100644 --- a/src/primitives/SensingPrims.as +++ b/src/primitives/SensingPrims.as @@ -30,6 +30,7 @@ package primitives { import interpreter.*; import scratch.*; import uiwidgets.DialogBox; + import com.adobe.crypto.MD5; public class SensingPrims { @@ -37,7 +38,8 @@ public class SensingPrims { private var interp:Interpreter; private var dialogBoxAllowed = 10; private var dialogBoxActive = 0; // TODO: Add hidden setting for dialog boxs allowed - + private var passwordWarningHasBeenShown:Boolean = false; + public function SensingPrims(app:Scratch, interpreter:Interpreter) { this.app = app; this.interp = interpreter; @@ -84,6 +86,8 @@ public class SensingPrims { primTable["isInFullscreen:"] = function(b:*):* { return app.isFullScreen }; primTable["usingTurboMode:"] = function(b:*):* { return interp.turboMode }; primTable["sharpVersion:"] = function(b:*):* { return Scratch.versionString }; + primTable["passwordHash:"] = primPasswordHash; + primTable["passwordVerify:"] = primPasswordVerify; } // Sharp @@ -111,6 +115,35 @@ public class SensingPrims { dialogBoxActive--; }); } + private function primPasswordHash(b:Array):String{ + if(app.editMode && !passwordWarningHasBeenShown){ + DialogBox.notify("Warning!", "The password blocks are not made for and should not be used for real encryption purposes.\nIt uses MD5 to hash the password.\nIn the future the block encryption may change from MD5.\n\nIf the encryption is changed a password needs conversion boolean block will be added.\nThe hash block will return passwords with the new encryption\nThe verify block will verify for both the old and new encryption\n\n\nNOTE: This notice is shown once per session. And only while in the editor.\nIt is recommended for you to tell your users not to use real passwords"); + passwordWarningHasBeenShown = true; + } + //Hashing methods + //01 = MD5 + var hash:String = "01" + MD5.hash(b[0]); + return hash; + } + private function primPasswordVerify(b:Array):Boolean{ + if(app.editMode && !passwordWarningHasBeenShown){ + DialogBox.notify("Warning!", "The password blocks are not made for and should not be used for real encryption purposes.\nIt uses MD5 to hash the password.\nIn the future the block encryption may change from MD5."); + DialogBox.notify("Warning!", "If the encryption is changed a password needs conversion will be added.\nThe hash block will return passwords with the new encryption\nThe verify block will verify for both the old and new encryption"); + passwordWarningHasBeenShown = true; + } + //Hashing methods in passwordHash function + if(b[0].charAt(0) == "0" && b[0].charAt(1) == "1"){ + var hash:String = MD5.hash(b[1]); + if(hash === b[0].substr(2)){ + return true; + }else{ + return false; + } + } + else{ + return false; + } + } // TODO: move to stage static private var stageRect:Rectangle = new Rectangle(0, 0, 480, 360); From 6725f335d3bfef1247aa2761df7d50bafe091fa3 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Fri, 5 Aug 2016 22:56:19 +1000 Subject: [PATCH 094/141] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index e7ec8023c..319264807 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,8 @@ Sharp Scratch Mod by DrKat123 and Mrcomputer1 [Scratch topic](https://scratch.mit.edu/discuss/topic/199192/) +[Offline Editor](https://sharpscratchmod.github.io/sharp-offline-downloads/publish.htm) + Looking for the Scratch readme? https://github.com/SharpScratchMod/Sharp/blob/master/README_Scratch.md ##Versions From 7f730180ee20a2ffe7991fd23c725c1cbd11a7d3 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Sat, 6 Aug 2016 15:38:29 +1000 Subject: [PATCH 095/141] Fixed file blocks and added a go to url block --- src/Specs.as | 4 + src/primitives/Primitives.as | 173 ++++++++++++++++++++++++++--------- 2 files changed, 132 insertions(+), 45 deletions(-) diff --git a/src/Specs.as b/src/Specs.as index 52db814ad..0fc56c0d2 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -435,11 +435,15 @@ public class Specs { // --HTTP-- ["%m.httpMethod %s", " ", 13, "httpBlock:", "GET", "https://api.scratch.mit.edu"], ["http return", "r", 13, "httpReturn:"], + ["go to %s", " ", 13, "goToURL:"], // --Files-- ["save %s to file %s", " ", 14, "saveFile:", ":)", "smileface.txt"], ["load file", " ", 14, "loadFile:"], ["loaded file name", "r", 14, "loadedFileName:"], ["loaded file data", "r", 14, "loadedFileData:"], + ["loaded?", "b", 14, "fileLoaded:"], + ["loading failed?", "b", 14, "fileLoadFailed:"], + ["loading failure reason", "r", 14, "fileLoadFailReason:"], // Scratch diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index 2232e16c2..dfd146582 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -32,10 +32,14 @@ package primitives { import flash.net.*; import flash.events.Event; + import flash.events.IOErrorEvent; + import flash.events.SecurityErrorEvent; import flash.utils.ByteArray; import mx.utils.Base64Encoder; import mx.utils.Base64Decoder; + + import uiwidgets.DialogBox; public class Primitives { @@ -46,7 +50,7 @@ public class Primitives { private var counter:int; private var httpReturn:String = ""; private var httpRequestsAllowed:int = 10; private var httpRequestsActive:int = 0; // TODO: Add "hidden" setting for HTTP requests allowed - private var fileNameValue:String; private var fileDataValue:String; + private var fileNameValue:String; private var fileDataValue:String; private var fileLoadedValue:Boolean; private var fileErrored:Boolean; private var fileErrorValue:String; public function Primitives(app:Scratch, interpreter:Interpreter) { this.app = app; @@ -110,11 +114,15 @@ public class Primitives { // Sharp -- HTTP primTable["httpBlock:"] = primHttp; primTable["httpReturn:"] = function(b:*):* {return httpReturn}; + primTable["goToURL:"] = primGoTo; // Sharp -- Files primTable["saveFile:"] = primFileSave; primTable["loadFile:"] = primFileLoad; primTable["loadedFileName:"] = function(b:*):*{ return fileNameValue; }; primTable["loadedFileData:"] = function(b:*):*{ return fileDataValue; }; + primTable["fileLoaded:"] = primFileLoaded; + primTable["fileLoadFailed:"] = primFileLoadFail; + primTable["fileLoadFailReason:"] = primFileLoadFailReason; new LooksPrims(app, interp).addPrimsTo(primTable, specialTable); new MotionAndPenPrims(app, interp).addPrimsTo(primTable, specialTable); @@ -272,50 +280,6 @@ public class Primitives { private function primStrReplace(b:Array):String{ return b[1].replace(new RegExp(b[0], "g"), b[2]); } - // Sharp --- HTTP - private function primHttp(b:Array):void { - if(httpRequestsActive == httpRequestsAllowed) return; - httpRequestsActive++; - var url:String = b[1]; - var req:URLRequest = new URLRequest(url); - req.method = URLRequestMethod.GET; - - var loader:URLLoader = new URLLoader(); - loader.addEventListener(Event.COMPLETE, onComplete); - loader.dataFormat = URLLoaderDataFormat.TEXT; - loader.load(req); - - function onComplete(e:Event){ - httpReturn = e.target.data.readUTFBytes(e.target.data.bytesAvailable); - httpRequestsActive--; - } - } - //Sharp --- Files - private function primFileSave(b:Array):void{ - var file:FileReference = new FileReference(); - file.save(b[0], b[1]); - } - private function primFileLoad(b:Array):void{ - var fileName:String, data:ByteArray; - function fileLoaded(event:Event):void{ - var file:FileReference = FileReference(event.target); - fileName = file.name; - data = file.data; - - fileNameValue = fileName; - fileDataValue = data.readUTFBytes(data.bytesAvailable); - } - function fileSelected(event:Event):void{ - var file:FileReference = FileReference(fileList.fileList[0]); - file.addEventListener(Event.COMPLETE, fileLoaded); - file.load(); - } - var fileList:FileReferenceList = new FileReferenceList(); - fileList.addEventListener(Event.SELECT, fileSelected); - try{ - fileList.browse(null); - }catch(e:*){} - } private function primDigitalRoot(b:Array):Number{ if(interp.numarg(b[0]) < 9){ return interp.numarg(b[0]) @@ -352,4 +316,123 @@ public class Primitives { } return false; } + // Sharp --- HTTP + private function primHttp(b:Array):void { + if(httpRequestsActive == httpRequestsAllowed) return; + httpRequestsActive++; + var url:String = b[1]; + var req:URLRequest = new URLRequest(url); + req.method = URLRequestMethod.GET; + + var loader:URLLoader = new URLLoader(); + loader.addEventListener(Event.COMPLETE, onComplete); + loader.dataFormat = URLLoaderDataFormat.TEXT; + loader.load(req); + + function onComplete(e:Event){ + httpReturn = e.target.data.readUTFBytes(e.target.data.bytesAvailable); + httpRequestsActive--; + } + } + private function primGoTo(b:Array):void{ + DialogBox.confirm("Do you want to go to '" + b[0] + "'?", null, okFunc); + function okFunc():void{ + var request:URLRequest = new URLRequest(b[0]); + navigateToURL(request, "_blank"); + } + } + //Sharp --- Files + private function primFileSave(b:Array):void{ + DialogBox.confirm("Would you like to save the file '" + b[1] + "' to your computer?", null, okFunc, cancelFunc); + function okFunc():void{ + function cancelHandle(e:Event){ + fileLoadedValue = true; + fileErrored = true; + fileErrorValue = "Cancelled by user"; + } + function ioErrorHandle(e:IOErrorEvent){ + fileLoadedValue = true; + fileErrored = true; + fileErrorValue = "An IO error occurred!"; + } + function securityError(e:SecurityErrorEvent){ + fileLoadedValue = true; + fileErrored = true; + fileErrorValue = "A security error occurred! This is most likely a problem with Sharp!"; + } + var file:FileReference = new FileReference(); + file.addEventListener(Event.CANCEL, cancelHandle); + file.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandle); + file.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityError); + file.save(b[0], b[1]); + fileLoadedValue = true; + } + function cancelFunc():void{ + fileLoadedValue = true; + fileErrored = true; + fileErrorValue = "Denied by user"; + } + } + private function primFileLoad(b:Array):void{ + DialogBox.confirm("Would you like to open a file from your computer?", null, okFunc, cancelFunc); + function okFunc():void{ + var fileName:String, data:ByteArray; + function cancelHandle(e:Event){ + fileLoadedValue = true; + fileErrored = true; + fileErrorValue = "Cancelled by user"; + } + function ioErrorHandle(e:IOErrorEvent){ + fileLoadedValue = true; + fileErrored = true; + fileErrorValue = "An IO error occurred!"; + } + function securityError(e:SecurityErrorEvent){ + fileLoadedValue = true; + fileErrored = true; + fileErrorValue = "A security error occurred! This is most likely a problem with Sharp!"; + } + function fileLoaded(event:Event):void{ + var file:FileReference = FileReference(event.target); + file.addEventListener(Event.CANCEL, cancelHandle); + file.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandle); + file.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityError); + fileName = file.name; + data = file.data; + + fileNameValue = fileName; + fileDataValue = data.readUTFBytes(data.bytesAvailable); + fileLoadedValue = true; + } + function fileSelected(event:Event):void{ + var file:FileReference = FileReference(fileList.fileList[0]); + file.addEventListener(Event.COMPLETE, fileLoaded); + file.load(); + } + var fileList:FileReferenceList = new FileReferenceList(); + fileList.addEventListener(Event.SELECT, fileSelected); + fileList.addEventListener(Event.CANCEL, cancelHandle); + fileList.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandle); + fileList.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityError); + try{ + fileList.browse(null); + }catch(e:*){} + } + function cancelFunc():void{ + fileLoadedValue = true; + fileErrored = true; + fileErrorValue = "Denied by user"; + } + } + private function primFileLoaded(b:Array):Boolean{ + var bl:Boolean = fileLoadedValue; + fileLoadedValue = false; + return bl; + } + private function primFileLoadFail(b:Array):Boolean{ + return fileErrored; + } + private function primFileLoadFailReason(b:Array):String{ + return fileErrorValue; + } }} From 4b7d5f97f6aaefdb354606490953f1f5d90ddb13 Mon Sep 17 00:00:00 2001 From: DrKat123 Date: Wed, 10 Aug 2016 09:49:27 +0700 Subject: [PATCH 096/141] bitwise operators --- runbuild.bat | 3 +++ src/Specs.as | 25 +++++++++++++++---------- src/primitives/Primitives.as | 24 ++++++++++-------------- 3 files changed, 28 insertions(+), 24 deletions(-) create mode 100644 runbuild.bat diff --git a/runbuild.bat b/runbuild.bat new file mode 100644 index 000000000..b87445cb4 --- /dev/null +++ b/runbuild.bat @@ -0,0 +1,3 @@ +@echo off +gradlew.bat build +pause \ No newline at end of file diff --git a/src/Specs.as b/src/Specs.as index 0fc56c0d2..8e2473ebb 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -380,33 +380,38 @@ public class Specs { ["%b and %b", "b", 8, "&"], ["%b or %b", "b", 8, "|"], ["not %b", "b", 8, "~"], - //secret beta update blocks - //--- ["%b nand %b", "b", 8, "nand"], - //["%b nor %b", "b", 8, "nor"], + ["%b nor %b", "b", 8, "nor"], + //why the heck is NOR commented... ["%b xor %b", "b", 8, "xor"], ["%b xnor %b", "b", 8, "xnor"], - //this is supposed to be a secret but if you did find this, well, congratulations - //you just spoiled the secret update - ["-"], ["true", "b", 8, "true"], ["false", "b", 8, "false"], ["-"], - ["join %s %s", "r", 8, "concatenate:with:", "hello ", "world"], - ["letter %n of %s", "r", 8, "letter:of:", 1, "world"], - ["length of %s", "r", 8, "stringLength:", "world"], - ["-"], ["%n mod %n", "r", 8, "%", "", ""], ["round %n", "r", 8, "rounded", ""], ["-"], ["%m.mathOp of %n", "r", 8, "computeFunction:of:", "sqrt", 9], ["digital root of %n", "r", 8, "digitalRootOf:", "1234"], ["the constant %m.constantName", "r", 8, "chooseConstant:", "Pi"], + ["-"], + ["join %s %s", "r", 8, "concatenate:with:", "hello ", "world"], + ["letter %n of %s", "r", 8, "letter:of:", 1, "world"], + ["length of %s", "r", 8, "stringLength:", "world"], ["reverse %s", "r", 8, "reverseString:", "hello"], ["replace %s in %s with %s", "r", 8, "blockReplace:", "Hi", "Hi", "Hello"], ["split %s at %s and return to %m.list"," ", 8, "blockSplit:", "H i", " ", ""], ["split %s at %s and return %n", "r", 8, "blockSplitReturn:", "H i", " ", 1], ["split %s from letter %n to %n", "r", 8, "splitStringFrom:", "Foobar", "1", "3"], + //bitwise + ["-"], + ["%n & %n", "r", 8, "bitwiseAnd:", "1", "2"], + ["%n | %n", "r", 8, "bitwiseOr:", "1", "2"], + ["%n ^ %n", "r", 8, "bitwiseXor:", "1", "2"], + ["~ %n", "r", 8, "bitwiseNot:", "1", "2"], + ["%n << %n", "r", 8, "bitwiseLeftShift:", "2", "10"], + ["%n >> %n", "r", 8, "bitwiseRightShift:", "2", "10"], + //["%n >>> %n", "r", 8, "bitwiseUnsignedShift:", "2", "10"], // variables ["set %m.var to %s", " ", 9, SET_VAR], diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index dfd146582..ad52e834c 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -71,12 +71,10 @@ public class Primitives { primTable["|"] = function(b:*):* { return interp.boolarg(b[0]) || interp.boolarg(b[1]) }; primTable["~"] = function(b:*):* { return !interp.boolarg(b[0]) }; - //testing functions for moar logic gates - //don't spoil the secret update! - //Shhh - //--- + + primTable["nand"] = function(b:*):* { return !(interp.boolarg(b[0]) && interp.boolarg(b[1])) }; - primTable["nor"] = primLogicNor; + primTable["nor"] = function(b:*):* { return !(interp.boolarg(b[0]) || interp.boolarg(b[1])) }; //if i had realized that it was this simple i should've implemented logic gates since i started making sharp! primTable["xor"] = primLogicXor; primTable["xnor"] = primLogicXnor; primTable["abs"] = function(b:*):* { return Math.abs(interp.numarg(b[0])) }; @@ -84,6 +82,13 @@ public class Primitives { primTable["power:of:"] = function(b:*):* { return Math.pow(interp.numarg(b[0]), interp.numarg(b[1])) }; primTable["reverseString:"] = primReverseString; primTable["splitStringFrom:"] = primSplit; + primTable["bitwiseAnd:"] = function(b:*):* { return interp.numarg(b[0]) & interp.numarg(b[1]) }; + primTable["bitwiseOr:"] = function(b:*):* { return interp.numarg(b[0]) | interp.numarg(b[1]) }; + primTable["bitwiseNot:"] = function(b:*):* { return ~ interp.numarg(b[0]) }; + primTable["bitwiseXor:"] = function(b:*):* { return interp.numarg(b[0]) ^ interp.numarg(b[1]) }; + primTable["bitwiseLeftShift:"] = function(b:*):* { return interp.numarg(b[0]) << interp.numarg(b[1])}; + primTable["bitwiseRightShift:"] = function(b:*):* { return interp.numarg(b[0]) >> interp.numarg(b[1])}; + //primTable["bitwiseUnsignedShift"] = function(b:*):* { return interp.numarg(b[0]) >>> interp.numarg(b[1])}; primTable["concatenate:with:"] = function(b:*):* { return ("" + b[0] + b[1]).substr(0, 10240); }; primTable["letter:of:"] = primLetterOf; @@ -289,15 +294,6 @@ public class Primitives { } - private function primLogicNor(b:Array):Boolean{ - if((interp.boolarg(b[0]) == false) && (interp.boolarg(b[1]) == false)){ - return true; - } else { - return false; - }; - return false; - } - private function primLogicXor(b:Array):Boolean{ if(interp.boolarg(b[0]) !== interp.boolarg(b[1])){ return true; From cfe2e3345ffe2d32a6ddc2dd8a417e7873c2747e Mon Sep 17 00:00:00 2001 From: Alexander Liu Date: Wed, 10 Aug 2016 10:01:05 +0700 Subject: [PATCH 097/141] Rename runbuild.bat to build.bat --- runbuild.bat => build.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename runbuild.bat => build.bat (82%) diff --git a/runbuild.bat b/build.bat similarity index 82% rename from runbuild.bat rename to build.bat index b87445cb4..3014747ea 100644 --- a/runbuild.bat +++ b/build.bat @@ -1,3 +1,3 @@ @echo off gradlew.bat build -pause \ No newline at end of file +pause From e4f78cb37cfa04971cb85ab4f1a88511541c93e4 Mon Sep 17 00:00:00 2001 From: Alexander Liu Date: Wed, 10 Aug 2016 10:06:33 +0700 Subject: [PATCH 098/141] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 319264807..05230758f 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Looking for the Scratch readme? https://github.com/SharpScratchMod/Sharp/blob/ma Version | Code Name | LTS | Released | Still supported | Supported until | Notes ------------------ | ---------------- | --- | -------- | --------------- | --------------- | ----------------------------- 1.0.0 (Release) | Katana | NO | NO | --NOT YET-- | --NOT YET-- | -1.0.0 Beta | Chainsaw | NO | NO | --NOT YET-- | --NOT YET-- | +1.0.0 Beta | Chainsaw | YES | YES | YES | January 1, 2017 | 1.1.5 Alpha | Sawtooth | NO | YES | YES | --TBA-- | 1.1.0 Alpha | Sawtooth | NO | YES | YES | --TBA-- | 1.0.1 Alpha | Butterknife | NO | YES | YES | --TBA-- | Will replace 1.0.0 Alpha support From 69e3e79f4662ce99d91d2f409c13b9ecbaf15358 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Thu, 11 Aug 2016 21:10:19 +1000 Subject: [PATCH 099/141] Changed password blocks from MD5 to SHA256 --- src/Specs.as | 2 ++ src/primitives/SensingPrims.as | 37 ++++++++++++++++++++++++++++++---- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/Specs.as b/src/Specs.as index 8e2473ebb..0925b3737 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -293,6 +293,7 @@ public class Specs { ["-"], ["password hash %s", "r", 7, "passwordHash:", ""], ["password verify hash %s with %s", "b", 7, "passwordVerify:", ""], + ["password needs rehash %s?", "b", 7, "passwordRehash:", ""], ["-"], ["notify %s title %s", " ", 7, "notify:", "Hi!", "Hello!"], ["ask %s with dialog %s", " ", 7, "askBox:", "What's your name?", "IDK"], @@ -334,6 +335,7 @@ public class Specs { ["-"], ["password hash %s", "r", 107, "passwordHash:", ""], ["password verify hash %s with %s", "b", 107, "passwordVerify:", ""], + ["password needs rehash %s?", "b", 107, "passwordRehash:", ""], ["-"], ["notify %s title %s", " ", 107, "notify:", "Hi!", "Hello!"], ["ask %s with dialog %s", " ", 107, "askBox:", "What's your name?", "IDK"], diff --git a/src/primitives/SensingPrims.as b/src/primitives/SensingPrims.as index 33bfd33d5..254554a3e 100644 --- a/src/primitives/SensingPrims.as +++ b/src/primitives/SensingPrims.as @@ -31,6 +31,7 @@ package primitives { import scratch.*; import uiwidgets.DialogBox; import com.adobe.crypto.MD5; + import com.adobe.crypto.SHA256; public class SensingPrims { @@ -88,6 +89,7 @@ public class SensingPrims { primTable["sharpVersion:"] = function(b:*):* { return Scratch.versionString }; primTable["passwordHash:"] = primPasswordHash; primTable["passwordVerify:"] = primPasswordVerify; + primTable["passwordRehash:"] = primPasswordRehashCheck; } // Sharp @@ -117,18 +119,21 @@ public class SensingPrims { } private function primPasswordHash(b:Array):String{ if(app.editMode && !passwordWarningHasBeenShown){ - DialogBox.notify("Warning!", "The password blocks are not made for and should not be used for real encryption purposes.\nIt uses MD5 to hash the password.\nIn the future the block encryption may change from MD5.\n\nIf the encryption is changed a password needs conversion boolean block will be added.\nThe hash block will return passwords with the new encryption\nThe verify block will verify for both the old and new encryption\n\n\nNOTE: This notice is shown once per session. And only while in the editor.\nIt is recommended for you to tell your users not to use real passwords"); + //The password blocks are not made for and should not be used for real encryption purposes.\nIt uses MD5 to hash the password.\nIn the future the block encryption may change from MD5.\n\nIf the encryption is changed a password needs conversion boolean block will be added.\nThe hash block will return passwords with the new encryption\nThe verify block will verify for both the old and new encryption\n\n\nNOTE: This notice is shown once per session. And only while in the editor.\nIt is recommended for you to tell your users not to use real passwords + DialogBox.notify("Warning!", "The password blocks are not made for real password use.\nIt uses SHA256 to hash the password.\nIn the future the block encryption may change from SHA256.\n\nTo convert from MD5 use the password needs rehash boolean and password hash the password\nThe verify block can handle the MD5 and SHA256 methods.\n\n\nNOTE: This notice is shown once per session. And only while in the editor.\nIt is recommended for you to tell your users not to use real passwords"); passwordWarningHasBeenShown = true; } //Hashing methods //01 = MD5 - var hash:String = "01" + MD5.hash(b[0]); + //02 = SHA256 + var hash:String = "02" + SHA256.hash(b[0]); return hash; } private function primPasswordVerify(b:Array):Boolean{ if(app.editMode && !passwordWarningHasBeenShown){ - DialogBox.notify("Warning!", "The password blocks are not made for and should not be used for real encryption purposes.\nIt uses MD5 to hash the password.\nIn the future the block encryption may change from MD5."); - DialogBox.notify("Warning!", "If the encryption is changed a password needs conversion will be added.\nThe hash block will return passwords with the new encryption\nThe verify block will verify for both the old and new encryption"); + //DialogBox.notify("Warning!", "The password blocks are not made for and should not be used for real encryption purposes.\nIt uses MD5 to hash the password.\nIn the future the block encryption may change from MD5."); + //DialogBox.notify("Warning!", "If the encryption is changed a password needs conversion will be added.\nThe hash block will return passwords with the new encryption\nThe verify block will verify for both the old and new encryption"); + DialogBox.notify("Warning!", "The password blocks are not made for real password use.\nIt uses SHA256 to hash the password.\nIn the future the block encryption may change from SHA256.\n\nTo convert from MD5 use the password needs rehash boolean and password hash the password\nThe verify block can handle the MD5 and SHA256 methods.\n\n\nNOTE: This notice is shown once per session. And only while in the editor.\nIt is recommended for you to tell your users not to use real passwords"); passwordWarningHasBeenShown = true; } //Hashing methods in passwordHash function @@ -139,6 +144,30 @@ public class SensingPrims { }else{ return false; } + }else if(b[0].charAt(0) == "0" && b[0].charAt(1) == "2"){ + var hash:String = SHA256.hash(b[1]); + if(hash === b[0].substr(2)){ + return true; + }else{ + return false; + } + } + else{ + return false; + } + } + private function primPasswordRehashCheck(b:Array):Boolean{ + if(app.editMode && !passwordWarningHasBeenShown){ + //DialogBox.notify("Warning!", "The password blocks are not made for and should not be used for real encryption purposes.\nIt uses MD5 to hash the password.\nIn the future the block encryption may change from MD5."); + //DialogBox.notify("Warning!", "If the encryption is changed a password needs conversion will be added.\nThe hash block will return passwords with the new encryption\nThe verify block will verify for both the old and new encryption"); + DialogBox.notify("Warning!", "The password blocks are used at your own risk.\nIt uses SHA256 to hash the password.\nIn the future the block encryption may change from SHA256.\n\nTo convert from MD5 use the password needs rehash boolean and password hash the password\nThe verify block can handle the MD5 and SHA256 methods.\n\n\nNOTE: This notice is shown once per session. And only while in the editor.\nIt is recommended for you to tell your users not to use real passwords"); + passwordWarningHasBeenShown = true; + } + //Hashing methods in passwordHash function + if(b[0].charAt(0) == "0" && b[0].charAt(1) == "1"){ + return true + }else if(b[0].charAt(0) == "0" && b[0].charAt(1) == "2"){ + return false; } else{ return false; From 3a502ab82599e0f0c8afb766e9c1ce3f35205f42 Mon Sep 17 00:00:00 2001 From: Alexander Liu Date: Sun, 14 Aug 2016 07:22:14 +0700 Subject: [PATCH 100/141] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 05230758f..33504754e 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Sharp Scratch Mod by DrKat123 and Mrcomputer1 [![Gitter](https://badges.gitter.im/SharpScratchMod/Sharp.svg)](https://gitter.im/SharpScratchMod/Sharp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=body_badge) [![Build Status](https://travis-ci.org/SharpScratchMod/Sharp.svg?branch=master)](https://travis-ci.org/SharpScratchMod/Sharp) - +[![Version](https://img.shields.io/badge/version-beta%201.0.1-brightgreen.svg)](https://github.com/SharpScratchMod/Sharp/releases/tag/v1.0.0-beta) [Try it!](https://sharpscratchmod.github.io/Sharp.swf) [Scratch topic](https://scratch.mit.edu/discuss/topic/199192/) From 24454db4d36f554a58b4593238340a17e054e900 Mon Sep 17 00:00:00 2001 From: Alexander Liu Date: Sun, 14 Aug 2016 07:22:51 +0700 Subject: [PATCH 101/141] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 33504754e..fbfe4dbc4 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Sharp Scratch Mod by DrKat123 and Mrcomputer1 [![Gitter](https://badges.gitter.im/SharpScratchMod/Sharp.svg)](https://gitter.im/SharpScratchMod/Sharp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=body_badge) [![Build Status](https://travis-ci.org/SharpScratchMod/Sharp.svg?branch=master)](https://travis-ci.org/SharpScratchMod/Sharp) -[![Version](https://img.shields.io/badge/version-beta%201.0.1-brightgreen.svg)](https://github.com/SharpScratchMod/Sharp/releases/tag/v1.0.0-beta) +[![Version](https://img.shields.io/badge/version-beta%201.0.1-brightgreen.svg)](https://github.com/SharpScratchMod/Sharp/releases/tag/v1.0.0-beta) [Try it!](https://sharpscratchmod.github.io/Sharp.swf) [Scratch topic](https://scratch.mit.edu/discuss/topic/199192/) From 6528bf24d5e6bffb6a62da161444fd3941be07a5 Mon Sep 17 00:00:00 2001 From: Alexander Liu Date: Sun, 14 Aug 2016 07:23:19 +0700 Subject: [PATCH 102/141] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fbfe4dbc4..5ed2ad88c 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Sharp Scratch Mod by DrKat123 and Mrcomputer1 [![Gitter](https://badges.gitter.im/SharpScratchMod/Sharp.svg)](https://gitter.im/SharpScratchMod/Sharp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=body_badge) [![Build Status](https://travis-ci.org/SharpScratchMod/Sharp.svg?branch=master)](https://travis-ci.org/SharpScratchMod/Sharp) -[![Version](https://img.shields.io/badge/version-beta%201.0.1-brightgreen.svg)](https://github.com/SharpScratchMod/Sharp/releases/tag/v1.0.0-beta) +[![Version](https://img.shields.io/badge/version-beta%201.0.0-brightgreen.svg)](https://github.com/SharpScratchMod/Sharp/releases/tag/v1.0.0-beta) [Try it!](https://sharpscratchmod.github.io/Sharp.swf) [Scratch topic](https://scratch.mit.edu/discuss/topic/199192/) From fea3b427ba79a786e796db4b10ad632cf2d2fc4c Mon Sep 17 00:00:00 2001 From: Alexander Liu Date: Tue, 16 Aug 2016 09:59:31 +0700 Subject: [PATCH 103/141] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5ed2ad88c..1bf7e0991 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,8 @@ Sharp Scratch Mod by DrKat123 and Mrcomputer1 [![Gitter](https://badges.gitter.im/SharpScratchMod/Sharp.svg)](https://gitter.im/SharpScratchMod/Sharp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=body_badge) [![Build Status](https://travis-ci.org/SharpScratchMod/Sharp.svg?branch=master)](https://travis-ci.org/SharpScratchMod/Sharp) -[![Version](https://img.shields.io/badge/version-beta%201.0.0-brightgreen.svg)](https://github.com/SharpScratchMod/Sharp/releases/tag/v1.0.0-beta) +[![Version](https://img.shields.io/badge/version-beta%201.0.0-brightgreen.svg)](https://github.com/SharpScratchMod/Sharp/releases/tag/v1.0.0-beta) +[![License](https://img.shields.io/badge/license-GPL%20v2-brightgreen.svg)](https://github.com/SharpScratchMod/Sharp/blob/master/COPYING) [Try it!](https://sharpscratchmod.github.io/Sharp.swf) [Scratch topic](https://scratch.mit.edu/discuss/topic/199192/) From c12ccd3873543a6da54cbb01f255a20156e27740 Mon Sep 17 00:00:00 2001 From: Alexander Liu Date: Tue, 16 Aug 2016 11:25:00 +0700 Subject: [PATCH 104/141] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1bf7e0991..5afadd889 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,8 @@ Sharp Scratch Mod by DrKat123 and Mrcomputer1 [![Gitter](https://badges.gitter.im/SharpScratchMod/Sharp.svg)](https://gitter.im/SharpScratchMod/Sharp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=body_badge) [![Build Status](https://travis-ci.org/SharpScratchMod/Sharp.svg?branch=master)](https://travis-ci.org/SharpScratchMod/Sharp) -[![Version](https://img.shields.io/badge/version-beta%201.0.0-brightgreen.svg)](https://github.com/SharpScratchMod/Sharp/releases/tag/v1.0.0-beta) -[![License](https://img.shields.io/badge/license-GPL%20v2-brightgreen.svg)](https://github.com/SharpScratchMod/Sharp/blob/master/COPYING) +[![Version](https://img.shields.io/badge/version-beta%201.0.0-brightgreen.svg?style=flat-square)](https://github.com/SharpScratchMod/Sharp/releases/tag/v1.0.0-beta) +[![License](https://img.shields.io/badge/license-GPL%20v2-brightgreen.svg?style=flat-square)](https://github.com/SharpScratchMod/Sharp/blob/master/COPYING) [Try it!](https://sharpscratchmod.github.io/Sharp.swf) [Scratch topic](https://scratch.mit.edu/discuss/topic/199192/) From d26192ee36592a658fd641809148e3f464e48d13 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Thu, 18 Aug 2016 12:46:45 +1000 Subject: [PATCH 105/141] Changed media library code --- src/util/Server.as | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/util/Server.as b/src/util/Server.as index 02adf3b87..c28cbe895 100644 --- a/src/util/Server.as +++ b/src/util/Server.as @@ -253,12 +253,14 @@ public class Server implements IServer { // whenDone(BackpackPart.localAssets[md5]); // return null; // } - var url:String = URLs.assetCdnPrefix + URLs.internalAPI + 'asset/' + md5 + '/get/'; + //var url:String = URLs.assetCdnPrefix + URLs.internalAPI + 'asset/' + md5 + '/get/'; + var url:String = "static/assets/" + md5; return serverGet(url, whenDone); } public function getMediaLibrary(libraryType:String, whenDone:Function):URLLoader { - var url:String = getCdnStaticSiteURL() + 'medialibraries/' + libraryType + 'Library.json'; + //var url:String = getCdnStaticSiteURL() + 'medialibraries/' + libraryType + 'Library.json'; + var url:String = "static/medialibraries/" + libraryType + "Library.json"; return serverGet(url, whenDone); } From e9794e433cb39e51904fc39643baa428fc4c6873 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Thu, 18 Aug 2016 21:56:07 +1000 Subject: [PATCH 106/141] Changed medialibrariesthumbnails to the assets folder --- src/util/Server.as | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/util/Server.as b/src/util/Server.as index c28cbe895..46e9882f7 100644 --- a/src/util/Server.as +++ b/src/util/Server.as @@ -307,7 +307,8 @@ public class Server implements IServer { } public function getThumbnail(idAndExt:String, w:int, h:int, whenDone:Function):URLLoader { - var url:String = getCdnStaticSiteURL() + 'medialibrarythumbnails/' + idAndExt; + //var url:String = getCdnStaticSiteURL() + 'medialibrarythumbnails/' + idAndExt; + var url:String = "/static/assets/" + idAndExt; return downloadThumbnail(url, w, h, whenDone); } From ee5c03abcad22900207434c95fa94720ce7c19a9 Mon Sep 17 00:00:00 2001 From: DrKat123 Date: Thu, 11 Aug 2016 08:47:15 +0700 Subject: [PATCH 107/141] added golden ratios --- src/primitives/Primitives.as | 1 + src/scratch/BlockMenus.as | 1 + 2 files changed, 2 insertions(+) diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index ad52e834c..dc0ac9e36 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -267,6 +267,7 @@ public class Primitives { switch(pickConstant) { case "Pi": return Math.PI; case "E": return Math.E; + case "Phi": return (1 + Math.sqrt(5)) / 2; } return 0; } diff --git a/src/scratch/BlockMenus.as b/src/scratch/BlockMenus.as index ec95456fe..e2a22dfdf 100644 --- a/src/scratch/BlockMenus.as +++ b/src/scratch/BlockMenus.as @@ -867,6 +867,7 @@ public class BlockMenus implements DragClient { var m:Menu = new Menu(setBlockArg, 'constantName'); m.addItem('Pi'); m.addItem('E'); + m.addItem('Phi'); showMenu(m); } }} From 3f35b24b837a989b4a47cc1a216ff7040c61e48a Mon Sep 17 00:00:00 2001 From: DrKat123 Date: Fri, 19 Aug 2016 07:38:00 +0700 Subject: [PATCH 108/141] Sprites --- src/assets/sprite1A.svg | 10 ++++++++++ src/assets/sprite1B.svg | 10 ++++++++++ src/primitives/Primitives.as | 1 + src/scratch/ScratchRuntime.as | 15 +++++++++++++-- 4 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 src/assets/sprite1A.svg create mode 100644 src/assets/sprite1B.svg diff --git a/src/assets/sprite1A.svg b/src/assets/sprite1A.svg new file mode 100644 index 000000000..ddedc982f --- /dev/null +++ b/src/assets/sprite1A.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/sprite1B.svg b/src/assets/sprite1B.svg new file mode 100644 index 000000000..23129fb3d --- /dev/null +++ b/src/assets/sprite1B.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index dc0ac9e36..8ebbda00f 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -88,6 +88,7 @@ public class Primitives { primTable["bitwiseXor:"] = function(b:*):* { return interp.numarg(b[0]) ^ interp.numarg(b[1]) }; primTable["bitwiseLeftShift:"] = function(b:*):* { return interp.numarg(b[0]) << interp.numarg(b[1])}; primTable["bitwiseRightShift:"] = function(b:*):* { return interp.numarg(b[0]) >> interp.numarg(b[1])}; + //this block doesn't work so please don't use it until we can fix it //primTable["bitwiseUnsignedShift"] = function(b:*):* { return interp.numarg(b[0]) >>> interp.numarg(b[1])}; primTable["concatenate:with:"] = function(b:*):* { return ("" + b[0] + b[1]).substr(0, 10240); }; diff --git a/src/scratch/ScratchRuntime.as b/src/scratch/ScratchRuntime.as index 4e5610216..5a58c7e57 100644 --- a/src/scratch/ScratchRuntime.as +++ b/src/scratch/ScratchRuntime.as @@ -80,7 +80,8 @@ public class ScratchRuntime { protected var projectToInstall:ScratchStage; protected var saveAfterInstall:Boolean; - + [Embed(source='../assets/sprite1A.svg', mimeType='application/octet-stream')] protected static var ModCostume1:Class; + [Embed(source='../assets/sprite1B.svg', mimeType='application/octet-stream')] protected static var ModCostume2:Class; public function ScratchRuntime(app:Scratch, interp:Interpreter) { this.app = app; this.interp = interp; @@ -775,7 +776,17 @@ public class ScratchRuntime { } public function installNewProject():void { - installEmptyProject(); + var newStage:ScratchStage = new ScratchStage(); + var sprite:ScratchSprite = new ScratchSprite('Sprite1'); + var costume1:ScratchCostume = new ScratchCostume(Translator.map('costume1'), new ModCostume1()); + var costume2:ScratchCostume = new ScratchCostume(Translator.map('costume2'), new ModCostume2()); + sprite.costumes = [costume1, costume2]; + sprite.showCostume(1); //To fix odd bug + sprite.showCostume(0); + newStage.addChild(sprite); + app.saveForRevert(new ProjectIO(app).encodeProjectAsZipFile(newStage),true); + app.oldWebsiteURL = ""; + installProject(newStage); } public function selectProjectFile():void { From 84d895a80fd2a1f24f54ac7522d5a788bb0d5ef4 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Tue, 23 Aug 2016 17:12:45 +1000 Subject: [PATCH 109/141] Updated record video dialog, Part 1 of editor tour --- src/Scratch.as | 3 ++- src/scratch/ScratchRuntime.as | 4 ++-- src/ui/RecordingSpecEditor.as | 2 +- src/ui/SharingSpecEditor.as | 2 +- src/ui/parts/TopBarPart.as | 10 +++++----- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/Scratch.as b/src/Scratch.as index 4140e018b..b0d8a8830 100644 --- a/src/Scratch.as +++ b/src/Scratch.as @@ -183,7 +183,7 @@ public class Scratch extends Sprite { // UI Parts public var libraryPart:LibraryPart; - protected var topBarPart:TopBarPart; + public var topBarPart:TopBarPart; //was protected protected var stagePart:StagePart; private var tabsPart:TabsPart; protected var scriptsPart:ScriptsPart; @@ -289,6 +289,7 @@ public class Scratch extends Sprite { initSettings(); if(isOffline) DialogBox.notify("Welcome to Sharp!", "Website: http://SharpScratchMod.github.io\nGitHub: https://github.com/SharpScratchMod/Sharp\n\nCredits:\nDrKat123 - Developer, Owner\nMrcomputer1 - Developer, Owner\nscratchyone - Developer\n\nOther important credits:\nNoMod-Programming - Custom reporters"); + Tutorial.editorMap(); } protected function handleStartupParameters():void { diff --git a/src/scratch/ScratchRuntime.as b/src/scratch/ScratchRuntime.as index 4e5610216..a0895636d 100644 --- a/src/scratch/ScratchRuntime.as +++ b/src/scratch/ScratchRuntime.as @@ -496,11 +496,11 @@ public class ScratchRuntime { file.save(video, "movie.flv"); Scratch.app.log(LogLevel.TRACK, "Video downloaded", {projectID: app.projectID, seconds: roundToTens(seconds), megabytes: roundToTens(video.length/1000000)}); var specEditor:SharingSpecEditor = new SharingSpecEditor(); - DialogBox.close("Playing and Sharing Your Video",null,specEditor,"Back to Scratch"); + DialogBox.close("Playing and Sharing Your Video",null,specEditor,"Back to Sharp"); releaseVideo(false); } function releaseVideo(log:Boolean = true):void { - if (log) Scratch.app.log(LogLevel.TRACK, "Video canceled", {projectID: app.projectID, seconds: roundToTens(seconds), megabytes: roundToTens(video.length/1000000)}); + if (log) Scratch.app.log(LogLevel.TRACK, "Video cancelled", {projectID: app.projectID, seconds: roundToTens(seconds), megabytes: roundToTens(video.length/1000000)}); video = null; } DialogBox.close("Video Finished!","To save, click the button below.",null,"Save and Download",app.stage,saveFile,releaseVideo,null,true); diff --git a/src/ui/RecordingSpecEditor.as b/src/ui/RecordingSpecEditor.as index 428a166d6..45bf9ad37 100644 --- a/src/ui/RecordingSpecEditor.as +++ b/src/ui/RecordingSpecEditor.as @@ -53,7 +53,7 @@ public class RecordingSpecEditor extends Sprite { setWidthHeight(440, 10); addChild(description = makeLabel('Capture and download a video of your project to your computer.\nYou can record up to 60 seconds of video.',14)); - addChild(notSavedLabel = makeLabel('that the video will not be saved on Scratch.',14)); + addChild(notSavedLabel = makeLabel('that the video will not be saved on Sharp.',14)); addChild(pleaseNoteLabel = makeLabel('Please note',14,true)); addChild(moreLabel = makeLabel('More Options', 14)); moreLabel.addEventListener(MouseEvent.MOUSE_DOWN, toggleButtons); diff --git a/src/ui/SharingSpecEditor.as b/src/ui/SharingSpecEditor.as index 13f4992ce..0242a64b1 100644 --- a/src/ui/SharingSpecEditor.as +++ b/src/ui/SharingSpecEditor.as @@ -50,7 +50,7 @@ public class SharingSpecEditor extends Sprite { addChild(playLabel = makeLabel('To play your video, download and install the',14)); addChild(linkLabel = makeLinkLabel('VLC media player.',14,"http://www.videolan.org/vlc/index.html")); - addChild(faqLabel = makeLinkLabel('Questions?',14,"https://scratch.mit.edu/info/faq/")); + //addChild(faqLabel = makeLinkLabel('Questions?',14,"https://scratch.mit.edu/info/faq/")); addChild(shareLabel = makeLabel('You can also share your video with others to let them see it!',14)); addChild(shareImage = Resources.createDO("videoShare")); var h:Number = 160/shareImage.width*shareImage.height; diff --git a/src/ui/parts/TopBarPart.as b/src/ui/parts/TopBarPart.as index bb611e0e9..ab94111ae 100644 --- a/src/ui/parts/TopBarPart.as +++ b/src/ui/parts/TopBarPart.as @@ -39,13 +39,13 @@ public class TopBarPart extends UIPart { private var shape:Shape; protected var logoButton:IconButton; - protected var languageButton:IconButton; + public var languageButton:IconButton; //was protected - protected var fileMenu:IconButton; - protected var editMenu:IconButton; - protected var helpMenu:IconButton; + public var fileMenu:IconButton; //was protected + public var editMenu:IconButton; //was protected + public var helpMenu:IconButton; //was protected - private var copyTool:IconButton; + public var copyTool:IconButton; //was private private var cutTool:IconButton; private var growTool:IconButton; private var shrinkTool:IconButton; From 34f1f11039646a299e526c7d0987fe1501f984e4 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Wed, 24 Aug 2016 17:40:57 +1000 Subject: [PATCH 110/141] Part 2 of editor tour and something else --- config.groovy | 11 ++ src/Scratch.as | 79 +++++++++++- src/Tutorial.as | 226 +++++++++++++++++++++++++++++++++ src/scratch/ScratchObj.as | 16 ++- src/ui/parts/ScriptsPart.as | 2 +- src/ui/parts/StagePart.as | 8 +- src/ui/parts/TopBarPart.as | 20 ++- src/uiwidgets/TutorialDoBox.as | 100 +++++++++++++++ 8 files changed, 447 insertions(+), 15 deletions(-) create mode 100644 src/Tutorial.as create mode 100644 src/uiwidgets/TutorialDoBox.as diff --git a/config.groovy b/config.groovy index 29abead12..488254a73 100644 --- a/config.groovy +++ b/config.groovy @@ -1,10 +1,20 @@ environments { + '11.6dev' { + output = 'SharpDev' + playerVersion = '11.6' + additionalCompilerOptions = [ + "-swf-version=19", + "-define+=SCRATCH::allow3d,true", + "-define+=SHARP::builtWithDevMode,true", + ] + } '11.6' { output = 'Sharp' playerVersion = '11.6' additionalCompilerOptions = [ "-swf-version=19", "-define+=SCRATCH::allow3d,true", + "-define+=SHARP::builtWithDevMode,false", ] } '10.2' { @@ -13,6 +23,7 @@ environments { additionalCompilerOptions = [ "-swf-version=11", "-define+=SCRATCH::allow3d,false", + "-define+=SHARP::builtWithDevMode,false", ] } } diff --git a/src/Scratch.as b/src/Scratch.as index b0d8a8830..278c55b7c 100644 --- a/src/Scratch.as +++ b/src/Scratch.as @@ -74,10 +74,22 @@ import util.*; import watchers.ListWatcher; +import com.adobe.crypto.SHA256; + public class Scratch extends Sprite { // Version - public static const versionString:String = 'Beta 1.0.0 (Katana) : Scratch v448'; + public static const versionString:String = 'Beta 1.0.0 (Katana) : Scratch v448' + (SHARP::builtWithDevMode ? " : Sharp Developer Mode Active" : ""); public static var app:Scratch; // static reference to the app, used for debugging + // Sharp Developer Menu + // *------------------------------------* + // | We won't say the password! You will| + // | have to change the password or | + // | edit the code to gain access to thi| + // |s menu | + // *------------------------------------* + public var builtWithDevMode:Boolean = SHARP::builtWithDevMode; + public var devMode:Boolean = false; + public var devModePassword:String = "99625b7abd0d05c32905b9aa67c9e6cb7e19ead8dc16d0caf5d372a8441dbd34"; // Sharp settings store public var sharpSettings:SharedObject; @@ -184,9 +196,9 @@ public class Scratch extends Sprite { // UI Parts public var libraryPart:LibraryPart; public var topBarPart:TopBarPart; //was protected - protected var stagePart:StagePart; + public var stagePart:StagePart; //was protected private var tabsPart:TabsPart; - protected var scriptsPart:ScriptsPart; + public var scriptsPart:ScriptsPart; //was protected public var imagesPart:ImagesPart; public var soundsPart:SoundsPart; public const tipsBarClosedWidth:int = 17; @@ -289,7 +301,6 @@ public class Scratch extends Sprite { initSettings(); if(isOffline) DialogBox.notify("Welcome to Sharp!", "Website: http://SharpScratchMod.github.io\nGitHub: https://github.com/SharpScratchMod/Sharp\n\nCredits:\nDrKat123 - Developer, Owner\nMrcomputer1 - Developer, Owner\nscratchyone - Developer\n\nOther important credits:\nNoMod-Programming - Custom reporters"); - Tutorial.editorMap(); } protected function handleStartupParameters():void { @@ -1144,6 +1155,40 @@ public class Scratch extends Sprite { m.showOnStage(stage, b.x, topBarPart.bottom() - 1); } + public function showDevMenu(b:*):void{ + var m:Menu = new Menu(null, 'Dev', CSS.topBarColor(), 28); + + function devModeLogin():void{ + var d:DialogBox = new DialogBox(done); + function done():void{ + var hash:String = SHA256.hash(d.getField("Password")); + if(hash == devModePassword){ + devMode = true; + DialogBox.notify("Sharp Developer Mode", + "You are now logged in to Sharp Developer Mode!"); + }else{ + DialogBox.notify("Sharp Developer Mode", + "Wrong Password! :("); + } + } + d.addTitle("Sharp Developer Mode"); + d.addText("Please enter the Sharp Developer Password"); + d.addField("Password", 120, "", true); + d.setPasswordField("Password"); + d.addButton("Login Now", d.accept); + d.addButton("Cancel", d.cancel); + d.showOnStage(stage); + } + + if(!devMode){ + + m.addItem("Login to dev mode", devModeLogin); + + }else addDevMenuItems(b, m); + + m.showOnStage(stage, b.x, topBarPart.bottom() - 1); + } + public function stopVideo(b:*):void { runtime.stopVideo(); } @@ -1157,6 +1202,32 @@ public class Scratch extends Sprite { ]; } + protected function addDevMenuItems(b:*, m:Menu):void { + function devMenuAboutBuild(){ + DialogBox.notify("Sharp Developer Menu", + "Sharp Version: " + versionString.replace(" : Sharp Developer Mode Active", "") + "\n" + + "Host Protocol: " + hostProtocol + "\n" + + "Is in 3d: " + isIn3D + "\n" + + "Is ARM CPU: " + isArmCPU + "\n" + + "JS Enabled: " + jsEnabled + "\n" + + "Extension Dev Mode: " + isExtensionDevMode + "\n" + + "Uses Username Block: " + usesUserNameBlock + "\n" + + "Uses HTTP Block: " + usesHTTPBlock + "\n" + + "Turbo Mode is Active: " + turboModeIsActive + "\n" + + "Built with dev mode: " + SHARP::builtWithDevMode + "\n" + + "Build with allow3d: " + SCRATCH::allow3d); + } + function devMenuLogout(){ + devMode = false; + DialogBox.notify("Sharp Developer Menu", + "You have been logged out!"); + } + m.addItem("About this build", devMenuAboutBuild); + m.addItem("Logout of dev mode", devMenuLogout); + m.addLine(); + m.addItem("Tutorial: Editor Map", Tutorial.editorMap); + } + protected function addHelpMenuItems(b:*, m:Menu):void { function helpMenuItemCredits(){ DialogBox.notify("Credits", Translator.map("*Owner, # Non-Sharp Member") + "\n\nDrKat123*, Mrcomputer1*, scratchyone\n\nNoMod-Programming#"); diff --git a/src/Tutorial.as b/src/Tutorial.as new file mode 100644 index 000000000..b93c0e56a --- /dev/null +++ b/src/Tutorial.as @@ -0,0 +1,226 @@ +/* + * Sharp Project Editor and Player + * Copyright (C) 2016 Sharp Scratch Mod + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +// Tutorial.as +// Mrcomputer1, August 2016 +// +// The tutorial's code + +package { + import uiwidgets.*; + import flash.display.*; + +public class Tutorial { + + private static var stage:Stage = Scratch.app.stage; + + public static function editorMap():void{ + + var box:TutorialDoBox = new TutorialDoBox( + "Welcome to Sharp!\nLet's look at the editor!", + (stage.stageWidth - 190)/2, (stage.stageHeight - 100)/2); + function next18():void{ + box = new TutorialDoBox( + "This is the block categories.", + Scratch.app.scriptsPart.selector.x+40, + Scratch.app.scriptsPart.selector.y+40 + ); + box.addButton("Next", null); + box.addButton("End Tutorial", null, 70); + box.showOnStage(stage, false); + } + function next17():void{ + box = new TutorialDoBox( + "This is where all your\nsprites are listed!", + Scratch.app.libraryPart.x+40, + Scratch.app.libraryPart.y+40 + ); + box.addButton("Next", next18); + box.addButton("End Tutorial", null, 70); + box.showOnStage(stage, false); + } + function next16():void{ + box = new TutorialDoBox( + "This is the XY location\nof the mouse pointer", + Scratch.app.stagePart.yReadout.x+40, + Scratch.app.stagePart.yReadout.y+40 + ); + box.addButton("Next", next17); + box.addButton("End Tutorial", null, 70); + box.showOnStage(stage, true); + } + function next15():void{ + box = new TutorialDoBox( + "This is the Stop Sign!\nIt stops all the scripts\nrunning in the project", + Scratch.app.stagePart.stopButton.x+40, + Scratch.app.stagePart.stopButton.y+40 + ); + box.addButton("Next", next16); + box.addButton("End Tutorial", null, 70); + box.showOnStage(stage, true); + } + function next14():void{ + box = new TutorialDoBox( + "This is the Green Flag!\nIt runs the project!", + Scratch.app.stagePart.runButton.x+40, + Scratch.app.stagePart.runButton.y+40 + ); + box.addButton("Next", next15); + box.addButton("End Tutorial", null, 70); + box.showOnStage(stage, true); + } + function next13():void{ + box = new TutorialDoBox( + "This is fullscreen button\nClick it to toggle fullscreen\nBelow it is the Sharp\nversion information", + Scratch.app.stagePart.fullscreenButton.x+40, + Scratch.app.stagePart.fullscreenButton.y+40 + ); + box.addButton("Next", next14); + box.addButton("End Tutorial", null, 70); + box.showOnStage(stage, true); + } + function next12():void{ + box = new TutorialDoBox( + "This is the stage\nIt is where your sprites\nare shown", + Scratch.app.stagePart.x+40, + Scratch.app.stagePart.y+40 + ); + box.addButton("Next", next13); + box.addButton("End Tutorial", null, 70); + box.showOnStage(stage, false); + } + function next11():void{ + var box12:TutorialDoBox = new TutorialDoBox( + "That is all for the top bar\nNext is the layout of the\nmain editor!", + Scratch.app.topBarPart.helpTool.x+40, + Scratch.app.topBarPart.helpTool.y+10 + ); + box12.addButton("Next", next12); + box12.addButton("End Tutorial", null, 70); + box12.showOnStage(stage, false); + } + function next10():void{ + var box11:TutorialDoBox = new TutorialDoBox( + "This button does nothing at\nthis time\nJust ignore it!", + Scratch.app.topBarPart.helpTool.x+20, + Scratch.app.topBarPart.helpTool.y+10 + ); + box11.addButton("Next", next11); + box11.addButton("End Tutorial", null, 70); + box11.showOnStage(stage, true); + } + function next9():void{ + var box10:TutorialDoBox = new TutorialDoBox( + "You can use this to make\na sprite or costume smaller", + Scratch.app.topBarPart.shrinkTool.x+20, + Scratch.app.topBarPart.shrinkTool.y+10 + ); + box10.addButton("Next", next10); + box10.addButton("End Tutorial", null, 70); + box10.showOnStage(stage, true); + } + function next8():void{ + var box9:TutorialDoBox = new TutorialDoBox( + "You can use this to make\na sprite or costume bigger", + Scratch.app.topBarPart.growTool.x+20, + Scratch.app.topBarPart.growTool.y+10 + ); + box9.addButton("Next", next9); + box9.addButton("End Tutorial", null, 70); + box9.showOnStage(stage, true); + } + function next7():void{ + var box8:TutorialDoBox = new TutorialDoBox( + "You can use this to delete\na sprite or something else", + Scratch.app.topBarPart.cutTool.x+20, + Scratch.app.topBarPart.cutTool.y+10 + ); + box8.addButton("Next", next8); + box8.addButton("End Tutorial", null, 70); + box8.showOnStage(stage, true); + } + function next6():void{ + var box7:TutorialDoBox = new TutorialDoBox( + "You can use this to get\nmore of a sprite or something\nelse", + Scratch.app.topBarPart.copyTool.x+20, + Scratch.app.topBarPart.copyTool.y+10 + ); + box7.addButton("Next", next7); + box7.addButton("End Tutorial", null, 70); + box7.showOnStage(stage, true); + } + function next5():void{ + var box6:TutorialDoBox = new TutorialDoBox( + "In the Help menu you can\nreport bugs and see credits\nbut that is about it!", + Scratch.app.topBarPart.helpMenu.x+40, + Scratch.app.topBarPart.helpMenu.y+10 + ); + box6.addButton("Next", next6); + box6.addButton("End Tutorial", null, 70); + box6.showOnStage(stage, true); + } + function next4():void{ + var box5:TutorialDoBox = new TutorialDoBox( + "In the Edit menu you can\nundelete something and change\nthe colours of blocks", + Scratch.app.topBarPart.editMenu.x+40, + Scratch.app.topBarPart.editMenu.y+10 + ); + box5.addButton("Next", next5); + box5.addButton("End Tutorial", null, 70); + box5.showOnStage(stage, true); + } + function next3():void{ + var box4:TutorialDoBox = new TutorialDoBox( + "This is the File menu\nYou can save, load and create\na new project from it\nYou can also record the project", + Scratch.app.topBarPart.fileMenu.x+40, + Scratch.app.topBarPart.fileMenu.y+10 + ); + box4.addButton("Next", next4); + box4.addButton("End Tutorial", null, 70); + box4.showOnStage(stage, true); + } + function next2():void{ + var box3:TutorialDoBox = new TutorialDoBox( + "This is the language menu!\nYou can change what language\neverything is shown in\nTheir aren't many languages yet", + Scratch.app.topBarPart.languageButton.x+20, + Scratch.app.topBarPart.languageButton.y+10 + ); + box3.addButton("Next", next3); + box3.addButton("End Tutorial", null, 70); + box3.showOnStage(stage, true); + } + function next1():void{ + var box2:TutorialDoBox = new TutorialDoBox( + "This is the top bar!\nYou can do a lot of stuff with\nit", + Scratch.app.topBarPart.x+100, Scratch.app.topBarPart.y+20 + ); + box2.addButton("Next", next2); + box2.addButton("End Tutorial", null, 70); + box2.showOnStage(stage, false); + } + box.addButton("Next", next1); + box.addButton("End Tutorial", null, 70); + box.showOnStage(stage, false); + + } + +} + + +} \ No newline at end of file diff --git a/src/scratch/ScratchObj.as b/src/scratch/ScratchObj.as index a6fe8aca2..4c933a3fb 100644 --- a/src/scratch/ScratchObj.as +++ b/src/scratch/ScratchObj.as @@ -402,12 +402,20 @@ public class ScratchObj extends Sprite { /* Procedures */ - public function procedureDefinitions():Array { + public function procedureDefinitions():Array { var result:Array = []; for (var i:int = 0; i < scripts.length; i++) { var b:Block = scripts[i] as Block; if (b && (b.op == Specs.PROCEDURE_DEF)) result.push(b); } + var theStage:ScratchObj = Scratch.app.stagePane.objNamed("_stage_"); + var stageScripts:Array = theStage.scripts; + if(theStage != this){ + for (var i:int = 0; i < stageScripts.length; i++) { + var b:Block = stageScripts[i] as Block; + if (b && (b.op == Specs.PROCEDURE_DEF)) result.push(b); + } + } return result; } @@ -416,6 +424,12 @@ public class ScratchObj extends Sprite { var b:Block = scripts[i] as Block; if (b && (b.op == Specs.PROCEDURE_DEF) && (b.spec == procName)) return b; } + var theStage:ScratchObj = Scratch.app.stagePane.objNamed("_stage_"); + var stageScripts:Array = theStage.scripts; + for (var i:int = 0; i < stageScripts.length; i++) { + var b:Block = stageScripts[i] as Block; + if (b && (b.op == Specs.PROCEDURE_DEF) && (b.spec == procName)) return b; + } return null; } diff --git a/src/ui/parts/ScriptsPart.as b/src/ui/parts/ScriptsPart.as index cf707f106..e0067c9cd 100644 --- a/src/ui/parts/ScriptsPart.as +++ b/src/ui/parts/ScriptsPart.as @@ -36,7 +36,7 @@ import uiwidgets.*; public class ScriptsPart extends UIPart { private var shape:Shape; - private var selector:PaletteSelector; + public var selector:PaletteSelector; //was private private var spriteWatermark:Bitmap; protected var paletteFrame:ScrollFrame; protected var scriptsFrame:ScrollFrame; diff --git a/src/ui/parts/StagePart.as b/src/ui/parts/StagePart.as index 3a7d4a565..a934bf19d 100644 --- a/src/ui/parts/StagePart.as +++ b/src/ui/parts/StagePart.as @@ -51,9 +51,9 @@ public class StagePart extends UIPart { protected var projectInfo:TextField; private var versionInfo:TextField; private var turboIndicator:TextField; - private var runButton:IconButton; - private var stopButton:IconButton; - private var fullscreenButton:IconButton; + public var runButton:IconButton; //was private + public var stopButton:IconButton; //was private + public var fullscreenButton:IconButton; //was private private var stageSizeButton:Sprite; //video recording tools @@ -72,7 +72,7 @@ public class StagePart extends UIPart { private var xLabel:TextField; private var xReadout:TextField; private var yLabel:TextField; - private var yReadout:TextField; + public var yReadout:TextField; //was private public function StagePart(app:Scratch) { this.app = app; diff --git a/src/ui/parts/TopBarPart.as b/src/ui/parts/TopBarPart.as index ab94111ae..ade732b2b 100644 --- a/src/ui/parts/TopBarPart.as +++ b/src/ui/parts/TopBarPart.as @@ -44,12 +44,13 @@ public class TopBarPart extends UIPart { public var fileMenu:IconButton; //was protected public var editMenu:IconButton; //was protected public var helpMenu:IconButton; //was protected + private var devMenu:IconButton; public var copyTool:IconButton; //was private - private var cutTool:IconButton; - private var growTool:IconButton; - private var shrinkTool:IconButton; - private var helpTool:IconButton; + public var cutTool:IconButton; //was private + public var growTool:IconButton; //was private + public var shrinkTool:IconButton; //was private + public var helpTool:IconButton; //was private private var toolButtons:Array = []; private var toolOnMouseDown:String; @@ -94,8 +95,9 @@ public class TopBarPart extends UIPart { Scratch.app.showFileMenu(Menu.dummyButton()); Scratch.app.showEditMenu(Menu.dummyButton()); Scratch.app.showHelpMenu(Menu.dummyButton()); + if(Scratch.app.builtWithDevMode) Scratch.app.showDevMenu(Menu.dummyButton()); } - return ['File', 'Edit', "Help", 'Tips', 'Duplicate', 'Delete', 'Grow', 'Shrink', 'Block help', 'Offline Editor']; + return ['File', 'Edit', "Help", 'Tips', 'Duplicate', 'Delete', 'Grow', 'Shrink', 'Block help', 'Offline Editor', 'Dev']; } protected function removeTextButtons():void { @@ -103,6 +105,7 @@ public class TopBarPart extends UIPart { removeChild(fileMenu); removeChild(editMenu); removeChild(helpMenu); + if(Scratch.app.builtWithDevMode) removeChild(devMenu); } } @@ -156,6 +159,12 @@ public class TopBarPart extends UIPart { helpMenu.x = nextX; helpMenu.y = buttonY; nextX += helpMenu.width + buttonSpace; + + if(Scratch.app.builtWithDevMode){ + devMenu.x = nextX; + devMenu.y = buttonY; + nextX += devMenu.width + buttonSpace; + } // cursor tool buttons var space:int = 3; @@ -216,6 +225,7 @@ public class TopBarPart extends UIPart { addChild(fileMenu = makeMenuButton('File', app.showFileMenu, true)); addChild(editMenu = makeMenuButton('Edit', app.showEditMenu, true)); addChild(helpMenu = makeMenuButton('Help', app.showHelpMenu, true)); + if(Scratch.app.builtWithDevMode) addChild(devMenu = makeMenuButton('Dev', app.showDevMenu, true)); } private function addToolButtons():void { diff --git a/src/uiwidgets/TutorialDoBox.as b/src/uiwidgets/TutorialDoBox.as new file mode 100644 index 000000000..5582361de --- /dev/null +++ b/src/uiwidgets/TutorialDoBox.as @@ -0,0 +1,100 @@ +/* + * Sharp Project Editor and Player + * Copyright (C) 2016 Sharp Scratch Mod + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package uiwidgets{ + import flash.display.*; + import flash.events.*; + import flash.filters.DropShadowFilter; + import flash.text.*; + import ui.parts.UIPart; + +public class TutorialDoBox extends Sprite{ + private var text:String; + private var locx:int; + private var locy:int; + + public function TutorialDoBox(text:String = "Do something!", + locx:int = 0, locy:int = 0){ + this.text = text; + this.locx = locx; + this.locy = locy; + } + + private function drawBackground():void{ + var borderColor:int = 0xB0B0B0; + var arrowColor:int = 0xEEEEEE; + var g:Graphics = graphics; + g.clear(); + g.lineStyle(1.5, arrowColor, 1, true); + g.moveTo(locx, locy); + g.lineTo(locx+10, locy-10); + g.moveTo(locx, locy); + g.lineTo(locx+10, locy+10); + g.lineStyle(0.5, borderColor, 1, true); + g.beginFill(0xFFFFFF); + g.drawRect(locx+10, locy-10, 200, 100); + } + + private function drawNoArrow():void{ + var borderColor:int = 0xB0B0B0; + var g:Graphics = graphics; + g.clear(); + g.lineStyle(0.5, borderColor, 1, true); + g.beginFill(0xFFFFFF); + g.drawRect(locx+10, locy-10, 190, 100); + } + + private function makeTheTextLabel():VariableTextField{ + var format:TextFormat = new TextFormat(CSS.font, 14, CSS.textColor); + var result:VariableTextField = new VariableTextField(); + result.autoSize = TextFieldAutoSize.LEFT; + result.selectable = false; + result.background = false; + result.setText(text, null); + result.setTextFormat(format); + result.x = locx+15; + result.y = locy-10; + return result; + } + + public function remove():void{ + parent.removeChild(this); + } + + public function addButton(label:String, action:Function, x:int = 15, y:int = 60):void{ + function doAction():void { + remove(); + if(action != null) action(); + } + var b:Button = new Button(label, doAction); + b.x = locx+x; + b.y = locy+y; + addChild(b); + } + + public function showOnStage(stage:Stage, arrow:Boolean = true):void{ + if(arrow) drawBackground(); + if(!arrow) drawNoArrow(); + var t:TextField = makeTheTextLabel(); + addChild(t); + stage.addChild(this); + } +} + +} \ No newline at end of file From 98db0ac4a7ebe9e60f6080015f0f522d8452cdc3 Mon Sep 17 00:00:00 2001 From: Alexander Liu Date: Mon, 12 Sep 2016 12:38:05 +0700 Subject: [PATCH 111/141] Rename COPYING to LICENSE --- COPYING => LICENSE | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename COPYING => LICENSE (100%) diff --git a/COPYING b/LICENSE similarity index 100% rename from COPYING rename to LICENSE From 62851aee4d763edc4579ed1b4866e2ff56c85b0e Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Sat, 17 Sep 2016 14:33:38 +1000 Subject: [PATCH 112/141] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 5afadd889..11694f3a5 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ Sharp Scratch Mod by DrKat123 and Mrcomputer1 [![Build Status](https://travis-ci.org/SharpScratchMod/Sharp.svg?branch=master)](https://travis-ci.org/SharpScratchMod/Sharp) [![Version](https://img.shields.io/badge/version-beta%201.0.0-brightgreen.svg?style=flat-square)](https://github.com/SharpScratchMod/Sharp/releases/tag/v1.0.0-beta) [![License](https://img.shields.io/badge/license-GPL%20v2-brightgreen.svg?style=flat-square)](https://github.com/SharpScratchMod/Sharp/blob/master/COPYING) +[![Mirror: git.mrcomputer1.tk](https://img.shields.io/badge/mirror-git.mrcomputer1.tk-brightgreen.svg?style=flat-square)](https://git.mrcomputer1.tk/SharpScratchMod/Sharp) [Try it!](https://sharpscratchmod.github.io/Sharp.swf) [Scratch topic](https://scratch.mit.edu/discuss/topic/199192/) From 70165b455730e45a6d1db645b7ba54c79e85479b Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Sat, 17 Sep 2016 20:12:33 +1000 Subject: [PATCH 113/141] Update .travis.yml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index b11b79c42..d53f5e461 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,7 @@ cache: - $HOME/.gradle/caches/ - $HOME/.gradle/wrapper/dists/ before_install: + - mkdir -p /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/in/ && wget https://codeload.github.com/swfobject/swfobject/zip/2.2-O /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/in/swfobject_2_2.zip - mkdir -p /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/in/ && wget http://sourceforge.net/projects/osmf.adobe/files/OSMF%201.0%20%28final%20source%2C%20ASDocs%2C%20PDF%20guides%2C%20and%20release%20notes%29/OSMF_1.0.zip/download -O /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/in/OSMF_1.0.zip install: - ./gradlew build -Ptarget=11.6 From 48d405b9a3e1cd1258da137ebcdf11777bbaf63c Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Sat, 17 Sep 2016 20:13:43 +1000 Subject: [PATCH 114/141] Update .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d53f5e461..b15155a48 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ cache: - $HOME/.gradle/caches/ - $HOME/.gradle/wrapper/dists/ before_install: - - mkdir -p /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/in/ && wget https://codeload.github.com/swfobject/swfobject/zip/2.2-O /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/in/swfobject_2_2.zip + - mkdir -p /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/in/ && wget https://codeload.github.com/swfobject/swfobject/zip/2.2 -O /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/in/swfobject_2_2.zip - mkdir -p /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/in/ && wget http://sourceforge.net/projects/osmf.adobe/files/OSMF%201.0%20%28final%20source%2C%20ASDocs%2C%20PDF%20guides%2C%20and%20release%20notes%29/OSMF_1.0.zip/download -O /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/in/OSMF_1.0.zip install: - ./gradlew build -Ptarget=11.6 From b8d37c4fdd25615e7e6abc02fbbd3d87fc38b9dd Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Sat, 17 Sep 2016 20:28:36 +1000 Subject: [PATCH 115/141] Update .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b15155a48..16a22253f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ cache: - $HOME/.gradle/caches/ - $HOME/.gradle/wrapper/dists/ before_install: - - mkdir -p /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/in/ && wget https://codeload.github.com/swfobject/swfobject/zip/2.2 -O /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/in/swfobject_2_2.zip + - mkdir -p /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734 && wget https://www.dropbox.com/s/c6xavx90x3n5aov/apache-flex-sdk-4.10.0-bin.zip?dl=1 -O /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/apache-flex-sdk-4.10.0-bin.zip && unzip https://www.dropbox.com/s/c6xavx90x3n5aov/apache-flex-sdk-4.10.0-bin.zip?dl=1 -O /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/apache-flex-sdk-4.10.0-bin.zip -d /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734 && rm /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/apache-flex-sdk-4.10.0-bin.zip - mkdir -p /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/in/ && wget http://sourceforge.net/projects/osmf.adobe/files/OSMF%201.0%20%28final%20source%2C%20ASDocs%2C%20PDF%20guides%2C%20and%20release%20notes%29/OSMF_1.0.zip/download -O /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/in/OSMF_1.0.zip install: - ./gradlew build -Ptarget=11.6 From 2bec6e8575573d050305c35df4b35db1752c772e Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Sat, 17 Sep 2016 20:30:18 +1000 Subject: [PATCH 116/141] Update .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 16a22253f..33d5bc442 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ cache: - $HOME/.gradle/caches/ - $HOME/.gradle/wrapper/dists/ before_install: - - mkdir -p /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734 && wget https://www.dropbox.com/s/c6xavx90x3n5aov/apache-flex-sdk-4.10.0-bin.zip?dl=1 -O /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/apache-flex-sdk-4.10.0-bin.zip && unzip https://www.dropbox.com/s/c6xavx90x3n5aov/apache-flex-sdk-4.10.0-bin.zip?dl=1 -O /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/apache-flex-sdk-4.10.0-bin.zip -d /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734 && rm /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/apache-flex-sdk-4.10.0-bin.zip + - mkdir -p /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734 && wget https://www.dropbox.com/s/c6xavx90x3n5aov/apache-flex-sdk-4.10.0-bin.zip?dl=1 -O /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/apache-flex-sdk-4.10.0-bin.zip && unzip /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/apache-flex-sdk-4.10.0-bin.zip -d /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734 && rm /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/apache-flex-sdk-4.10.0-bin.zip - mkdir -p /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/in/ && wget http://sourceforge.net/projects/osmf.adobe/files/OSMF%201.0%20%28final%20source%2C%20ASDocs%2C%20PDF%20guides%2C%20and%20release%20notes%29/OSMF_1.0.zip/download -O /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/in/OSMF_1.0.zip install: - ./gradlew build -Ptarget=11.6 From faf02d350703e30e5b37248d115bd03504900d95 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Sat, 17 Sep 2016 20:42:58 +1000 Subject: [PATCH 117/141] Update .travis.yml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 33d5bc442..1cd8f5701 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,7 @@ cache: before_install: - mkdir -p /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734 && wget https://www.dropbox.com/s/c6xavx90x3n5aov/apache-flex-sdk-4.10.0-bin.zip?dl=1 -O /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/apache-flex-sdk-4.10.0-bin.zip && unzip /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/apache-flex-sdk-4.10.0-bin.zip -d /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734 && rm /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/apache-flex-sdk-4.10.0-bin.zip - mkdir -p /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/in/ && wget http://sourceforge.net/projects/osmf.adobe/files/OSMF%201.0%20%28final%20source%2C%20ASDocs%2C%20PDF%20guides%2C%20and%20release%20notes%29/OSMF_1.0.zip/download -O /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/in/OSMF_1.0.zip + - unzip /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/in/OSMF_1.0.zip -d /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/in && mv /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/in/OSMF.swc /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/frameworks/lis/OSMF.swc install: - ./gradlew build -Ptarget=11.6 - ./gradlew build -Ptarget=10.2 From da5116eda9487b3e7181eda148bf1efdd10f17c5 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Sat, 17 Sep 2016 20:44:27 +1000 Subject: [PATCH 118/141] Update .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 1cd8f5701..e0b03ea4f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ cache: before_install: - mkdir -p /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734 && wget https://www.dropbox.com/s/c6xavx90x3n5aov/apache-flex-sdk-4.10.0-bin.zip?dl=1 -O /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/apache-flex-sdk-4.10.0-bin.zip && unzip /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/apache-flex-sdk-4.10.0-bin.zip -d /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734 && rm /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/apache-flex-sdk-4.10.0-bin.zip - mkdir -p /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/in/ && wget http://sourceforge.net/projects/osmf.adobe/files/OSMF%201.0%20%28final%20source%2C%20ASDocs%2C%20PDF%20guides%2C%20and%20release%20notes%29/OSMF_1.0.zip/download -O /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/in/OSMF_1.0.zip - - unzip /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/in/OSMF_1.0.zip -d /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/in && mv /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/in/OSMF.swc /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/frameworks/lis/OSMF.swc + - unzip /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/in/OSMF_1.0.zip -d /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/in && mv /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/in/OSMF.swc /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/frameworks/libs/osmf.swc install: - ./gradlew build -Ptarget=11.6 - ./gradlew build -Ptarget=10.2 From 575e67902a947d8c21a097e60cc74fbf7e0ca953 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Thu, 22 Sep 2016 00:21:45 +1000 Subject: [PATCH 119/141] make file for windows --- Makefile | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..0bc1277ba --- /dev/null +++ b/Makefile @@ -0,0 +1,22 @@ +go: + @echo Building Sharp... + @.\gradlew build + @echo Building complete + +all: go dev +clean: + @del "build\11.6\*" /Q + @del "build\11.6dev\*" /Q + @rmdir build\11.6 + @rmdir build\11.6dev +dev: + @echo Building Sharp (Dev Mode)... + @.\gradlew build -Ptarget=11.6dev + @echo Building complete +help: + @echo "nmake" for a shortcut for "nmake go" + @echo. + @echo "nmake go" to build Sharp + @echo "nmake dev" to build Sharp with dev mode + @echo "nmake all" to build Sharp normally and build Sharp with dev mode + @echo "nmake clean" to clean out the build directory \ No newline at end of file From b667e9cc2d1f257b58aafe0f6b08243f6f00f91f Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Wed, 5 Oct 2016 14:28:58 +1000 Subject: [PATCH 120/141] Fixed #19 - Thanks @NoMod-Programming --- src/blocks/Block.as | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/blocks/Block.as b/src/blocks/Block.as index 9af82e3a0..59c6e81f6 100644 --- a/src/blocks/Block.as +++ b/src/blocks/Block.as @@ -576,7 +576,7 @@ public class Block extends Sprite { public function duplicate(forClone:Boolean, forStage:Boolean = false):Block { var newSpec:String = spec; if (op == 'whenClicked') newSpec = forStage ? 'when Stage clicked' : 'when this sprite clicked'; - var dup:Block = new Block(newSpec, procedureType ? procedureType : type, (int)(forClone ? -1 : base.color), op); + var dup:Block = new Block(newSpec, type, (int)(forClone ? -1 : base.color), op); dup.isRequester = isRequester; dup.forceAsync = forceAsync; dup.parameterNames = parameterNames; From 09ccce69c9c47d50bb41cafbfdd9e4a7a54d093c Mon Sep 17 00:00:00 2001 From: Alexander Liu Date: Sun, 9 Oct 2016 12:03:06 +0700 Subject: [PATCH 121/141] Bump flex version --- scratch.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scratch.gradle b/scratch.gradle index aaa9a7655..c82156016 100644 --- a/scratch.gradle +++ b/scratch.gradle @@ -42,7 +42,7 @@ def scratchFlashCommitID = getCommitID(commonDir) println "Commit ID for scratch-flash is: ${scratchFlashCommitID}" dependencies { - flexSDK group: 'org.apache', name: 'apache-flex-sdk', version: '4.10.0', ext: 'zip' + flexSDK group: 'org.apache', name: 'apache-flex-sdk', version: '4.14.1', ext: 'zip' external group: 'macromedia.com', name: 'playerglobal', version: playerVersion.replace('.', '_'), ext: 'swc' merged files( "${commonDir}/libs/as3corelib.swc", From d79b777bad73d375f631f84b96aa0bd934c5733f Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Wed, 12 Oct 2016 20:59:21 +1000 Subject: [PATCH 122/141] Bleeding Edge releases - Part 1 --- Makefile | 4 ++++ config.groovy | 13 +++++++++++++ src/CSS.as | 2 ++ src/Scratch.as | 8 +++++++- 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 0bc1277ba..0e5162374 100644 --- a/Makefile +++ b/Makefile @@ -13,6 +13,10 @@ dev: @echo Building Sharp (Dev Mode)... @.\gradlew build -Ptarget=11.6dev @echo Building complete +bleedingedge: + @echo Building Sharp (Bleeding Edge)... + @.\gradlew build -Ptarget=11.6be + @echo Building complete help: @echo "nmake" for a shortcut for "nmake go" @echo. diff --git a/config.groovy b/config.groovy index 488254a73..952f3404d 100644 --- a/config.groovy +++ b/config.groovy @@ -1,4 +1,14 @@ environments { + '11.6be' { + output = 'SharpBleedingEdge' + playerVersion = '11.6' + additionalCompilerOptions = [ + "-swf-version=19", + "-define+=SCRATCH::allow3d,true", + "-define+=SHARP::bleedingEdge,true", + "-define+=SHARP::builtWithDevMode,false", + ] + } '11.6dev' { output = 'SharpDev' playerVersion = '11.6' @@ -6,6 +16,7 @@ environments { "-swf-version=19", "-define+=SCRATCH::allow3d,true", "-define+=SHARP::builtWithDevMode,true", + "-define+=SHARP::bleedingEdge,false", ] } '11.6' { @@ -15,6 +26,7 @@ environments { "-swf-version=19", "-define+=SCRATCH::allow3d,true", "-define+=SHARP::builtWithDevMode,false", + "-define+=SHARP::bleedingEdge,false", ] } '10.2' { @@ -24,6 +36,7 @@ environments { "-swf-version=11", "-define+=SCRATCH::allow3d,false", "-define+=SHARP::builtWithDevMode,false", + "-define+=SHARP::bleedingEdge,false", ] } } diff --git a/src/CSS.as b/src/CSS.as index 2c49f2164..fe10c814f 100644 --- a/src/CSS.as +++ b/src/CSS.as @@ -28,6 +28,8 @@ package { public class CSS { + //To add a value for Sharp Bleeding Edge replace the color code with "!Scratch.app.bleedingEdge ? (old color code) : (new color code)" + public static function topBarColor():int { return Scratch.app.isExtensionDevMode ? topBarColor_ScratchX : topBarColor_default; } public static function backgroundColor():int { return Scratch.app.isExtensionDevMode ? backgroundColor_ScratchX : backgroundColor_default; } diff --git a/src/Scratch.as b/src/Scratch.as index ab2a47f0f..47c6c6412 100644 --- a/src/Scratch.as +++ b/src/Scratch.as @@ -78,7 +78,7 @@ import com.adobe.crypto.SHA256; public class Scratch extends Sprite { // Version - public static const versionString:String = 'Beta 1.0.0 (Katana) : Scratch v449' + (SHARP::builtWithDevMode ? " : Sharp Developer Mode Active" : ""); + public static const versionString:String = 'Beta 1.0.0 (Katana) : Scratch v449' + (SHARP::builtWithDevMode ? " : Sharp Developer Mode Active" : "") + (SHARP::bleedingEdge ? " : BLEEDING EDGE" : ""); public static var app:Scratch; // static reference to the app, used for debugging // Sharp Developer Menu // *------------------------------------* @@ -88,6 +88,7 @@ public class Scratch extends Sprite { // |s menu | // *------------------------------------* public var builtWithDevMode:Boolean = SHARP::builtWithDevMode; + public var bleedingEdge:Boolean = SHARP::bleedingEdge; public var devMode:Boolean = false; public var devModePassword:String = "99625b7abd0d05c32905b9aa67c9e6cb7e19ead8dc16d0caf5d372a8441dbd34"; @@ -1844,5 +1845,10 @@ public class Scratch extends Sprite { args.splice(1, 0, returnValueCallback); externalCall.apply(this, args); } + + // SHARP LIBRARY SYSTEM + public function importLibrary(id:String){ + DialogBox.notify("Hi!", "Imported " + id); + } } } From 5e3d90798f4f6befddfd28b7fc2b1ad778f09722 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Thu, 13 Oct 2016 20:55:51 +1000 Subject: [PATCH 123/141] Bleeding Edge Part 2 - Colours selected by @algmwc5 --- src/CSS.as | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CSS.as b/src/CSS.as index fe10c814f..3cef09576 100644 --- a/src/CSS.as +++ b/src/CSS.as @@ -39,8 +39,8 @@ public class CSS { // Colors public static const white:int = 0xFFFFFF; - public static const backgroundColor_default:int = white; - public static const topBarColor_default:int = 0x9C9EA2; + public static const backgroundColor_default:int = !Scratch.app.bleedingEdge ? white : 0xa6a6a6; + public static const topBarColor_default:int = !Scratch.app.bleedingEdge ? 0x9C9EA2 : 0x333333; public static const tabColor:int = 0xE6E8E8; public static const panelColor:int = 0xF2F2F2; public static const itemSelectedColor:int = 0xD0D0D0; From 2af88d2d30adac003d5ee9e1f873ef5dcb24ca18 Mon Sep 17 00:00:00 2001 From: 66A3E5BC207B4953 Date: Sat, 15 Oct 2016 07:45:48 +0700 Subject: [PATCH 124/141] update credits --- src/Scratch.as | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Scratch.as b/src/Scratch.as index d2fb96ca5..35c0ac74b 100644 --- a/src/Scratch.as +++ b/src/Scratch.as @@ -301,7 +301,7 @@ public class Scratch extends Sprite { handleStartupParameters(); initSettings(); - if(isOffline) DialogBox.notify("Welcome to Sharp!", "Website: http://SharpScratchMod.github.io\nGitHub: https://github.com/SharpScratchMod/Sharp\n\nCredits:\nDrKat123 - Developer, Owner\nMrcomputer1 - Developer, Owner\nscratchyone - Developer\n\nOther important credits:\nNoMod-Programming - Custom reporters"); + if(isOffline) DialogBox.notify("Welcome to Sharp!", "Website: http://SharpScratchMod.cf\nGitHub: https://github.com/SharpScratchMod/Sharp\n\nCredits:\nalgmwc5 - Developer, Owner\nMrcomputer1 - Developer, Owner\nscratchyone - Developer\n\nOther important credits:\nNoMod-Programming - Custom reporters"); } protected function handleStartupParameters():void { From 63421e84cc7aa71fd953157856d5ba98ff0cb3f6 Mon Sep 17 00:00:00 2001 From: 66A3E5BC207B4953 Date: Sat, 15 Oct 2016 18:46:06 +0700 Subject: [PATCH 125/141] factorial --- src/Specs.as | 1 + src/primitives/Primitives.as | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/src/Specs.as b/src/Specs.as index 143c3c63c..2fbaeb108 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -396,6 +396,7 @@ public class Specs { ["%m.mathOp of %n", "r", 8, "computeFunction:of:", "sqrt", 9], ["digital root of %n", "r", 8, "digitalRootOf:", "1234"], ["the constant %m.constantName", "r", 8, "chooseConstant:", "Pi"], + ["%n !", "r", 8, "factorialOf:", 5], ["-"], ["join %s %s", "r", 8, "concatenate:with:", "hello ", "world"], ["letter %n of %s", "r", 8, "letter:of:", 1, "world"], diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index c63e81f43..b88430b89 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -88,6 +88,7 @@ public class Primitives { primTable["bitwiseXor:"] = function(b:*):* { return interp.numarg(b[0]) ^ interp.numarg(b[1]) }; primTable["bitwiseLeftShift:"] = function(b:*):* { return interp.numarg(b[0]) << interp.numarg(b[1])}; primTable["bitwiseRightShift:"] = function(b:*):* { return interp.numarg(b[0]) >> interp.numarg(b[1])}; + primTable["factorialOf:"] = primFactorial; //this block doesn't work so please don't use it until we can fix it //primTable["bitwiseUnsignedShift"] = function(b:*):* { return interp.numarg(b[0]) >>> interp.numarg(b[1])}; @@ -436,4 +437,14 @@ public class Primitives { private function primFileLoadFailReason(b:Array):String{ return fileErrorValue; } + + private function primFactorial(b:Array):Number{ + function factorial(n:int){ + if (n < 2) { + return 1; + } + return n*factorial(n-1); + } + return factorial(interp.numarg(b[0])); + } }} From 17174dd001766e7886129e8381305c27c211c951 Mon Sep 17 00:00:00 2001 From: 66A3E5BC207B4953 Date: Sat, 15 Oct 2016 19:15:53 +0700 Subject: [PATCH 126/141] Fibonacci --- src/Specs.as | 1 + src/primitives/Primitives.as | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/Specs.as b/src/Specs.as index 2fbaeb108..a99757b8e 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -397,6 +397,7 @@ public class Specs { ["digital root of %n", "r", 8, "digitalRootOf:", "1234"], ["the constant %m.constantName", "r", 8, "chooseConstant:", "Pi"], ["%n !", "r", 8, "factorialOf:", 5], + ["%n th Fibonacci number", "r", 8, "nthFibonacci:", 10], ["-"], ["join %s %s", "r", 8, "concatenate:with:", "hello ", "world"], ["letter %n of %s", "r", 8, "letter:of:", 1, "world"], diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index b88430b89..83016109c 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -89,6 +89,7 @@ public class Primitives { primTable["bitwiseLeftShift:"] = function(b:*):* { return interp.numarg(b[0]) << interp.numarg(b[1])}; primTable["bitwiseRightShift:"] = function(b:*):* { return interp.numarg(b[0]) >> interp.numarg(b[1])}; primTable["factorialOf:"] = primFactorial; + primTable["nthFibonacci:"] = primFibonacci; //this block doesn't work so please don't use it until we can fix it //primTable["bitwiseUnsignedShift"] = function(b:*):* { return interp.numarg(b[0]) >>> interp.numarg(b[1])}; @@ -447,4 +448,21 @@ public class Primitives { } return factorial(interp.numarg(b[0])); } + private function primFibonacci(b:Array):Number{ + function getFibonacci(n:int){ + var f1:int, f2:int, f:int, i:int; + if(n < 2){ + return n; + } + f1 = 0; + f2 = 1; + for(i = 2; i <= n; i++){ + f = f1; + f1 = f2; + f2 = f + f1; + } + return f2; + } + return getFibonacci(interp.numarg(b[0])); + } }} From f0c4a349621208f0b39016034b1b68aefd5b03b7 Mon Sep 17 00:00:00 2001 From: 66A3E5BC207B4953 Date: Thu, 27 Oct 2016 09:12:27 +0700 Subject: [PATCH 127/141] base64 --- src/Specs.as | 5 ++++- src/primitives/Primitives.as | 21 +++++++++++++++++++++ src/ui/PaletteSelector.as | 4 ++-- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/Specs.as b/src/Specs.as index a99757b8e..ce73f0581 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -76,6 +76,7 @@ public class Specs { [12, "List", listColor], [13, "HTTP", 0x55af40], [14, "Files", 0x333399], + [15, "Miscellaneous", 0x657b32], [20, "Extension", extensionsColor], ]; @@ -396,7 +397,7 @@ public class Specs { ["%m.mathOp of %n", "r", 8, "computeFunction:of:", "sqrt", 9], ["digital root of %n", "r", 8, "digitalRootOf:", "1234"], ["the constant %m.constantName", "r", 8, "chooseConstant:", "Pi"], - ["%n !", "r", 8, "factorialOf:", 5], + [" %n !", "r", 8, "factorialOf:", 5], ["%n th Fibonacci number", "r", 8, "nthFibonacci:", 10], ["-"], ["join %s %s", "r", 8, "concatenate:with:", "hello ", "world"], @@ -453,6 +454,8 @@ public class Specs { ["loaded?", "b", 14, "fileLoaded:"], ["loading failed?", "b", 14, "fileLoadFailed:"], ["loading failure reason", "r", 14, "fileLoadFailReason:"], + //--MISCELLANEOUS-- + ["base64 encode %s", "r", 15, "b64encode:", "abcd"], // Scratch diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index 83016109c..71cdd806a 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -131,6 +131,7 @@ public class Primitives { primTable["fileLoaded:"] = primFileLoaded; primTable["fileLoadFailed:"] = primFileLoadFail; primTable["fileLoadFailReason:"] = primFileLoadFailReason; + primTable["b64encode:"] = primB64enc; new LooksPrims(app, interp).addPrimsTo(primTable, specialTable); new MotionAndPenPrims(app, interp).addPrimsTo(primTable, specialTable); @@ -465,4 +466,24 @@ public class Primitives { } return getFibonacci(interp.numarg(b[0])); } + + private function primB64enc(b:Array):String{ + function encode64(input) { + var output = "", i = 0, l = input.length, key = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", chr1, chr2, chr3, enc1, enc2, enc3, enc4; + while (i < l) { + chr1 = input.charCodeAt(i++); + chr2 = input.charCodeAt(i++); + chr3 = input.charCodeAt(i++); + enc1 = chr1 >> 2; + enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); + enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); + enc4 = chr3 & 63; + if (isNaN(chr2)) enc3 = enc4 = 64; + else if (isNaN(chr3)) enc4 = 64; + output = output + key.charAt(enc1) + key.charAt(enc2) + key.charAt(enc3) + key.charAt(enc4); + } + return output; + } + return encode64(b[0]); + } }} diff --git a/src/ui/PaletteSelector.as b/src/ui/PaletteSelector.as index b10404996..7c3e0d3e7 100644 --- a/src/ui/PaletteSelector.as +++ b/src/ui/PaletteSelector.as @@ -32,7 +32,7 @@ package ui { public class PaletteSelector extends Sprite { private static const categories:Array = [ - 'Motion', 'Looks', 'Sound', 'Pen', 'Data', 'HTTP', // column 1 + 'Motion', 'Looks', 'Sound', 'Pen', 'Data', 'HTTP', 'Miscellaneous', // column 1 'Events', 'Control', 'Sensing', 'Operators', 'More Blocks', 'Files']; // column 2 public var selectedCategory:int = 0; @@ -61,7 +61,7 @@ public class PaletteSelector extends Sprite { } private function initCategories():void { - const numberOfRows:int = 6; + const numberOfRows:int = 7; const w:int = 208; const startY:int = 3; var itemH:int; From 0fe6d7a7102164ff05aace63d2d085afcd2dab29 Mon Sep 17 00:00:00 2001 From: Alexander Liu Date: Thu, 27 Oct 2016 09:14:12 +0700 Subject: [PATCH 128/141] . --- src/primitives/Primitives.as | 1 + 1 file changed, 1 insertion(+) diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index 71cdd806a..199cee33f 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -469,6 +469,7 @@ public class Primitives { private function primB64enc(b:Array):String{ function encode64(input) { + //no decode yet, sorry :( var output = "", i = 0, l = input.length, key = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", chr1, chr2, chr3, enc1, enc2, enc3, enc4; while (i < l) { chr1 = input.charCodeAt(i++); From 650491dadc85dde060abdf4a6fb177b88d6d1226 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Tue, 1 Nov 2016 17:42:14 +1000 Subject: [PATCH 129/141] Fixes #23 --- src/ui/ProcedureSpecEditor.as | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ui/ProcedureSpecEditor.as b/src/ui/ProcedureSpecEditor.as index d566948d3..1381e1129 100644 --- a/src/ui/ProcedureSpecEditor.as +++ b/src/ui/ProcedureSpecEditor.as @@ -55,6 +55,9 @@ public class ProcedureSpecEditor extends Sprite { public function ProcedureSpecEditor(originalSpec:String, inputNames:Array, warpFlag:Boolean, type:String, isEdit:Boolean) { this.isEdit = isEdit; + if(isEdit){ + originalSpec = originalSpec.replace(/^@rabbit/g, ""); + } addChild(base = new Shape()); setWidthHeight(350, 10); From b09286dfae41ca9e75dd66283f78eb9e11c286b1 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Mon, 12 Dec 2016 21:58:35 +1000 Subject: [PATCH 130/141] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 11694f3a5..f8044fe9c 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ Sharp Scratch Mod by DrKat123 and Mrcomputer1 [![Version](https://img.shields.io/badge/version-beta%201.0.0-brightgreen.svg?style=flat-square)](https://github.com/SharpScratchMod/Sharp/releases/tag/v1.0.0-beta) [![License](https://img.shields.io/badge/license-GPL%20v2-brightgreen.svg?style=flat-square)](https://github.com/SharpScratchMod/Sharp/blob/master/COPYING) [![Mirror: git.mrcomputer1.tk](https://img.shields.io/badge/mirror-git.mrcomputer1.tk-brightgreen.svg?style=flat-square)](https://git.mrcomputer1.tk/SharpScratchMod/Sharp) + [Try it!](https://sharpscratchmod.github.io/Sharp.swf) [Scratch topic](https://scratch.mit.edu/discuss/topic/199192/) From fe4de774a0d6598d8228716081f88c30f1d79f1a Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Fri, 3 Feb 2017 22:19:27 +1000 Subject: [PATCH 131/141] Show/hide blocks can now show/hide other blocks --- src/Specs.as | 11 +++++++++-- src/blocks/Block.as | 15 ++++++++++++++- src/primitives/LooksPrims.as | 17 +++++++++++++++-- src/scratch/BlockMenus.as | 3 +++ src/scratch/ScratchObj.as | 4 ++++ 5 files changed, 45 insertions(+), 5 deletions(-) diff --git a/src/Specs.as b/src/Specs.as index ce73f0581..b7a7c1d6d 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -148,8 +148,8 @@ public class Specs { ["think %s for %n secs", " ", 2, "think:duration:elapsed:from:", "Hmm...", 2], ["think %s", " ", 2, "think:", "Hmm..."], ["-"], - ["show", " ", 2, "show"], - ["hide", " ", 2, "hide"], + ["show %m.spriteOnly", " ", 2, "showSprite", "_myself_"], + ["hide %m.spriteOnly", " ", 2, "hideSprite", "_myself_"], ["-"], ["switch costume to %m.costume", " ", 2, "lookLike:", "costume1"], ["next costume", " ", 2, "nextCostume"], @@ -170,6 +170,9 @@ public class Specs { ["size", "r", 2, "scale"], // stage looks + ["show %m.spriteNotSelf", " ", 102, "showStage", "Sprite1"], + ["hide %m.spriteNotSelf", " ", 102, "hideStage", "Sprite1"], + ["-"], ["switch backdrop to %m.backdrop", " ", 102, "startScene", "backdrop1"], ["switch backdrop to %m.backdrop and wait", " ", 102, "startSceneAndWait", "backdrop1"], ["next backdrop", " ", 102, "nextScene"], @@ -473,6 +476,10 @@ public class Specs { ["switch to background %m.costume", " ", 98, "showBackground:", "backdrop1"], ["next background", " ", 98, "nextBackground"], ["forever if %b", "cf",98, "doForeverIf"], + + // obsolete blocks from Official Scratch that may be used in older Sharp/current Scratch projects + ["legacy show", " ", 98, "show"], + ["legacy hide", " ", 98, "hide"], // testing and experimental control prims ["noop", "r", 99, "COUNT"], diff --git a/src/blocks/Block.as b/src/blocks/Block.as index f15fd1894..236d30bbb 100644 --- a/src/blocks/Block.as +++ b/src/blocks/Block.as @@ -40,6 +40,8 @@ import flash.events.*; import flash.filters.GlowFilter; import flash.geom.*; import flash.net.URLLoader; +import flash.net.URLRequest; +import flash.net.navigateToURL; import flash.text.*; import scratch.*; @@ -860,7 +862,7 @@ public class Block extends Sprite { else { Scratch.app.showTip(op); }*/ - var mappings = { + /* // Control - Sprite/Stage "inlineComment:": "control:inlineComment", "codeSection": "control:codeSection", @@ -870,7 +872,18 @@ public class Block extends Sprite { "INCR_COUNT": "control:INCR_COUNT", // Sensing "notify:": "sensing:notify" + */ + var mappings = { + "show": "obsolete:legacy_show_hide", + "hide": "obsolete:legacy_show_hide" }; + var path = "https://wiki.sharpscratchmod.cf/"; + if(mappings[op]){ + var req:URLRequest = new URLRequest(path + mappings[op]); + navigateToURL(req, "_blank"); + }else{ + DialogBox.notify("Sorry, No help for this block", "We don't have help for this block, sorry!"); + } } public function duplicateStack(deltaX:Number, deltaY:Number):void { diff --git a/src/primitives/LooksPrims.as b/src/primitives/LooksPrims.as index 168e119a2..0a78de2c3 100644 --- a/src/primitives/LooksPrims.as +++ b/src/primitives/LooksPrims.as @@ -69,6 +69,11 @@ public class LooksPrims { primTable['hide'] = primHide; // primTable['hideAll'] = primHideAll; + primTable['showStage'] = primShow; + primTable['hideStage'] = primHide; + primTable['showSprite'] = primShow; + primTable['hideSprite'] = primHide; + primTable['comeToFront'] = primGoFront; primTable['goBackByLayers:'] = primGoBack; @@ -244,7 +249,11 @@ public class LooksPrims { } private function primShow(b:Array):void { - var s:ScratchSprite = interp.targetSprite(); + if(b.length != 1 || b[0] == "_myself_"){ + var s:ScratchSprite = interp.targetSprite(); + }else{ + var s:ScratchSprite = Scratch.app.stagePane.spriteNamed(b[0]); + } if (s == null) return; s.visible = true; if(!app.isIn3D) s.applyFilters(); @@ -253,7 +262,11 @@ public class LooksPrims { } private function primHide(b:Array):void { - var s:ScratchSprite = interp.targetSprite(); + if(b.length != 1 || b[0] == "_myself_"){ + var s:ScratchSprite = interp.targetSprite(); + }else{ + var s:ScratchSprite = Scratch.app.stagePane.spriteNamed(b[0]); + } if ((s == null) || !s.visible) return; s.visible = false; if(!app.isIn3D) s.applyFilters(); diff --git a/src/scratch/BlockMenus.as b/src/scratch/BlockMenus.as index e2a22dfdf..75c555a79 100644 --- a/src/scratch/BlockMenus.as +++ b/src/scratch/BlockMenus.as @@ -95,6 +95,7 @@ public class BlockMenus implements DragClient { if (menuName == 'spriteOrStage') menuHandler.spriteMenu(evt, false, false, true, false, false); if (menuName == 'touching') menuHandler.spriteMenu(evt, true, true, false, false, false); if (menuName == 'stageOrThis') menuHandler.stageOrThisSpriteMenu(evt); + if (menuName == 'spriteNotSelf') menuHandler.spriteMenu(evt, false, false, false, false, false); if (menuName == 'stop') menuHandler.stopMenu(evt); if (menuName == 'timeAndDate') menuHandler.timeAndDateMenu(evt); if (menuName == 'triggerSensor') menuHandler.triggerSensorMenu(evt); @@ -139,6 +140,7 @@ public class BlockMenus implements DragClient { handler.spriteMenu(evt, true, false, false, false, true); handler.spriteMenu(evt, false, false, true, false, false); handler.spriteMenu(evt, true, true, false, false, false); + handler.spriteMenu(evt, false, false, false, false, false); handler.stageOrThisSpriteMenu(evt); handler.stopMenu(evt); handler.timeAndDateMenu(evt); @@ -193,6 +195,7 @@ public class BlockMenus implements DragClient { case 'spriteOrMouse': case 'location': case 'spriteOrStage': + case 'spriteNotSelf': case 'touching': return false; // handled directly by menu code case 'var': diff --git a/src/scratch/ScratchObj.as b/src/scratch/ScratchObj.as index 4c933a3fb..7a243c734 100644 --- a/src/scratch/ScratchObj.as +++ b/src/scratch/ScratchObj.as @@ -331,6 +331,10 @@ public class ScratchObj extends Sprite { sprites = Scratch.app.stagePane.sprites(); return (sprites.length > 0) ? ['x position', sprites[sprites.length - 1].objName] : ['volume', '_stage_']; } + if ('showStage' == op || 'hideStage' == op){ + sprites = Scratch.app.stagePane.sprites(); + return (sprites.length > 0) ? [sprites[sprites.length - 1].objName] : [""]; + } if ('setVar:to:' == op) return [defaultVarName(), 0]; if ('changeVar:by:' == op) return [defaultVarName(), 1]; From 7df9582a1de1d0869dcd5ba87b99dd73aafec4f9 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Thu, 29 Jun 2017 22:29:01 +1000 Subject: [PATCH 132/141] Fixed #20 --- src/blocks/Block.as | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/blocks/Block.as b/src/blocks/Block.as index 236d30bbb..4c22c6e5e 100644 --- a/src/blocks/Block.as +++ b/src/blocks/Block.as @@ -143,7 +143,7 @@ public class Block extends Sprite { indentLeft = 9; indentRight = 7; } else if (type == "r" || type == "R" || type == "or") { - this.type = 'r'; + this.type = type == "or" ? 'or' : 'r'; base = new BlockShape(type == "or" ? BlockShape.NumberOutlineShape : BlockShape.NumberShape, color); isReporter = true; forceAsync = (type == 'r') && Scratch.app.extensionManager.shouldForceAsync(op); @@ -587,6 +587,7 @@ public class Block extends Sprite { dup.defaultArgValues = defaultArgValues; dup.warpProcFlag = warpProcFlag; dup.procedureType = procedureType; + //DialogBox.notify("", newSpec + ":" + type + ":" + op + ":" + procedureType); if (forClone) { dup.copyArgsForClone(args); } else { From aa0e4e26c32b9990e2a12b926b7f7709f05b079a Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Thu, 29 Jun 2017 23:58:26 +1000 Subject: [PATCH 133/141] Fixed #15 I hope --- src/blocks/Block.as | 5 +++++ src/interpreter/Interpreter.as | 11 +++++++++++ src/scratch/BlockMenus.as | 1 + 3 files changed, 17 insertions(+) diff --git a/src/blocks/Block.as b/src/blocks/Block.as index 4c22c6e5e..bc183fe5a 100644 --- a/src/blocks/Block.as +++ b/src/blocks/Block.as @@ -845,8 +845,13 @@ public class Block extends Sprite { if ('cut' == tool) deleteStack(); } if (tool == 'help') showHelp(); + if (tool == "showSpec") showSpec(); } + public function showSpec(){ + DialogBox.notify("Block Spec Information", "Spec: " + this.spec + "\n" + "OP Code: " + this.op + "\nType: " + this.type); + } + public function showHelp():void { /*var extName:String = ExtensionManager.unpackExtensionName(op); if (extName) { diff --git a/src/interpreter/Interpreter.as b/src/interpreter/Interpreter.as index e2cfc244f..328e8e697 100644 --- a/src/interpreter/Interpreter.as +++ b/src/interpreter/Interpreter.as @@ -315,6 +315,17 @@ public class Interpreter { if(debugFunc != null) debugFunc(b); + if(b.op == "procDef" && (b.procedureType == "r" || b.procedureType == "b")){ + var curBlock:Block = b; + while(curBlock.nextBlock){ + curBlock = curBlock.nextBlock; + } + if(curBlock.op != "report"){ + curBlock.insertBlock(new Block("report %s", "f", Specs.procedureColor, "report", [0])); + DialogBox.notify("Warning", "A custom reporter/boolean was missing a report block!\nWe added one to prevent Sharp crashing."); + } + } + if (b.opFunction == primNoop) { // kludge: don't evaluate args for primNoop because procDef has weird ones activeThread.popState(); diff --git a/src/scratch/BlockMenus.as b/src/scratch/BlockMenus.as index 75c555a79..559a5423e 100644 --- a/src/scratch/BlockMenus.as +++ b/src/scratch/BlockMenus.as @@ -539,6 +539,7 @@ public class BlockMenus implements DragClient { m.addItem('add comment', block.addComment); } m.addItem('help', block.showHelp); + if(Scratch.app.builtWithDevMode) m.addItem('Show Block Spec', block.showSpec) m.addLine(); } From f41ea3cc8bc7e1e6d39b779f1eacc7f2131833c0 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Sat, 1 Jul 2017 16:19:05 +1000 Subject: [PATCH 134/141] Fixed #25 --- src/ui/ProcedureSpecEditor.as | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/ProcedureSpecEditor.as b/src/ui/ProcedureSpecEditor.as index 1381e1129..c54a493ca 100644 --- a/src/ui/ProcedureSpecEditor.as +++ b/src/ui/ProcedureSpecEditor.as @@ -293,7 +293,7 @@ public class ProcedureSpecEditor extends Sprite { for each (label in buttonLabels) if (label.parent) removeChild(label); for each (label in shapeLabels) if (label.parent) removeChild(label); for each (b in buttons) if (b.parent) removeChild(b); - for each (ib in shapeButtons) if (b.parent) removeChild(b); + for each (ib in shapeButtons) if (ib.parent) removeChild(ib); for each (shape in shapeIcons) if (shape.parent) removeChild(shape); if (warpCheckbox.parent) removeChild(warpCheckbox); if (warpLabel.parent) removeChild(warpLabel); From 5a547a1cc7773cd6bc2c3b298f75aece7655e45e Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Wed, 23 Aug 2017 17:29:46 +1000 Subject: [PATCH 135/141] Renamed some file blocks and fixed a bug --- src/Specs.as | 6 +++--- src/primitives/Primitives.as | 10 ++++++++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/Specs.as b/src/Specs.as index b7a7c1d6d..7c90c548c 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -454,9 +454,9 @@ public class Specs { ["load file", " ", 14, "loadFile:"], ["loaded file name", "r", 14, "loadedFileName:"], ["loaded file data", "r", 14, "loadedFileData:"], - ["loaded?", "b", 14, "fileLoaded:"], - ["loading failed?", "b", 14, "fileLoadFailed:"], - ["loading failure reason", "r", 14, "fileLoadFailReason:"], + ["loaded/saved?", "b", 14, "fileLoaded:"], + ["failed?", "b", 14, "fileLoadFailed:"], + ["failure reason", "r", 14, "fileLoadFailReason:"], //--MISCELLANEOUS-- ["base64 encode %s", "r", 15, "b64encode:", "abcd"], diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index 199cee33f..549b6ebef 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -347,6 +347,9 @@ public class Primitives { } //Sharp --- Files private function primFileSave(b:Array):void{ + fileLoadedValue = false; + fileErrored = false; + fileErrorValue = ""; DialogBox.confirm("Would you like to save the file '" + b[1] + "' to your computer?", null, okFunc, cancelFunc); function okFunc():void{ function cancelHandle(e:Event){ @@ -378,6 +381,9 @@ public class Primitives { } } private function primFileLoad(b:Array):void{ + fileLoadedValue = false; + fileErrored = false; + fileErrorValue = ""; DialogBox.confirm("Would you like to open a file from your computer?", null, okFunc, cancelFunc); function okFunc():void{ var fileName:String, data:ByteArray; @@ -429,8 +435,8 @@ public class Primitives { } } private function primFileLoaded(b:Array):Boolean{ - var bl:Boolean = fileLoadedValue; - fileLoadedValue = false; + //var bl:Boolean = fileLoadedValue; + //fileLoadedValue = false; return bl; } private function primFileLoadFail(b:Array):Boolean{ From d786b6448bcbb98a4ee969094bdc340e37724b14 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Wed, 23 Aug 2017 17:36:39 +1000 Subject: [PATCH 136/141] Fixed a build error I just made #fail :P --- src/primitives/Primitives.as | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as index 549b6ebef..7ca4c673d 100644 --- a/src/primitives/Primitives.as +++ b/src/primitives/Primitives.as @@ -437,7 +437,7 @@ public class Primitives { private function primFileLoaded(b:Array):Boolean{ //var bl:Boolean = fileLoadedValue; //fileLoadedValue = false; - return bl; + return fileLoadedValue; } private function primFileLoadFail(b:Array):Boolean{ return fileErrored; From 6a5aad7ac7b2e324c676e69dc743fb37f02cae47 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Sat, 26 Aug 2017 18:34:17 +1000 Subject: [PATCH 137/141] Changed some things to do something --- src/util/Server.as | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/util/Server.as b/src/util/Server.as index 98fc3ceb2..26e6f3295 100644 --- a/src/util/Server.as +++ b/src/util/Server.as @@ -265,12 +265,18 @@ public class Server implements IServer { // } //var url:String = URLs.assetCdnPrefix + URLs.internalAPI + 'asset/' + md5 + '/get/'; var url:String = "static/assets/" + md5; + if(Scratch.app.loaderInfo.parameters["requestPrefix"]){ + url = "../" + url; + } return serverGet(url, whenDone); } public function getMediaLibrary(libraryType:String, whenDone:Function):URLLoader { //var url:String = getCdnStaticSiteURL() + 'medialibraries/' + libraryType + 'Library.json'; var url:String = "static/medialibraries/" + libraryType + "Library.json"; + if(Scratch.app.loaderInfo.parameters["requestPrefix"]){ + url = "../" + url; + } return serverGet(url, whenDone); } @@ -299,7 +305,9 @@ public class Server implements IServer { function imageDecoded(e:Event):void { whenDone(makeThumbnail(e.target.content.bitmapData)); } - + if(Scratch.app.loaderInfo.parameters["requestPrefix"]){ + url = "../" + url; + } return serverGet(url, decodeImage); } @@ -327,10 +335,18 @@ public class Server implements IServer { //------------------------------ public function getLanguageList(whenDone:Function):void { + if(Scratch.app.loaderInfo.parameters["requestPrefix"]){ + serverGet("../locale/lang_list.txt", whenDone); + return; + } serverGet('locale/lang_list.txt', whenDone); } public function getPOFile(lang:String, whenDone:Function):void { + if(Scratch.app.loaderInfo.parameters["requestPrefix"]){ + serverGet("../locale/" + lang + ".po", whenDone); + return; + } serverGet('locale/' + lang + '.po', whenDone); } From bde9b46a990e4f520e05108434b231414eb16d35 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Sat, 26 Aug 2017 20:50:09 +1000 Subject: [PATCH 138/141] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f8044fe9c..75f5a86c5 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Sharp -Sharp Scratch Mod by DrKat123 and Mrcomputer1 +Sharp Scratch Mod by algmwc5 and Mrcomputer1 [![Gitter](https://badges.gitter.im/SharpScratchMod/Sharp.svg)](https://gitter.im/SharpScratchMod/Sharp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=body_badge) [![Build Status](https://travis-ci.org/SharpScratchMod/Sharp.svg?branch=master)](https://travis-ci.org/SharpScratchMod/Sharp) @@ -7,7 +7,7 @@ Sharp Scratch Mod by DrKat123 and Mrcomputer1 [![License](https://img.shields.io/badge/license-GPL%20v2-brightgreen.svg?style=flat-square)](https://github.com/SharpScratchMod/Sharp/blob/master/COPYING) [![Mirror: git.mrcomputer1.tk](https://img.shields.io/badge/mirror-git.mrcomputer1.tk-brightgreen.svg?style=flat-square)](https://git.mrcomputer1.tk/SharpScratchMod/Sharp) -[Try it!](https://sharpscratchmod.github.io/Sharp.swf) +[Try it!](https://sharpscratchmod.github.io/editor/) [Scratch topic](https://scratch.mit.edu/discuss/topic/199192/) From 8a8bd2f7d2a01fdf889294d985779934a58a8e0e Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Wed, 9 May 2018 20:46:58 +1000 Subject: [PATCH 139/141] Add some keys to key pressed? and when key pressed --- src/primitives/SensingPrims.as | 4 ++++ src/scratch/BlockMenus.as | 2 +- src/scratch/ScratchRuntime.as | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/primitives/SensingPrims.as b/src/primitives/SensingPrims.as index 0015205c7..4d46c3f6b 100644 --- a/src/primitives/SensingPrims.as +++ b/src/primitives/SensingPrims.as @@ -340,6 +340,10 @@ public class SensingPrims { case 'up arrow': ch = Keyboard.UP; break; case 'down arrow': ch = Keyboard.DOWN; break; case 'space': ch = Keyboard.SPACE; break; + case 'shift': ch = Keyboard.SHIFT; break; + case 'enter': ch = Keyboard.ENTER; break; + case 'backspace': ch = Keyboard.BACKSPACE; break; + case 'control': ch = Keyboard.CONTROL; break; default: ch = key.toUpperCase().charCodeAt(0); break; } return app.runtime.keyIsDown[ch] || false; diff --git a/src/scratch/BlockMenus.as b/src/scratch/BlockMenus.as index 559a5423e..cdcb08167 100644 --- a/src/scratch/BlockMenus.as +++ b/src/scratch/BlockMenus.as @@ -318,7 +318,7 @@ public class BlockMenus implements DragClient { private function keyMenu(evt:MouseEvent):void { var ch:int; - var namedKeys:Array = ['space', 'up arrow', 'down arrow', 'right arrow', 'left arrow', 'any']; + var namedKeys:Array = ['space', 'up arrow', 'down arrow', 'right arrow', 'left arrow', 'shift', 'enter', 'backspace', 'control', 'any']; var m:Menu = new Menu(setBlockArg, 'key'); for each (var s:String in namedKeys) m.addItem(s); for (ch = 97; ch < 123; ch++) m.addItem(String.fromCharCode(ch)); // a-z diff --git a/src/scratch/ScratchRuntime.as b/src/scratch/ScratchRuntime.as index ceac7ce18..9ee01f167 100644 --- a/src/scratch/ScratchRuntime.as +++ b/src/scratch/ScratchRuntime.as @@ -568,6 +568,10 @@ public class ScratchRuntime { case Keyboard.UP: keyName = 'up arrow'; break; case Keyboard.DOWN: keyName = 'down arrow'; break; case Keyboard.SPACE: keyName = 'space'; break; + case Keyboard.SHIFT: keyName = 'shift'; break; + case Keyboard.ENTER: keyName = 'enter'; break; + case Keyboard.BACKSPACE: keyName = 'backspace'; break; + case Keyboard.CONTROL: keyName = 'control'; break; default: keyName = String.fromCharCode(keyCode).toLowerCase(); break; } function startMatchingKeyHats(stack:Block, target:ScratchObj):void { From 02bf2f57ac8390a7effb8301741afe9f603c38b5 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Sat, 17 Nov 2018 20:48:21 +1000 Subject: [PATCH 140/141] changes --- src/Specs.as | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Specs.as b/src/Specs.as index 91f6578b8..5b6158920 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -375,7 +375,7 @@ public class Specs { ["%n - %n", "r", 8, "-", "", ""], ["%n * %n", "r", 8, "*", "", ""], ["%n / %n", "r", 8, "/", "", ""], - ["%n ^ %n", "r", 8, "power:of:", "", ""], + ["%n ^ %n", "r", 8, "power:of:", "", ""], ["-"], ["pick random %n to %n", "r", 8, "randomFrom:to:", 1, 10], ["-"], @@ -415,7 +415,7 @@ public class Specs { ["-"], ["%n & %n", "r", 8, "bitwiseAnd:", "1", "2"], ["%n | %n", "r", 8, "bitwiseOr:", "1", "2"], - ["%n ^ %n", "r", 8, "bitwiseXor:", "1", "2"], + ["%n XOR %n", "r", 8, "bitwiseXor:", "1", "2"], ["~ %n", "r", 8, "bitwiseNot:", "1", "2"], ["%n << %n", "r", 8, "bitwiseLeftShift:", "2", "10"], ["%n >> %n", "r", 8, "bitwiseRightShift:", "2", "10"], From 1239ffe0c25592a283c7dc1f11674be5ea22e059 Mon Sep 17 00:00:00 2001 From: Mrcomputer1 Date: Tue, 5 Feb 2019 17:48:43 +1000 Subject: [PATCH 141/141] Restore Scratch show/hide Blocks setting --- src/Scratch.as | 28 +++++++++++++++++++++++++++- src/Specs.as | 5 +++-- src/uiwidgets/DialogBox.as | 3 +++ 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/Scratch.as b/src/Scratch.as index f46812abb..cf7127733 100644 --- a/src/Scratch.as +++ b/src/Scratch.as @@ -94,7 +94,7 @@ public class Scratch extends Sprite { // Sharp settings store public var sharpSettings:SharedObject; - private var sharpSettingsVersion:int = 2; + private var sharpSettingsVersion:int = 3; private function initSettings():void{ if(!sharpSettings.data.hasOwnProperty("_settingsVersion")){ trace("Creating default setting values"); @@ -103,6 +103,7 @@ public class Scratch extends Sprite { sharpSettings.data.alwaysTurboMode = false; sharpSettings.data.hackMode = true; sharpSettings.data.cloneLimit = 300; + sharpSettings.data.restoreScratchShowHide = false; saveSettings(); }else{ updateSettings(); @@ -113,6 +114,24 @@ public class Scratch extends Sprite { if(sharpSettings.data.alwaysTurboMode){ toggleTurboMode(); } + reloadSettings(); + } + public function reloadSettings():void{ + // Reload "Restore Scratch show/hide Blocks" setting. + var showFound:Boolean = false; + var hideFound:Boolean = false; + var shouldBeVisible:Boolean = sharpSettings.data.restoreScratchShowHide; + for(var i = 0; i < Specs.commands.length; i++){ + if(Specs.commands[i][3] == "show"){ + Specs.commands[i][2] = shouldBeVisible ? 2 : 98; + showFound = true; + }else if(Specs.commands[i][3] == "hide"){ + Specs.commands[i][2] = shouldBeVisible ? 2 : 98; + hideFound = true; + } + if(showFound && hideFound) break; + } + updatePalette(); } public function saveSettings():void{ sharpSettings.flush(); @@ -129,6 +148,13 @@ public class Scratch extends Sprite { // do updates trace("Updated!"); }*/ + if(sharpSettings.data._settingsVersion == 2){ + trace("Updating settings from " + sharpSettings.data._settingsVersion + " to 3"); + sharpSettings.data.restoreScratchShowHide = false; + sharpSettings.data._settingsVersion = 3; + saveSettings(); + trace("Updated!"); + } if(sharpSettings.data._settingsVersion == 1){ trace("Updating settings from " + sharpSettings.data._settingsVersion + " to 2"); sharpSettings.data.hackMode = true; diff --git a/src/Specs.as b/src/Specs.as index 5b6158920..b8a1f1f59 100644 --- a/src/Specs.as +++ b/src/Specs.as @@ -151,6 +151,9 @@ public class Specs { ["show %m.spriteOnly", " ", 2, "showSprite", "_myself_"], ["hide %m.spriteOnly", " ", 2, "hideSprite", "_myself_"], ["-"], + ["scratch show", " ", 98, "show"],//This block is hidden by default, but shown by the "Restore Scratch show/hide Blocks" option + ["scratch hide", " ", 98, "hide"],//This block is hidden by default, but shown by the "Restore Scratch show/hide Blocks" option + ["-"], ["switch costume to %m.costume", " ", 2, "lookLike:", "costume1"], ["next costume", " ", 2, "nextCostume"], ["switch backdrop to %m.backdrop", " ", 2, "startScene", "backdrop1"], @@ -478,8 +481,6 @@ public class Specs { ["forever if %b", "cf",98, "doForeverIf"], // obsolete blocks from Official Scratch that may be used in older Sharp/current Scratch projects - ["legacy show", " ", 98, "show"], - ["legacy hide", " ", 98, "hide"], // testing and experimental control prims ["noop", "r", 99, "COUNT"], diff --git a/src/uiwidgets/DialogBox.as b/src/uiwidgets/DialogBox.as index 076fe592e..a1b901276 100644 --- a/src/uiwidgets/DialogBox.as +++ b/src/uiwidgets/DialogBox.as @@ -124,7 +124,9 @@ public class DialogBox extends Sprite { if(d.booleanFields['Always in turbo mode'].isOn() && !Scratch.app.turboModeIsActive) Scratch.app.toggleTurboMode(); Scratch.app.sharpSettings.data.hackMode = d.booleanFields['Hack mode'].isOn(); Scratch.app.sharpSettings.data.cloneLimit = d.fields['Clone limit'].text; + Scratch.app.sharpSettings.data.restoreScratchShowHide = d.booleanFields['Restore Scratch show/hide Blocks'].isOn(); Scratch.app.saveSettings(); + Scratch.app.reloadSettings(); } function resetSettings():void { DialogBox.confirm(Translator.map("Do you really want to reset settings?"), null, function():*{ Scratch.app.resetSettings(); }); @@ -134,6 +136,7 @@ public class DialogBox extends Sprite { d.addBoolean("Always in turbo mode", Scratch.app.sharpSettings.data.alwaysTurboMode, false); d.addBoolean("Hack mode", Scratch.app.sharpSettings.data.hackMode, false); d.addField("Clone limit", 120, Scratch.app.sharpSettings.data.cloneLimit, true); + d.addBoolean("Restore Scratch show/hide Blocks", Scratch.app.sharpSettings.data.restoreScratchShowHide, false); d.addButton("OK", d.accept); d.addButton("Cancel", d.cancel); d.addButton("Reset Settings", resetSettings);