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 MotionAndPenPrims = function ( ) { } ;
2013-10-28 20:00:20 +00:00
MotionAndPenPrims . prototype . addPrimsTo = function ( primTable ) {
primTable [ 'forward:' ] = this . primMove ;
primTable [ 'turnLeft:' ] = this . primTurnLeft ;
primTable [ 'turnRight:' ] = this . primTurnRight ;
primTable [ 'heading:' ] = this . primSetDirection ;
2013-11-14 22:21:49 -05:00
primTable [ 'pointTowards:' ] = this . primPointTowards ;
primTable [ 'gotoX:y:' ] = this . primGoTo ;
primTable [ 'gotoSpriteOrMouse:' ] = this . primGoToSpriteOrMouse ;
primTable [ 'glideSecs:toX:y:elapsed:from:' ] = this . primGlide ;
primTable [ 'changeXposBy:' ] = this . primChangeX ;
primTable [ 'xpos:' ] = this . primSetX ;
primTable [ 'changeYposBy:' ] = this . primChangeY ;
primTable [ 'ypos:' ] = this . primSetY ;
primTable [ 'bounceOffEdge' ] = this . primBounceOffEdge ;
primTable [ 'setRotationStyle' ] = this . primSetRotationStyle ;
primTable [ 'xpos' ] = this . primXPosition ;
primTable [ 'ypos' ] = this . primYPosition ;
primTable [ 'heading' ] = this . primDirection ;
primTable [ 'clearPenTrails' ] = this . primClear ;
primTable [ 'putPenDown' ] = this . primPenDown ;
primTable [ 'putPenUp' ] = this . primPenUp ;
primTable [ 'penColor:' ] = this . primSetPenColor ;
primTable [ 'setPenHueTo:' ] = this . primSetPenHue ;
primTable [ 'changePenHueBy:' ] = this . primChangePenHue ;
primTable [ 'setPenShadeTo:' ] = this . primSetPenShade ;
primTable [ 'changePenShadeBy:' ] = this . primChangePenShade ;
primTable [ 'penSize:' ] = this . primSetPenSize ;
primTable [ 'changePenSizeBy:' ] = this . primChangePenSize ;
primTable [ 'stampCostume' ] = this . primStamp ;
primTable [ 'stampTransparent' ] = this . primStampTransparent ;
2013-11-01 22:44:51 -04:00
} ;
2013-10-28 20:00:20 +00:00
MotionAndPenPrims . prototype . primMove = function ( b ) {
var s = interp . targetSprite ( ) ;
2013-11-01 22:44:51 -04:00
var radians = ( 90 - s . direction ) * Math . PI / 180 ;
2013-11-02 00:38:29 -05:00
var d = interp . numarg ( b , 0 ) ;
2013-10-28 20:00:20 +00:00
2013-11-01 22:44:51 -04:00
moveSpriteTo ( s , s . scratchX + d * Math . cos ( radians ) , s . scratchY + d * Math . sin ( radians ) ) ;
if ( s . visible ) interp . redraw ( ) ;
} ;
2013-10-28 20:00:20 +00:00
MotionAndPenPrims . prototype . primTurnLeft = function ( b ) {
var s = interp . targetSprite ( ) ;
2013-11-02 00:38:29 -05:00
var d = s . direction - interp . numarg ( b , 0 ) ;
2013-10-28 20:00:20 +00:00
s . setDirection ( d ) ;
2013-11-01 22:44:51 -04:00
if ( s . visible ) interp . redraw ( ) ;
} ;
2013-10-28 20:00:20 +00:00
MotionAndPenPrims . prototype . primTurnRight = function ( b ) {
var s = interp . targetSprite ( ) ;
2013-11-02 00:38:29 -05:00
var d = s . direction + interp . numarg ( b , 0 ) ;
2013-10-28 20:00:20 +00:00
s . setDirection ( d ) ;
2013-11-01 22:44:51 -04:00
if ( s . visible ) interp . redraw ( ) ;
} ;
2013-10-28 20:00:20 +00:00
MotionAndPenPrims . prototype . primSetDirection = function ( b ) {
var s = interp . targetSprite ( ) ;
2013-11-02 00:38:29 -05:00
s . setDirection ( interp . numarg ( b , 0 ) ) ;
2013-11-01 22:44:51 -04:00
if ( s . visible ) interp . redraw ( ) ;
} ;
2013-10-28 20:00:20 +00:00
MotionAndPenPrims . prototype . primPointTowards = function ( b ) {
var s = interp . targetSprite ( ) ;
var p = mouseOrSpritePosition ( interp . arg ( b , 0 ) ) ;
2013-11-01 22:44:51 -04:00
if ( s == null || p == null ) return ;
2013-10-28 20:00:20 +00:00
var dx = p . x - s . scratchX ;
var dy = p . y - s . scratchY ;
2013-11-01 22:44:51 -04:00
var angle = 90 - Math . atan2 ( dy , dx ) * 180 / Math . PI ;
2013-10-28 20:00:20 +00:00
s . setDirection ( angle ) ;
if ( s . visible ) interp . redraw ( ) ;
2013-11-01 22:44:51 -04:00
} ;
2013-10-28 20:00:20 +00:00
MotionAndPenPrims . prototype . primGoTo = function ( b ) {
var s = interp . targetSprite ( ) ;
2013-11-02 00:38:29 -05:00
if ( s != null ) moveSpriteTo ( s , interp . numarg ( b , 0 ) , interp . numarg ( b , 1 ) ) ;
2013-11-01 22:44:51 -04:00
} ;
2013-10-28 20:00:20 +00:00
MotionAndPenPrims . prototype . primGoToSpriteOrMouse = function ( b ) {
var s = interp . targetSprite ( ) ;
var p = mouseOrSpritePosition ( interp . arg ( b , 0 ) ) ;
2013-11-01 22:44:51 -04:00
if ( s == null || p == null ) return ;
2013-10-28 20:00:20 +00:00
moveSpriteTo ( s , p . x , p . y ) ;
2013-11-01 22:44:51 -04:00
} ;
2013-10-28 20:00:20 +00:00
MotionAndPenPrims . prototype . primGlide = function ( b ) {
var s = interp . targetSprite ( ) ;
if ( s == null ) return ;
if ( interp . activeThread . firstTime ) {
2013-11-02 00:38:29 -05:00
var secs = interp . numarg ( b , 0 ) ;
var destX = interp . numarg ( b , 1 ) ;
var destY = interp . numarg ( b , 2 ) ;
2013-10-28 20:00:20 +00:00
if ( secs <= 0 ) {
moveSpriteTo ( s , destX , destY ) ;
return ;
}
// record state: [0]start msecs, [1]duration, [2]startX, [3]startY, [4]endX, [5]endY
2013-11-01 22:44:51 -04:00
interp . activeThread . tmpObj = [ interp . currentMSecs , 1000 * secs , s . scratchX , s . scratchY , destX , destY ] ;
2013-10-28 20:00:20 +00:00
interp . startTimer ( secs ) ;
} else {
var state = interp . activeThread . tmpObj ;
if ( ! interp . checkTimer ( ) ) {
// in progress: move to intermediate position along path
var frac = ( interp . currentMSecs - state [ 0 ] ) / state [ 1 ] ;
2013-11-01 22:44:51 -04:00
var newX = state [ 2 ] + frac * ( state [ 4 ] - state [ 2 ] ) ;
var newY = state [ 3 ] + frac * ( state [ 5 ] - state [ 3 ] ) ;
2013-10-28 20:00:20 +00:00
moveSpriteTo ( s , newX , newY ) ;
} else {
// finished: move to final position and clear state
moveSpriteTo ( s , state [ 4 ] , state [ 5 ] ) ;
interp . activeThread . tmpObj = null ;
}
2013-11-01 22:44:51 -04:00
}
} ;
2013-10-28 20:00:20 +00:00
MotionAndPenPrims . prototype . primChangeX = function ( b ) {
var s = interp . targetSprite ( ) ;
2013-11-02 00:38:29 -05:00
if ( s != null ) moveSpriteTo ( s , s . scratchX + interp . numarg ( b , 0 ) , s . scratchY ) ;
2013-11-01 22:44:51 -04:00
} ;
2013-10-28 20:00:20 +00:00
MotionAndPenPrims . prototype . primSetX = function ( b ) {
var s = interp . targetSprite ( ) ;
2013-11-02 00:38:29 -05:00
if ( s != null ) moveSpriteTo ( s , interp . numarg ( b , 0 ) , s . scratchY ) ;
2013-11-01 22:44:51 -04:00
} ;
2013-10-28 20:00:20 +00:00
MotionAndPenPrims . prototype . primChangeY = function ( b ) {
var s = interp . targetSprite ( ) ;
2013-11-02 00:38:29 -05:00
if ( s != null ) moveSpriteTo ( s , s . scratchX , s . scratchY + interp . numarg ( b , 0 ) ) ;
2013-11-01 22:44:51 -04:00
} ;
2013-10-28 20:00:20 +00:00
MotionAndPenPrims . prototype . primSetY = function ( b ) {
var s = interp . targetSprite ( ) ;
2013-11-02 00:38:29 -05:00
if ( s != null ) moveSpriteTo ( s , s . scratchX , interp . numarg ( b , 0 ) ) ;
2013-11-01 22:44:51 -04:00
} ;
2013-10-28 20:00:20 +00:00
MotionAndPenPrims . prototype . primBounceOffEdge = function ( b ) {
var s = interp . targetSprite ( ) ;
if ( s == null ) return ;
if ( ! turnAwayFromEdge ( s ) ) return ;
ensureOnStageOnBounce ( s ) ;
if ( s . visible ) interp . redraw ( ) ;
2013-11-01 22:44:51 -04:00
} ;
2013-10-28 20:00:20 +00:00
MotionAndPenPrims . prototype . primSetRotationStyle = function ( b ) {
var s = interp . targetSprite ( ) ;
if ( s == null ) return ;
var request = interp . arg ( b , 0 ) ;
var rotationStyle = 'normal' ;
if ( request == 'all around' ) rotationStyle = 'normal' ;
else if ( request == 'left-right' ) rotationStyle = 'leftRight' ;
else if ( request == 'none' ) rotationStyle = 'none' ;
s . setRotationStyle ( rotationStyle ) ;
2013-11-01 22:44:51 -04:00
} ;
2013-10-28 20:00:20 +00:00
MotionAndPenPrims . prototype . primXPosition = function ( b ) {
var s = interp . targetSprite ( ) ;
2013-11-01 22:44:51 -04:00
return s != null ? s . scratchX : 0 ;
} ;
2013-10-28 20:00:20 +00:00
MotionAndPenPrims . prototype . primYPosition = function ( b ) {
var s = interp . targetSprite ( ) ;
2013-11-01 22:44:51 -04:00
return s != null ? s . scratchY : 0 ;
} ;
2013-10-28 20:00:20 +00:00
MotionAndPenPrims . prototype . primDirection = function ( b ) {
var s = interp . targetSprite ( ) ;
2013-11-01 22:44:51 -04:00
return s != null ? s . direction : 0 ;
} ;
2013-10-28 20:00:20 +00:00
MotionAndPenPrims . prototype . primClear = function ( b ) {
runtime . stage . clearPenStrokes ( ) ;
interp . redraw ( ) ;
2013-11-01 22:44:51 -04:00
} ;
2013-10-28 20:00:20 +00:00
MotionAndPenPrims . prototype . primPenDown = function ( b ) {
var s = interp . targetSprite ( ) ;
if ( s != null ) s . penIsDown = true ;
stroke ( s , s . scratchX , s . scratchY , s . scratchX + 0.2 , s . scratchY + 0.2 ) ;
interp . redraw ( ) ;
2013-11-01 22:44:51 -04:00
} ;
2013-10-28 20:00:20 +00:00
MotionAndPenPrims . prototype . primPenUp = function ( b ) {
var s = interp . targetSprite ( ) ;
if ( s != null ) s . penIsDown = false ;
2013-11-01 22:44:51 -04:00
} ;
2013-10-28 20:00:20 +00:00
MotionAndPenPrims . prototype . primSetPenColor = function ( b ) {
var s = interp . targetSprite ( ) ;
2013-11-02 00:38:29 -05:00
if ( s != null ) s . setPenColor ( interp . numarg ( b , 0 ) ) ;
2013-11-01 22:44:51 -04:00
} ;
2013-10-28 20:00:20 +00:00
MotionAndPenPrims . prototype . primSetPenHue = function ( b ) {
var s = interp . targetSprite ( ) ;
2013-11-02 00:38:29 -05:00
if ( s != null ) s . setPenHue ( interp . numarg ( b , 0 ) ) ;
2013-11-01 22:44:51 -04:00
} ;
2013-10-28 20:00:20 +00:00
MotionAndPenPrims . prototype . primChangePenHue = function ( b ) {
var s = interp . targetSprite ( ) ;
2013-11-02 00:38:29 -05:00
if ( s != null ) s . setPenHue ( s . penHue + interp . numarg ( b , 0 ) ) ;
2013-11-01 22:44:51 -04:00
} ;
2013-10-28 20:00:20 +00:00
MotionAndPenPrims . prototype . primSetPenShade = function ( b ) {
var s = interp . targetSprite ( ) ;
2013-11-02 00:38:29 -05:00
if ( s != null ) s . setPenShade ( interp . numarg ( b , 0 ) ) ;
2013-11-01 22:44:51 -04:00
} ;
2013-10-28 20:00:20 +00:00
MotionAndPenPrims . prototype . primChangePenShade = function ( b ) {
var s = interp . targetSprite ( ) ;
2013-11-02 00:38:29 -05:00
if ( s != null ) s . setPenShade ( s . penShade + interp . numarg ( b , 0 ) ) ;
2013-11-01 22:44:51 -04:00
} ;
2013-10-28 20:00:20 +00:00
MotionAndPenPrims . prototype . primSetPenSize = function ( b ) {
var s = interp . targetSprite ( ) ;
2013-11-02 00:38:29 -05:00
var w = Math . max ( 0 , Math . min ( interp . numarg ( b , 0 ) , 100 ) ) ;
2013-10-28 20:00:20 +00:00
if ( s != null ) s . penWidth = w ;
2013-11-01 22:44:51 -04:00
} ;
2013-10-28 20:00:20 +00:00
MotionAndPenPrims . prototype . primChangePenSize = function ( b ) {
var s = interp . targetSprite ( ) ;
2013-11-02 00:38:29 -05:00
var w = Math . max ( 0 , Math . min ( s . penWidth + interp . numarg ( b , 0 ) , 100 ) ) ;
2013-10-28 20:00:20 +00:00
if ( s != null ) s . penWidth = w ;
2013-11-01 22:44:51 -04:00
} ;
2013-10-28 20:00:20 +00:00
MotionAndPenPrims . prototype . primStamp = function ( b ) {
var s = interp . targetSprite ( ) ;
s . stamp ( runtime . stage . lineCache , 100 ) ;
2013-11-01 22:44:51 -04:00
} ;
2013-10-28 20:00:20 +00:00
MotionAndPenPrims . prototype . primStampTransparent = function ( b ) {
var s = interp . targetSprite ( ) ;
2013-11-02 00:38:29 -05:00
var transparency = Math . max ( 0 , Math . min ( interp . numarg ( b , 0 ) , 100 ) ) ;
2013-10-28 20:00:20 +00:00
var alpha = 100 - transparency ;
s . stamp ( runtime . stage . lineCache , alpha ) ;
2013-11-01 22:44:51 -04:00
} ;
2013-10-28 20:00:20 +00:00
// Helpers
var stroke = function ( s , oldX , oldY , newX , newY ) {
2013-11-01 22:44:51 -04:00
runtime . stage . stroke ( [ oldX , oldY ] , [ newX , newY ] , s . penWidth , s . penColorCache ) ;
2013-10-28 20:00:20 +00:00
interp . redraw ( ) ;
2013-11-01 22:44:51 -04:00
} ;
2013-10-28 20:00:20 +00:00
var mouseOrSpritePosition = function ( arg ) {
2013-11-14 22:21:49 -05:00
if ( arg == '_mouse_' ) {
2013-10-28 20:00:20 +00:00
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
} ;
2013-10-28 20:00:20 +00:00
var moveSpriteTo = function ( s , newX , newY ) {
var oldX = s . scratchX ;
var oldY = s . scratchY ;
s . setXY ( newX , newY ) ;
s . keepOnStage ( ) ;
if ( s . penIsDown ) stroke ( s , oldX , oldY , s . scratchX , s . scratchY ) ;
2013-11-01 22:44:51 -04:00
if ( s . penIsDown || s . visible ) interp . redraw ( ) ;
} ;
2013-10-28 20:00:20 +00:00
var turnAwayFromEdge = function ( s ) {
// turn away from the nearest edge if it's close enough; otherwise do nothing
// Note: comparisions are in the stage coordinates, with origin (0, 0)
// use bounding rect of the sprite to account for costume rotation and scale
var r = s . getRect ( ) ;
// measure distance to edges
var d1 = Math . max ( 0 , r . left ) ;
var d2 = Math . max ( 0 , r . top ) ;
var d3 = Math . max ( 0 , 480 - r . right ) ;
var d4 = Math . max ( 0 , 360 - r . bottom ) ;
// find the nearest edge
var e = 0 , minDist = 100000 ;
2013-11-01 22:44:51 -04:00
if ( d1 < minDist ) { minDist = d1 ; e = 1 ; }
if ( d2 < minDist ) { minDist = d2 ; e = 2 ; }
if ( d3 < minDist ) { minDist = d3 ; e = 3 ; }
if ( d4 < minDist ) { minDist = d4 ; e = 4 ; }
2013-10-28 20:00:20 +00:00
if ( minDist > 0 ) return false ; // not touching to any edge
// point away from nearest edge
2013-11-01 22:44:51 -04:00
var radians = ( 90 - s . direction ) * Math . PI / 180 ;
2013-10-28 20:00:20 +00:00
var dx = Math . cos ( radians ) ;
var dy = - Math . sin ( radians ) ;
2013-11-01 22:44:51 -04:00
if ( e == 1 ) { dx = Math . max ( 0.2 , Math . abs ( dx ) ) ; }
if ( e == 2 ) { dy = Math . max ( 0.2 , Math . abs ( dy ) ) ; }
if ( e == 3 ) { dx = 0 - Math . max ( 0.2 , Math . abs ( dx ) ) ; }
if ( e == 4 ) { dy = 0 - Math . max ( 0.2 , Math . abs ( dy ) ) ; }
var newDir = Math . atan2 ( dy , dx ) * 180 / Math . PI + 90 ;
2013-10-28 20:00:20 +00:00
s . direction = newDir ;
return true ;
2013-11-01 22:44:51 -04:00
} ;
2013-10-28 20:00:20 +00:00
var ensureOnStageOnBounce = function ( s ) {
var r = s . getRect ( ) ;
if ( r . left < 0 ) moveSpriteTo ( s , s . scratchX - r . left , s . scratchY ) ;
if ( r . top < 0 ) moveSpriteTo ( s , s . scratchX , s . scratchY + r . top ) ;
if ( r . right > 480 ) {
moveSpriteTo ( s , s . scratchX - ( r . right - 480 ) , s . scratchY ) ;
}
if ( r . bottom > 360 ) {
moveSpriteTo ( s , s . scratchX , s . scratchY + ( r . bottom - 360 ) ) ;
}
2013-11-01 22:44:51 -04:00
} ;