2013-10-28 20:00:20 +00:00
// Copyright (C) 2013 Massachusetts Institute of Technology
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License version 2,
// as published by the Free Software Foundation.
//
// 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.
'use strict' ;
2013-11-01 22:44:51 -04:00
var SensingPrims = function ( ) { } ;
2013-10-28 20:00:20 +00:00
SensingPrims . prototype . addPrimsTo = function ( primTable ) {
primTable [ 'touching:' ] = this . primTouching ;
primTable [ 'touchingColor:' ] = this . primTouchingColor ;
primTable [ 'color:sees:' ] = this . primColorTouchingColor ;
2013-11-01 22:44:51 -04:00
2014-03-09 11:59:38 -06:00
primTable [ 'doAsk' ] = this . primDoAsk ;
primTable [ 'answer' ] = this . primAnswer ;
2013-10-28 20:00:20 +00:00
primTable [ 'keyPressed:' ] = this . primKeyPressed ;
primTable [ 'mousePressed' ] = function ( b ) { return runtime . mouseDown ; } ;
primTable [ 'mouseX' ] = function ( b ) { return runtime . mousePos [ 0 ] ; } ;
primTable [ 'mouseY' ] = function ( b ) { return runtime . mousePos [ 1 ] ; } ;
primTable [ 'distanceTo:' ] = this . primDistanceTo ;
primTable [ 'getAttribute:of:' ] = this . primGetAttribute ;
2013-10-30 12:34:18 +02:00
2014-04-09 01:17:50 -07:00
primTable [ 'timeAndDate' ] = function ( b ) { return runtime . getTimeString ( interp . arg ( b , 0 ) ) ; } ;
2013-10-30 14:28:55 +02:00
primTable [ 'timestamp' ] = this . primTimestamp ;
2013-11-01 22:44:51 -04:00
} ;
2013-10-28 20:00:20 +00:00
SensingPrims . prototype . primTouching = function ( b ) {
var s = interp . targetSprite ( ) ;
if ( s == null || ! s . visible ) return false ;
2013-11-01 22:44:51 -04:00
2013-10-28 20:00:20 +00:00
var arg = interp . arg ( b , 0 ) ;
if ( arg == '_edge_' ) {
return false ; // TODO
}
2013-11-01 22:44:51 -04:00
2013-10-28 20:00:20 +00:00
if ( arg == '_mouse_' ) {
return false ; // TODO
}
2013-11-01 22:44:51 -04:00
2013-10-28 20:00:20 +00:00
var s2 = runtime . spriteNamed ( arg ) ;
if ( s2 == null || ! s2 . visible ) return false ;
2013-11-01 22:44:51 -04:00
2013-10-28 20:00:20 +00:00
return spriteHitTest ( s , s2 ) ;
2013-11-01 22:44:51 -04:00
} ;
2013-10-28 20:00:20 +00:00
SensingPrims . prototype . primTouchingColor = function ( b ) {
var s = interp . targetSprite ( ) ;
if ( s == null || ! s . visible ) return false ;
var color = interp . arg ( b , 0 ) ;
return stageColorHitTest ( s , color ) ;
2013-11-01 22:44:51 -04:00
} ;
2013-10-28 20:00:20 +00:00
SensingPrims . prototype . primColorTouchingColor = function ( b ) {
var s = interp . targetSprite ( ) ;
if ( s == null || ! s . visible ) return false ;
var myColor = interp . arg ( b , 0 ) ;
var stageColor = interp . arg ( b , 1 ) ;
return stageColorByColorHitTest ( s , myColor , stageColor ) ;
2013-11-01 22:44:51 -04:00
} ;
2013-10-28 20:00:20 +00:00
var spriteHitTest = function ( a , b ) {
var hitCanvas = document . createElement ( 'canvas' ) ;
hitCanvas . width = 480 ;
hitCanvas . height = 360 ;
var hitTester = hitCanvas . getContext ( '2d' ) ;
hitTester . globalCompositeOperation = 'source-over' ;
a . stamp ( hitTester , 100 ) ;
hitTester . globalCompositeOperation = 'source-in' ;
b . stamp ( hitTester , 100 ) ;
var aData = hitTester . getImageData ( 0 , 0 , 480 , 360 ) . data ;
var pxCount = aData . length ;
for ( var i = 0 ; i < pxCount ; i += 4 ) {
if ( aData [ i + 3 ] > 0 ) {
return true ;
}
}
return false ;
2013-11-01 22:44:51 -04:00
} ;
2013-10-28 20:00:20 +00:00
var stageColorHitTest = function ( target , color ) {
var r , g , b ;
r = ( color >> 16 ) ;
g = ( color >> 8 & 255 ) ;
b = ( color & 255 ) ;
var targetCanvas = document . createElement ( 'canvas' ) ;
targetCanvas . width = 480 ;
targetCanvas . height = 360 ;
var targetTester = targetCanvas . getContext ( '2d' ) ;
target . stamp ( targetTester , 100 ) ;
var stageCanvas = document . createElement ( 'canvas' ) ;
stageCanvas . width = 480 ;
stageCanvas . height = 360 ;
var stageContext = stageCanvas . getContext ( '2d' ) ;
$ . each ( runtime . sprites , function ( i , sprite ) {
if ( sprite != target )
sprite . stamp ( stageContext , 100 ) ;
} ) ;
var hitData = stageContext . getImageData ( 0 , 0 , stageCanvas . width , stageCanvas . height ) . data ;
var meshData = targetTester . getImageData ( 0 , 0 , targetCanvas . width , targetCanvas . height ) . data ;
var pxCount = meshData . length ;
for ( var i = 0 ; i < pxCount ; i += 4 ) {
if ( meshData [ i + 3 ] > 0 && hitData [ i ] == r && hitData [ i + 1 ] == g && hitData [ i + 2 ] == b )
return true ;
}
return false ;
2013-11-01 22:44:51 -04:00
} ;
2013-10-28 20:00:20 +00:00
var stageColorByColorHitTest = function ( target , myColor , otherColor ) {
var threshold _acceptable = function ( a , b , c , x , y , z ) {
2013-10-30 11:40:53 -06:00
var diff _a = Math . abs ( a - x ) ;
var diff _b = Math . abs ( b - y ) ;
var diff _c = Math . abs ( c - z ) ;
2013-10-28 20:00:20 +00:00
if ( diff _a + diff _b + diff _c < 100 ) {
return true ;
}
return false ;
2013-11-01 22:44:51 -04:00
} ;
2013-10-28 20:00:20 +00:00
var targetCanvas = document . createElement ( 'canvas' ) ;
targetCanvas . width = 480 ;
targetCanvas . height = 360 ;
var targetTester = targetCanvas . getContext ( '2d' ) ;
target . stamp ( targetTester , 100 ) ;
var targetData = targetTester . getImageData ( 0 , 0 , targetCanvas . width , targetCanvas . height ) . data ;
// Calculate RGB values of the colors - TODO thresholding
//myColor = Math.abs(myColor);
//otherColor = Math.abs(otherColor);
var mr , mg , mb , or , og , ob ;
mr = ( myColor >> 16 ) ;
mg = ( myColor >> 8 & 255 ) ;
mb = ( myColor & 255 ) ;
or = ( otherColor >> 16 ) ;
og = ( otherColor >> 8 & 255 ) ;
ob = ( otherColor & 255 ) ;
// Create the hit canvas for comparison
var hitCanvas = document . createElement ( 'canvas' ) ;
hitCanvas . width = 480 ;
hitCanvas . height = 360 ;
2013-10-30 11:40:53 -06:00
var hitCtx = hitCanvas . getContext ( '2d' ) ;
2013-10-28 20:00:20 +00:00
$ . each ( runtime . sprites , function ( i , sprite ) {
2013-11-01 22:44:51 -04:00
if ( sprite != target ) {
2013-10-28 20:00:20 +00:00
sprite . stamp ( hitCtx , 100 ) ;
2013-11-01 22:44:51 -04:00
}
2013-10-28 20:00:20 +00:00
} ) ;
var hitData = hitCtx . getImageData ( 0 , 0 , hitCanvas . width , hitCanvas . height ) . data ;
var pxCount = targetData . length ;
for ( var i = 0 ; i < pxCount ; i += 4 ) {
2013-11-01 22:44:51 -04:00
if ( threshold _acceptable ( targetData [ i ] , targetData [ i + 1 ] , targetData [ i + 2 ] , mr , mg , mb ) && threshold _acceptable ( hitData [ i ] , hitData [ i + 1 ] , hitData [ i + 2 ] , or , og , ob ) ) {
2013-10-28 20:00:20 +00:00
return true ;
2013-11-01 22:44:51 -04:00
}
2013-10-28 20:00:20 +00:00
}
return false ;
2013-11-01 22:44:51 -04:00
} ;
2014-03-09 11:59:38 -06:00
SensingPrims . prototype . primDoAsk = function ( b ) {
showBubble ( b , "doAsk" ) ;
var s = interp . targetSprite ( ) ;
if ( s !== null ) {
2014-04-09 01:17:50 -07:00
interp . activeThread . paused = true ;
s . showAsk ( ) ;
2014-03-09 11:59:38 -06:00
}
} ;
SensingPrims . prototype . primAnswer = function ( b ) {
var s = interp . targetStage ( ) ;
return ( s !== null ? s . askAnswer : undefined ) ;
} ;
2013-10-28 20:00:20 +00:00
SensingPrims . prototype . primKeyPressed = function ( b ) {
var key = interp . arg ( b , 0 ) ;
var ch = key . charCodeAt ( 0 ) ;
if ( ch > 127 ) return false ;
if ( key == "left arrow" ) ch = 37 ;
if ( key == "right arrow" ) ch = 39 ;
if ( key == "up arrow" ) ch = 38 ;
if ( key == "down arrow" ) ch = 40 ;
if ( key == "space" ) ch = 32 ;
return ( typeof ( runtime . keysDown [ ch ] ) != 'undefined' ) ;
2013-11-01 22:44:51 -04:00
} ;
2013-10-28 20:00:20 +00:00
SensingPrims . prototype . primDistanceTo = function ( b ) {
var s = interp . targetSprite ( ) ;
var p = mouseOrSpritePosition ( interp . arg ( b , 0 ) ) ;
if ( s == null || p == null ) return 0 ;
var dx = p . x - s . scratchX ;
var dy = p . y - s . scratchY ;
return Math . sqrt ( ( dx * dx ) + ( dy * dy ) ) ;
2013-11-01 22:44:51 -04:00
} ;
2013-10-28 20:00:20 +00:00
SensingPrims . prototype . primGetAttribute = function ( b ) {
var attr = interp . arg ( b , 0 ) ;
var targetSprite = runtime . spriteNamed ( interp . arg ( b , 1 ) ) ;
if ( targetSprite == null ) return 0 ;
if ( attr == 'x position' ) return targetSprite . scratchX ;
if ( attr == 'y position' ) return targetSprite . scratchY ;
if ( attr == 'direction' ) return targetSprite . direction ;
if ( attr == 'costume #' ) return targetSprite . currentCostumeIndex + 1 ;
if ( attr == 'costume name' ) return targetSprite . costumes [ targetSprite . currentCostumeIndex ] [ 'costumeName' ] ;
if ( attr == 'size' ) return targetSprite . getSize ( ) ;
if ( attr == 'volume' ) return targetSprite . volume ;
return 0 ;
2013-11-01 22:44:51 -04:00
} ;
2013-10-28 20:00:20 +00:00
2013-10-30 12:34:18 +02:00
SensingPrims . prototype . primTimeDate = function ( b ) {
var dt = interp . arg ( b , 0 ) ;
var now = new Date ( ) ;
if ( dt == 'year' ) return now . getFullYear ( ) ;
if ( dt == 'month' ) return now . getMonth ( ) + 1 ;
if ( dt == 'date' ) return now . getDate ( ) ;
if ( dt == 'day of week' ) return now . getDay ( ) + 1 ;
if ( dt == 'hour' ) return now . getHours ( ) ;
if ( dt == 'minute' ) return now . getMinutes ( ) ;
if ( dt == 'second' ) return now . getSeconds ( ) ;
return 0 ;
2013-11-01 22:44:51 -04:00
} ;
2013-10-30 12:34:18 +02:00
2013-10-30 18:25:32 +02:00
SensingPrims . prototype . primTimestamp = function ( b ) {
2013-11-01 22:44:51 -04:00
var now = new Date ( ) ;
var epoch = new Date ( 2000 , 0 , 1 ) ;
var dst = now . getTimezoneOffset ( ) - epoch . getTimezoneOffset ( ) ;
var msSince = now . getTime ( ) - epoch . getTime ( ) ;
2014-03-21 19:54:59 +01:00
msSince -= dst * 60000 ;
2013-11-01 22:44:51 -04:00
return msSince / 86400000 ;
} ;
2013-10-30 14:28:55 +02:00
2013-10-28 20:00:20 +00:00
// Helpers
SensingPrims . prototype . mouseOrSpritePosition = function ( arg ) {
if ( arg == "_mouse_" ) {
var w = runtime . stage ;
return new Point ( runtime . mousePos [ 0 ] , runtime . mousePos [ 1 ] ) ;
} else {
var s = runtime . spriteNamed ( arg ) ;
if ( s == null ) return null ;
return new Point ( s . scratchX , s . scratchY ) ;
}
return null ;
2013-11-01 22:44:51 -04:00
} ;