summaryrefslogtreecommitdiff
path: root/objects.js
diff options
context:
space:
mode:
Diffstat (limited to 'objects.js')
-rw-r--r--objects.js505
1 files changed, 461 insertions, 44 deletions
diff --git a/objects.js b/objects.js
index a952515..96fda2e 100644
--- a/objects.js
+++ b/objects.js
@@ -125,7 +125,7 @@ PrototypeHatBlockMorph*/
// Global stuff ////////////////////////////////////////////////////////
-modules.objects = '2015-February-28';
+modules.objects = '2015-March-24';
var SpriteMorph;
var StageMorph;
@@ -464,6 +464,23 @@ SpriteMorph.prototype.initBlocks = function () {
category: 'sound',
spec: 'stop all sounds'
},
+ doSetVolume: {
+ type: 'command',
+ category: 'sound',
+ spec: 'set volume to %n %',
+ defaults: [100]
+ },
+ doChangeVolume: {
+ type: 'command',
+ category: 'sound',
+ spec: 'change volume by %n',
+ defaults: [-10]
+ },
+ reportVolume: {
+ type: 'reporter',
+ category: 'sound',
+ spec: 'volume'
+ },
doRest: {
type: 'command',
category: 'sound',
@@ -879,6 +896,11 @@ SpriteMorph.prototype.initBlocks = function () {
category: 'sensing',
spec: 'key %key pressed?'
},
+ getKeysPressed: {
+ type: 'reporter',
+ category: 'sensing',
+ spec: 'keys pressed'
+ },
reportDistanceTo: {
type: 'reporter',
category: 'sensing',
@@ -1160,6 +1182,13 @@ SpriteMorph.prototype.initBlocks = function () {
spec: 'script variables %scriptVars'
},
+ // inheritance - experimental
+ doDeleteAttr: {
+ type: 'command',
+ category: 'variables',
+ spec: 'delete %shd'
+ },
+
// Lists
reportNewList: {
type: 'reporter',
@@ -1233,6 +1262,29 @@ SpriteMorph.prototype.initBlocks = function () {
defaults: [localize('each item')]
},
+ // peer to peer communication
+ receivePeerMessage: {
+ type: 'hat',
+ category: 'other',
+ spec: 'when I receive %upvar from %upvar',
+ defaults: [localize('message'), localize('peer')]
+ },
+ sendPeerMessage: {
+ type: 'command',
+ category: 'other',
+ spec: 'send %s to %s'
+ },
+ reportPeerId: {
+ type: 'reporter',
+ category: 'other',
+ spec: 'my peer id'
+ },
+ reportPeerList: {
+ type: 'reporter',
+ category: 'other',
+ spec: 'peers online'
+ },
+
// Code mapping - experimental
doMapCodeOrHeader: { // experimental
type: 'command',
@@ -1379,6 +1431,8 @@ SpriteMorph.prototype.init = function (globals) {
this.version = Date.now(); // for observer optimization
this.isClone = false; // indicate a "temporary" Scratch-style clone
this.cloneOriginName = '';
+ this.volume = 100;
+ this.activeSounds = [];
// sprite nesting properties
this.parts = []; // not serialized, only anchor (name)
@@ -1405,11 +1459,13 @@ SpriteMorph.prototype.init = function (globals) {
'confetti': 0
};
+ // sprite inheritance
+ this.exemplar = null;
+
SpriteMorph.uber.init.call(this);
this.isDraggable = true;
this.isDown = false;
-
this.heading = 90;
this.changed();
this.drawNew();
@@ -1482,8 +1538,11 @@ SpriteMorph.prototype.appearIn = function (ide) {
// SpriteMorph versioning
SpriteMorph.prototype.setName = function (string) {
- this.name = string || this.name;
- this.version = Date.now();
+ if (string != 'mouse-pointer' && string != 'pen trails'
+ && string != 'edge') { // used by system
+ this.name = string || this.name;
+ this.version = Date.now();
+ }
};
// SpriteMorph rendering
@@ -1699,7 +1758,8 @@ SpriteMorph.prototype.variableBlock = function (varName) {
SpriteMorph.prototype.blockTemplates = function (category) {
var blocks = [], myself = this, varNames, button,
- cat = category || 'motion', txt;
+ cat = category || 'motion', txt,
+ inheritedVars = this.inheritedVariableNames();
function block(selector) {
if (StageMorph.prototype.hiddenPrimitives[selector]) {
@@ -1714,6 +1774,9 @@ SpriteMorph.prototype.blockTemplates = function (category) {
var newBlock = SpriteMorph.prototype.variableBlock(varName);
newBlock.isDraggable = false;
newBlock.isTemplate = true;
+ if (contains(inheritedVars, varName)) {
+ newBlock.ghost();
+ }
return newBlock;
}
@@ -1762,15 +1825,18 @@ SpriteMorph.prototype.blockTemplates = function (category) {
}
function addVar(pair) {
+ var ide;
if (pair) {
- if (myself.variables.silentFind(pair[0])) {
+ if (myself.isVariableNameInUse(pair[0], pair[1])) {
myself.inform('that name is already in use');
} else {
+ ide = myself.parentThatIsA(IDE_Morph);
myself.addVariable(pair[0], pair[1]);
- myself.toggleVariableWatcher(pair[0], pair[1]);
- myself.blocksCache[cat] = null;
- myself.paletteCache[cat] = null;
- myself.parentThatIsA(IDE_Morph).refreshPalette();
+ if (!myself.showingVariableWatcher(pair[0])) {
+ myself.toggleVariableWatcher(pair[0], pair[1]);
+ }
+ ide.flushBlocksCache('variables'); // b/c of inheritance
+ ide.refreshPalette();
}
}
}
@@ -1858,6 +1924,11 @@ SpriteMorph.prototype.blockTemplates = function (category) {
blocks.push(block('doPlaySoundUntilDone'));
blocks.push(block('doStopAllSounds'));
blocks.push('-');
+ blocks.push(block('doSetVolume'));
+ blocks.push(block('doChangeVolume'));
+ blocks.push(watcherToggle('reportVolume'));
+ blocks.push(block('reportVolume'));
+ blocks.push('-');
blocks.push(block('doRest'));
blocks.push('-');
blocks.push(block('doPlayNote'));
@@ -1976,6 +2047,7 @@ SpriteMorph.prototype.blockTemplates = function (category) {
blocks.push(block('reportMouseDown'));
blocks.push('-');
blocks.push(block('reportKeyPressed'));
+ blocks.push(block('getKeysPressed'));
blocks.push('-');
blocks.push(block('reportDistanceTo'));
blocks.push('-');
@@ -2099,7 +2171,7 @@ SpriteMorph.prototype.blockTemplates = function (category) {
button.showHelp = BlockMorph.prototype.showHelp;
blocks.push(button);
- if (this.variables.allNames().length > 0) {
+ if (this.deletableVariableNames().length > 0) {
button = new PushButtonMorph(
null,
function () {
@@ -2108,7 +2180,7 @@ SpriteMorph.prototype.blockTemplates = function (category) {
null,
myself
);
- myself.variables.allNames().forEach(function (name) {
+ myself.deletableVariableNames().forEach(function (name) {
menu.addItem(name, name);
});
menu.popUpAtHand(myself.world());
@@ -2138,6 +2210,13 @@ SpriteMorph.prototype.blockTemplates = function (category) {
blocks.push(block('doHideVar'));
blocks.push(block('doDeclareVariables'));
+ // inheritance:
+
+ blocks.push('-');
+ blocks.push(block('doDeleteAttr'));
+
+ ///////////////////////////////
+
blocks.push('=');
blocks.push(block('reportNewList'));
@@ -2174,6 +2253,13 @@ SpriteMorph.prototype.blockTemplates = function (category) {
blocks.push('=');
+ blocks.push(block('receivePeerMessage'));
+ blocks.push(block('sendPeerMessage'));
+ blocks.push(block('reportPeerId'));
+ blocks.push(block('reportPeerList'));
+
+ blocks.push('=');
+
if (StageMorph.prototype.enableCodeMapping) {
blocks.push(block('doMapCodeOrHeader'));
blocks.push(block('doMapStringCode'));
@@ -2562,7 +2648,7 @@ SpriteMorph.prototype.searchBlocks = function () {
SpriteMorph.prototype.addVariable = function (name, isGlobal) {
var ide = this.parentThatIsA(IDE_Morph);
if (isGlobal) {
- this.variables.parentFrame.addVar(name);
+ this.globalVariables().addVar(name);
if (ide) {
ide.flushBlocksCache('variables');
}
@@ -2574,7 +2660,10 @@ SpriteMorph.prototype.addVariable = function (name, isGlobal) {
SpriteMorph.prototype.deleteVariable = function (varName) {
var ide = this.parentThatIsA(IDE_Morph);
- this.deleteVariableWatcher(varName);
+ if (!contains(this.inheritedVariableNames(true), varName)) {
+ // check only shadowed variables
+ this.deleteVariableWatcher(varName);
+ }
this.variables.deleteVar(varName);
if (ide) {
ide.flushBlocksCache('variables'); // b/c the var could be global
@@ -2691,7 +2780,8 @@ SpriteMorph.prototype.reportCostumes = function () {
// SpriteMorph sound management
SpriteMorph.prototype.addSound = function (audio, name) {
- this.sounds.add(new Sound(audio, name));
+ var volume = this.volume;
+ this.sounds.add(new Sound(audio, name, volume));
};
SpriteMorph.prototype.playSound = function (name) {
@@ -2702,7 +2792,18 @@ SpriteMorph.prototype.playSound = function (name) {
),
active;
if (sound) {
+ sound.volume = this.volume;
active = sound.play();
+
+ if (stage.muted === true) {
+ active.volume = 0;
+ }
+
+ this.activeSounds.push(active);
+ this.activeSounds = this.activeSounds.filter(function (aud) {
+ return !aud.ended && !aud.terminated;
+ });
+
if (stage) {
stage.activeSounds.push(active);
stage.activeSounds = stage.activeSounds.filter(function (aud) {
@@ -2713,6 +2814,34 @@ SpriteMorph.prototype.playSound = function (name) {
}
};
+SpriteMorph.prototype.doSetVolume = function (val) {
+ var myself = this;
+ myself.volume = Math.min(Math.max(0, val), 100);
+
+ if (myself.parentThatIsA(StageMorph).muted === true) {
+ return;
+ }
+
+ myself.activeSounds.forEach(function (snd) {
+ snd.volume = myself.volume / 100; // 'audio' objects
+ });
+};
+
+SpriteMorph.prototype.doChangeVolume = function (val) {
+ this.doSetVolume(this.volume + val);
+};
+
+SpriteMorph.prototype.reportVolume = function () {
+ return this.volume;
+}
+
+SpriteMorph.prototype.unmuteAllSounds = function () {
+ var stage = this.parentThatIsA(StageMorph);
+ stage.muted = false;
+
+ this.doSetVolume(this.volume);
+};
+
SpriteMorph.prototype.reportSounds = function () {
return this.sounds;
};
@@ -3365,9 +3494,7 @@ Morph.prototype.setPosition = function (aPoint, justMe) {
// override the inherited default to make sure my parts follow
// unless it's justMe
var delta = aPoint.subtract(this.topLeft());
- if ((delta.x !== 0) || (delta.y !== 0)) {
- this.moveBy(delta, justMe);
- }
+ this.moveBy(delta, justMe);
};
SpriteMorph.prototype.forward = function (steps) {
@@ -3588,6 +3715,9 @@ SpriteMorph.prototype.allHatBlocksFor = function (message) {
if (morph.selector === 'receiveOnClone') {
return message === '__clone__init__';
}
+ if (morph.selector === 'receivePeerMessage') {
+ return message === '__peer__message__';
+ }
}
return false;
});
@@ -3597,7 +3727,19 @@ SpriteMorph.prototype.allHatBlocksForKey = function (key) {
return this.scripts.children.filter(function (morph) {
if (morph.selector) {
if (morph.selector === 'receiveKey') {
- return morph.inputs()[0].evaluate()[0] === key;
+ var selectedOption = morph.inputs()[0].evaluate()[0];
+
+ if (selectedOption === 'any key') {
+ return true;
+ }
+ if (selectedOption === 'number key' &&
+ (key >= '0' && key <= '9')) {
+ return true;
+ }
+ if (selectedOption === key) {
+ return true;
+ }
+ return false;
}
}
return false;
@@ -3666,6 +3808,16 @@ SpriteMorph.prototype.getTempo = function () {
return 0;
};
+// SpriteMorph last key
+
+SpriteMorph.prototype.getKeysPressed = function () {
+ var stage = this.parentThatIsA(StageMorph);
+ if (stage) {
+ return stage.getKeysPressed();
+ }
+ return '';
+};
+
// SpriteMorph last message
SpriteMorph.prototype.getLastMessage = function () {
@@ -3714,6 +3866,7 @@ SpriteMorph.prototype.reportThreadCount = function () {
SpriteMorph.prototype.findVariableWatcher = function (varName) {
var stage = this.parentThatIsA(StageMorph),
+ globals = this.globalVariables(),
myself = this;
if (stage === null) {
return null;
@@ -3723,7 +3876,7 @@ SpriteMorph.prototype.findVariableWatcher = function (varName) {
function (morph) {
return morph instanceof WatcherMorph
&& (morph.target === myself.variables
- || morph.target === myself.variables.parentFrame)
+ || morph.target === globals)
&& morph.getter === varName;
}
);
@@ -3731,6 +3884,7 @@ SpriteMorph.prototype.findVariableWatcher = function (varName) {
SpriteMorph.prototype.toggleVariableWatcher = function (varName, isGlobal) {
var stage = this.parentThatIsA(StageMorph),
+ globals = this.globalVariables(),
watcher,
others;
if (stage === null) {
@@ -3750,12 +3904,12 @@ SpriteMorph.prototype.toggleVariableWatcher = function (varName, isGlobal) {
// if no watcher exists, create a new one
if (isNil(isGlobal)) {
- isGlobal = contains(this.variables.parentFrame.names(), varName);
+ isGlobal = contains(globals.names(), varName);
}
watcher = new WatcherMorph(
varName,
this.blockColor.variables,
- isGlobal ? this.variables.parentFrame : this.variables,
+ isGlobal ? globals : this.variables,
varName
);
watcher.setPosition(stage.position().add(10));
@@ -4181,6 +4335,129 @@ SpriteMorph.prototype.restoreLayers = function () {
this.layers = null;
};
+// SpriteMorph inheritance - general
+
+SpriteMorph.prototype.chooseExemplar = function () {
+ var stage = this.parentThatIsA(StageMorph),
+ myself = this,
+ other = stage.children.filter(function (m) {
+ return m instanceof SpriteMorph &&
+ (!contains(m.allExemplars(), myself));
+ }),
+ menu;
+ menu = new MenuMorph(
+ function (aSprite) {myself.setExemplar(aSprite); },
+ localize('current parent') +
+ ':\n' +
+ (this.exemplar ? this.exemplar.name : localize('none'))
+ );
+ other.forEach(function (eachSprite) {
+ menu.addItem(eachSprite.name, eachSprite);
+ });
+ menu.addLine();
+ menu.addItem(localize('none'), null);
+ menu.popUpAtHand(this.world());
+};
+
+SpriteMorph.prototype.setExemplar = function (another) {
+ var ide = this.parentThatIsA(IDE_Morph);
+ this.exemplar = another;
+ if (isNil(another)) {
+ this.variables.parentFrame = (this.globalVariables());
+ } else {
+ this.variables.parentFrame = (another.variables);
+ }
+ if (ide) {
+ ide.flushBlocksCache('variables');
+ ide.refreshPalette();
+ }
+};
+
+SpriteMorph.prototype.allExemplars = function () {
+ // including myself
+ var all = [],
+ current = this;
+ while (!isNil(current)) {
+ all.push(current);
+ current = current.exemplar;
+ }
+ return all;
+};
+
+SpriteMorph.prototype.specimens = function () {
+ // without myself
+ var myself = this;
+ return this.siblings().filter(function (m) {
+ return m instanceof SpriteMorph && (m.exemplar === myself);
+ });
+};
+
+SpriteMorph.prototype.allSpecimens = function () {
+ // without myself
+ var myself = this;
+ return this.siblings().filter(function (m) {
+ return m instanceof SpriteMorph && contains(m.allExemplars(), myself);
+ });
+};
+
+// SpriteMorph inheritance - variables
+
+SpriteMorph.prototype.isVariableNameInUse = function (vName, isGlobal) {
+ if (isGlobal) {
+ return contains(this.variables.allNames(), vName);
+ }
+ if (contains(this.variables.names(), vName)) {return true; }
+ return contains(this.globalVariables().names(), vName);
+};
+
+SpriteMorph.prototype.globalVariables = function () {
+ var current = this.variables.parentFrame;
+ while (current.owner) {
+ current = current.parentFrame;
+ }
+ return current;
+};
+
+SpriteMorph.prototype.shadowVar = function (name, value) {
+ var ide = this.parentThatIsA(IDE_Morph);
+ this.variables.addVar(name, value);
+ if (ide) {
+ ide.flushBlocksCache('variables');
+ ide.refreshPalette();
+ }
+};
+
+SpriteMorph.prototype.inheritedVariableNames = function (shadowedOnly) {
+ var names = [],
+ own = this.variables.names(),
+ current = this.variables.parentFrame;
+
+ function test(each) {
+ return shadowedOnly ? contains(own, each) : !contains(own, each);
+ }
+
+ while (current.owner instanceof SpriteMorph) {
+ names.push.apply(
+ names,
+ current.names().filter(test)
+ );
+ current = current.parentFrame;
+ }
+ return names;
+};
+
+SpriteMorph.prototype.deletableVariableNames = function () {
+ var locals = this.variables.names(),
+ inherited = this.inheritedVariableNames();
+ return locals.concat(
+ this.globalVariables().names().filter(
+ function (each) {
+ return !contains(locals, each) && !contains(inherited, each);
+ }
+ )
+ );
+};
+
// SpriteMorph highlighting
SpriteMorph.prototype.addHighlight = function (oldHighlight) {
@@ -4421,6 +4698,8 @@ StageMorph.prototype.init = function (globals) {
this.version = Date.now(); // for observers
this.isFastTracked = false;
this.cloneCount = 0;
+ this.volume = 100;
+ this.muted = false;
this.timerStart = Date.now();
this.tempo = 60; // bpm
@@ -4464,6 +4743,51 @@ StageMorph.prototype.init = function (globals) {
this.fps = this.frameRate;
};
+StageMorph.prototype.newPeerMessage = function (data, peer) {
+ var ide = this.parentThatIsA(IDE_Morph);
+ if (!ide || !peer) return;
+ var myself = this;
+ var hats = [], model, message;
+
+ try {
+ model = ide.serializer.parse(data);
+ message = ide.serializer.loadValue(model);
+
+ // TODO: If a Context is sent, a new Sprite appears.
+ // This below is just a workaround for one-level rings,
+ // objects should be cleaned recursively.
+ message.receiver = null;
+ message.outerContext = null;
+ } catch (err) {
+ console.log(err); // DEBUG
+ // Ok, it does not seem to be XML. It must be a string then.
+ message = data;
+ }
+
+ // call hat blocks
+ this.children.concat(myself).forEach(function (morph) {
+ if (morph instanceof SpriteMorph
+ || morph instanceof StageMorph) {
+ hats = hats.concat(
+ morph.allHatBlocksFor('__peer__message__'));
+ }
+ });
+ hats.forEach(function (block) {
+ var process = myself.threads.startProcess(block,
+ myself.isThreadSafe);
+ process.context.outerContext.variables.addVar(localize('message'));
+ process.context.outerContext.variables.setVar(
+ localize('message'),
+ message
+ );
+ process.context.outerContext.variables.addVar(localize('peer'));
+ process.context.outerContext.variables.setVar(
+ localize('peer'),
+ peer
+ );
+ });
+};
+
// StageMorph scaling
StageMorph.prototype.setScale = function (number) {
@@ -4709,6 +5033,16 @@ StageMorph.prototype.getTempo = function () {
return +this.tempo;
};
+// StageMorph keys
+
+StageMorph.prototype.getKeysPressed = function () {
+ var keys = [];
+ for (var key in this.keysPressed) {
+ keys.push(key);
+ }
+ return new List(keys);
+};
+
// StageMorph messages
StageMorph.prototype.getLastMessage = function () {
@@ -4762,7 +5096,7 @@ StageMorph.prototype.step = function () {
world.keyboardReceiver = this;
}
if (world.currentKey === null) {
- this.keyPressed = null;
+ this.keysPressed = {};
}
// manage threads
@@ -4950,7 +5284,7 @@ StageMorph.prototype.fireGreenFlagEvent = function () {
StageMorph.prototype.fireStopAllEvent = function () {
var ide = this.parentThatIsA(IDE_Morph);
- this.threads.resumeAll(this.stage);
+ //this.threads.resumeAll(this.stage); // leads to a strange Note bug
this.keysPressed = {};
this.threads.stopAll();
this.stopAllActiveSounds();
@@ -5042,7 +5376,7 @@ StageMorph.prototype.blockTemplates = function (category) {
function addVar(pair) {
if (pair) {
- if (myself.variables.silentFind(pair[0])) {
+ if (myself.isVariableNameInUse(pair[0])) {
myself.inform('that name is already in use');
} else {
myself.addVariable(pair[0], pair[1]);
@@ -5106,6 +5440,11 @@ StageMorph.prototype.blockTemplates = function (category) {
blocks.push(block('doPlaySoundUntilDone'));
blocks.push(block('doStopAllSounds'));
blocks.push('-');
+ blocks.push(block('doSetVolume'));
+ blocks.push(block('doChangeVolume'));
+ blocks.push(watcherToggle('reportVolume'));
+ blocks.push(block('reportVolume'));
+ blocks.push('-');
blocks.push(block('doRest'));
blocks.push('-');
blocks.push(block('doPlayNote'));
@@ -5204,6 +5543,7 @@ StageMorph.prototype.blockTemplates = function (category) {
blocks.push(block('reportMouseDown'));
blocks.push('-');
blocks.push(block('reportKeyPressed'));
+ blocks.push(block('getKeysPressed'));
blocks.push('-');
blocks.push(block('doResetTimer'));
blocks.push(watcherToggle('getTimer'));
@@ -5359,9 +5699,7 @@ StageMorph.prototype.blockTemplates = function (category) {
blocks.push(block('doShowVar'));
blocks.push(block('doHideVar'));
blocks.push(block('doDeclareVariables'));
-
blocks.push('=');
-
blocks.push(block('reportNewList'));
blocks.push('-');
blocks.push(block('reportCONS'));
@@ -5396,6 +5734,12 @@ StageMorph.prototype.blockTemplates = function (category) {
blocks.push('=');
+ blocks.push(block('receivePeerMessage'));
+ blocks.push(block('sendPeerMessage'));
+ blocks.push(block('reportPeerId'));
+ blocks.push(block('reportPeerList'));
+ blocks.push('=');
+
if (StageMorph.prototype.enableCodeMapping) {
blocks.push(block('doMapCodeOrHeader'));
blocks.push(block('doMapStringCode'));
@@ -5654,6 +5998,15 @@ StageMorph.prototype.addSound
StageMorph.prototype.playSound
= SpriteMorph.prototype.playSound;
+StageMorph.prototype.doSetVolume
+ = SpriteMorph.prototype.doSetVolume;
+
+StageMorph.prototype.doChangeVolume
+ = SpriteMorph.prototype.doChangeVolume;
+
+StageMorph.prototype.reportVolume
+ = SpriteMorph.prototype.reportVolume;
+
StageMorph.prototype.stopAllActiveSounds = function () {
this.activeSounds.forEach(function (audio) {
audio.pause();
@@ -5668,11 +6021,29 @@ StageMorph.prototype.pauseAllActiveSounds = function () {
};
StageMorph.prototype.resumeAllActiveSounds = function () {
+ var newSounds = []; // remove Sounds that have been played so they do not resume
+
+ this.activeSounds.forEach(function (audio) {
+ if (audio.ended === false) {
+ newSounds.push(audio);
+ audio.play();
+ }
+ });
+
+ this.activeSounds = newSounds;
+};
+
+StageMorph.prototype.muteAllSounds = function () {
+ this.muted = true;
+
this.activeSounds.forEach(function (audio) {
- audio.play();
+ audio.volume = 0;
});
};
+StageMorph.prototype.unmuteAllSounds
+ = SpriteMorph.prototype.unmuteAllSounds;
+
StageMorph.prototype.reportSounds
= SpriteMorph.prototype.reportSounds;
@@ -5751,6 +6122,18 @@ StageMorph.prototype.doubleDefinitionsFor
StageMorph.prototype.replaceDoubleDefinitionsFor
= SpriteMorph.prototype.replaceDoubleDefinitionsFor;
+// StageMorph inheritance support - variables
+
+StageMorph.prototype.isVariableNameInUse
+ = SpriteMorph.prototype.isVariableNameInUse;
+
+StageMorph.prototype.globalVariables
+ = SpriteMorph.prototype.globalVariables;
+
+StageMorph.prototype.inheritedVariableNames = function () {
+ return [];
+};
+
// SpriteBubbleMorph ////////////////////////////////////////////////////////
/*
@@ -6442,9 +6825,10 @@ CostumeEditorMorph.prototype.mouseMove
// Sound instance creation
-function Sound(audio, name) {
+function Sound(audio, name, volume) {
this.audio = audio; // mandatory
this.name = name || "Sound";
+ this.volume = volume || 100;
}
Sound.prototype.play = function () {
@@ -6452,6 +6836,7 @@ Sound.prototype.play = function () {
// externally (i.e. by the stage)
var aud = document.createElement('audio');
aud.src = this.audio.src;
+ aud.volume = Math.min(Math.max(0, this.volume), 100) / 100;
aud.play();
return aud;
};
@@ -6461,7 +6846,8 @@ Sound.prototype.copy = function () {
cpy;
snd.src = this.audio.src;
- cpy = new Sound(snd, this.name ? copy(this.name) : null);
+ snd.volume = this.volume;
+ cpy = new Sound(snd, this.name ? copy(this.name) : null, this.volume ? copy(this.volume) : null);
return cpy;
};
@@ -6475,8 +6861,9 @@ Sound.prototype.toDataURL = function () {
// Note instance creation
-function Note(pitch) {
+function Note(pitch, volume) {
this.pitch = pitch === 0 ? 0 : pitch || 69;
+ this.volume = volume;
this.setupContext();
this.oscillator = null;
}
@@ -6507,12 +6894,13 @@ Note.prototype.setupContext = function () {
}
Note.prototype.audioContext = new AudioContext();
Note.prototype.gainNode = Note.prototype.audioContext.createGain();
- Note.prototype.gainNode.gain.value = 0.25; // reduce volume by 1/4
};
// Note playing
Note.prototype.play = function () {
+ this.gainNode.gain.value = 0.25 * this.volume / 100; // reduce volume by 1/4
+
this.oscillator = this.audioContext.createOscillator();
if (!this.oscillator.start) {
this.oscillator.start = this.oscillator.noteOn;
@@ -6528,6 +6916,12 @@ Note.prototype.play = function () {
this.oscillator.start(0);
};
+Note.prototype.setVolume = function (volume) {
+ this.stop();
+ this.volume = volume;
+ this.play();
+}
+
Note.prototype.stop = function () {
if (this.oscillator) {
this.oscillator.stop(0);
@@ -6956,7 +7350,7 @@ WatcherMorph.prototype.object = function () {
WatcherMorph.prototype.isGlobal = function (selector) {
return contains(
- ['getLastAnswer', 'getLastMessage', 'getTempo', 'getTimer',
+ ['getLastAnswer', 'getKeysPressed', 'getLastMessage', 'getTempo', 'getTimer',
'reportMouseX', 'reportMouseY', 'reportThreadCount'],
selector
);
@@ -6964,32 +7358,51 @@ WatcherMorph.prototype.isGlobal = function (selector) {
// WatcherMorph slider accessing:
-WatcherMorph.prototype.setSliderMin = function (num) {
+WatcherMorph.prototype.setSliderMin = function (num, noUpdate) {
if (this.target instanceof VariableFrame) {
- this.sliderMorph.setSize(1);
- this.sliderMorph.setStart(num);
- this.sliderMorph.setSize(this.sliderMorph.rangeSize() / 5);
+ this.sliderMorph.setSize(1, noUpdate);
+ this.sliderMorph.setStart(num, noUpdate);
+ this.sliderMorph.setSize(this.sliderMorph.rangeSize() / 5, noUpdate);
}
};
-WatcherMorph.prototype.setSliderMax = function (num) {
+WatcherMorph.prototype.setSliderMax = function (num, noUpdate) {
if (this.target instanceof VariableFrame) {
- this.sliderMorph.setSize(1);
- this.sliderMorph.setStop(num);
- this.sliderMorph.setSize(this.sliderMorph.rangeSize() / 5);
+ this.sliderMorph.setSize(1, noUpdate);
+ this.sliderMorph.setStop(num, noUpdate);
+ this.sliderMorph.setSize(this.sliderMorph.rangeSize() / 5, noUpdate);
}
};
// WatcherMorph updating:
WatcherMorph.prototype.update = function () {
- var newValue,
- num;
+ var newValue, sprite, num;
+
if (this.target && this.getter) {
this.updateLabel();
if (this.target instanceof VariableFrame) {
newValue = this.target.vars[this.getter] ?
this.target.vars[this.getter].value : undefined;
+ if (newValue === undefined && this.target.owner) {
+ sprite = this.target.owner;
+ if (contains(sprite.inheritedVariableNames(), this.getter)) {
+ newValue = this.target.getVar(this.getter);
+ // ghost cell color
+ this.cellMorph.setColor(
+ SpriteMorph.prototype.blockColor.variables
+ .lighter(35)
+ );
+ } else {
+ this.destroy();
+ return;
+ }
+ } else {
+ // un-ghost the cell color
+ this.cellMorph.setColor(
+ SpriteMorph.prototype.blockColor.variables
+ );
+ }
} else {
newValue = this.target[this.getter]();
}
@@ -7074,7 +7487,11 @@ WatcherMorph.prototype.fixLayout = function () {
this.sliderMorph.button.pressColor.b += 100;
this.sliderMorph.setHeight(fontSize);
this.sliderMorph.action = function (num) {
- myself.target.vars[myself.getter].value = Math.round(num);
+ myself.target.setVar(
+ myself.getter,
+ Math.round(num),
+ myself.target.owner
+ );
};
this.add(this.sliderMorph);
}