2015-01-01 13:47:36 +01:00
/*global __plugin, require, org, setTimeout, addUnloadHandler, exports, global, Packages, server*/
2014-01-29 20:49:15 +01:00
var utils = require ( 'utils' ) ,
blocks = require ( 'blocks' ) ,
2014-12-28 16:07:08 +01:00
THOUSAND = 1000 ,
2014-12-29 23:42:00 +01:00
MILLION = THOUSAND * THOUSAND ;
2014-12-27 20:03:30 +01:00
2013-12-24 01:09:49 +01:00
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2014-01-04 19:39:49 +01:00
# # Drone Plugin
2013-12-24 01:09:49 +01:00
The Drone is a convenience class for building . It can be used for ...
1. Building
2. Copying and Pasting
2014-06-14 16:40:19 +02:00
It uses a fluent interface which means all of the Drone ' s methods return ` this ` and can be chained together like so ...
2013-12-24 01:09:49 +01:00
2014-12-30 15:54:38 +01:00
var theDrone = new Drone ( self ) ;
2013-12-24 01:09:49 +01:00
theDrone . up ( ) . left ( ) . box ( blocks . oak ) . down ( ) . fwd ( 3 ) . cylinder0 ( blocks . lava , 8 ) ;
2014-01-04 19:39:49 +01:00
# # # Constructing a Drone Object
2013-12-24 01:09:49 +01:00
Drones can be created in any of the following ways ...
1. Calling any one of the methods listed below will return a Drone object . For example ...
var d = box ( blocks . oak )
2014-06-14 16:40:19 +02:00
... creates a 1 x1x1 wooden block at the cross - hairs or player 's location and returns a Drone object. This might look odd (if you' re familiar with Java 's Object-dot-method syntax) but all of the Drone class' s methods are also global functions that return new Drone objects . This is short - hand for creating drones and is useful for playing around with Drones at the in - game command prompt . It ' s shorter than typing ...
2013-12-24 01:09:49 +01:00
2014-12-30 15:54:38 +01:00
var d = new Drone ( self ) . box ( blocks . oak )
2013-12-24 01:09:49 +01:00
2013-12-30 22:33:12 +01:00
... All of the Drone ' s methods return ` this ` so you can chain operations together like this ...
2013-12-24 01:09:49 +01:00
var d = box ( blocks . oak )
. up ( )
. box ( blocks . oak , 3 , 1 , 3 )
. down ( )
. fwd ( 2 )
. box ( blocks . oak )
. turn ( )
. fwd ( 2 )
. box ( blocks . oak )
. turn ( )
. fwd ( 2 )
. box ( blocks . oak ) ;
2. Using the following form ...
2014-12-30 15:54:38 +01:00
d = new Drone ( self )
2013-12-24 01:09:49 +01:00
2014-12-31 10:40:30 +01:00
... will create a new Drone taking the current player as the parameter . If the player 's cross-hairs are pointing at a block at the time then, that block' s location becomes the drone 's starting point. If the cross-hairs are _not_ pointing at a block, then the drone' s starting location will be 2 blocks directly in front of the player . TIP : Building always happens right and front of the drone ' s position ...
2013-12-24 01:09:49 +01:00
Plan View :
^
|
|
D -- -- >
2014-12-30 15:54:38 +01:00
For convenience you can use a _corner stone _ to begin building . The corner stone should be located just above ground level . If the cross - hair is point at or into ground level when you create a new Drone ( ) with either a player or location given as a parameter , then building begins at the location the player was looking at or at the location . You can get around this by pointing at a 'corner stone' just above ground level or alternatively use the following statement ...
2013-12-24 01:09:49 +01:00
2014-12-30 15:54:38 +01:00
d = new Drone ( self ) . up ( ) ;
2013-12-24 01:09:49 +01:00
... which will move the drone up one block as soon as it ' s created .
! [ corner stone ] ( img / cornerstone1 . png )
3. Or by using the following form ...
d = new Drone ( x , y , z , direction , world ) ;
2014-06-14 16:40:19 +02:00
This will create a new Drone at the location you specified using x , y , z In minecraft , the X axis runs west to east and the Z axis runs north to south . The direction parameter says what direction you want the drone to face : 0 = east , 1 = south , 2 = west , 3 = north . If the direction parameter is omitted , the player ' s direction is used instead . Both the ` direction ` and ` world ` parameters are optional .
2013-12-24 01:09:49 +01:00
2014-12-31 10:40:30 +01:00
4. Create a new Drone based on a Location object ...
2013-12-24 01:09:49 +01:00
d = new Drone ( location ) ;
2014-06-14 16:40:19 +02:00
This is useful when you want to create a drone at a given ` org.bukkit.Location ` . The ` Location ` class is used throughout the bukkit API . For example , if you want to create a drone when a block is broken at the block ' s location you would do so like this ...
2013-12-24 01:09:49 +01:00
2014-06-14 16:40:19 +02:00
events . blockBreak ( function ( event ) {
2013-12-24 01:09:49 +01:00
var location = event . block . location ;
var drone = new Drone ( location ) ;
// do more stuff with the drone here...
} ) ;
2014-01-04 19:39:49 +01:00
# # # # Parameters
2014-12-31 10:40:30 +01:00
* Player : If a player reference is given as the sole parameter then the block the player was looking at will be used as the starting point for the drone . If the player was not looking at a block then the player ' s location will be used as the starting point . If a ` Player ` object is provided as a paramter then it should be the only parameter .
* location : * NB * If a ` Location ` object is provided as a parameter , then it should be the only parameter .
* x : The x coordinate of the Drone ( x , y , z , direction and world are not needed if either a player or location parameter is provided )
* y : The y coordinate of the Drone
* z : The z coordinate of the Drone
* direction : The direction in which the Drone is facing . Possible values are 0 ( east ) , 1 ( south ) , 2 ( west ) or 3 ( north )
* world : The world in which the drone is created .
2013-12-24 01:09:49 +01:00
2014-01-04 19:39:49 +01:00
# # # Drone . box ( ) method
2013-12-24 01:09:49 +01:00
the box ( ) method is a convenience method for building things . ( For the more performance - oriented method - see cuboid )
2014-01-04 19:39:49 +01:00
# # # # parameters
2014-06-14 16:40:19 +02:00
* b - the block id - e . g . 6 for an oak sapling or '6:2' for a birch sapling . Alternatively you can use any one of the ` blocks ` values e . g . ` blocks.sapling.birch `
2013-12-24 01:09:49 +01:00
* w ( optional - default 1 ) - the width of the structure
* h ( optional - default 1 ) - the height of the structure
2014-06-14 16:40:19 +02:00
* d ( optional - default 1 ) - the depth of the structure - NB this is not how deep underground the structure lies - this is how far away ( depth of field ) from the drone the structure will extend .
2013-12-24 01:09:49 +01:00
2014-01-04 19:39:49 +01:00
# # # # Example
2013-12-24 01:09:49 +01:00
To create a black structure 4 blocks wide , 9 blocks tall and 1 block long ...
box ( blocks . wool . black , 4 , 9 , 1 ) ;
... or the following code does the same but creates a variable that can be used for further methods ...
2014-12-30 15:54:38 +01:00
var drone = new Drone ( self ) ;
2013-12-24 01:09:49 +01:00
drone . box ( blocks . wool . black , 4 , 9 , 1 ) ;
! [ box example 1 ] ( img / boxex1 . png )
2014-01-04 19:39:49 +01:00
# # # Drone . box0 ( ) method
2013-12-24 01:09:49 +01:00
Another convenience method - this one creates 4 walls with no floor or ceiling .
2014-01-04 19:39:49 +01:00
# # # # Parameters
2014-06-14 16:40:19 +02:00
* block - the block id - e . g . 6 for an oak sapling or '6:2' for a birch sapling . Alternatively you can use any one of the ` blocks ` values e . g . ` blocks.sapling.birch `
2013-12-24 01:09:49 +01:00
* width ( optional - default 1 ) - the width of the structure
* height ( optional - default 1 ) - the height of the structure
* length ( optional - default 1 ) - the length of the structure - how far
away ( depth of field ) from the drone the structure will extend .
2014-01-04 19:39:49 +01:00
# # # # Example
2013-12-24 01:09:49 +01:00
To create a stone building with the insided hollowed out 7 wide by 3 tall by 6 long ...
box0 ( blocks . stone , 7 , 3 , 6 ) ;
! [ example box0 ] ( img / box0ex1 . png )
2014-01-04 19:39:49 +01:00
# # # Drone . boxa ( ) method
2014-06-14 16:40:19 +02:00
Construct a cuboid using an array of blocks . As the drone moves first along the width axis , then the height ( y axis ) then the length , each block is picked from the array and placed .
2013-12-24 01:09:49 +01:00
2014-01-04 19:39:49 +01:00
# # # # Parameters
2013-12-24 01:09:49 +01:00
* blocks - An array of blocks - each block in the array will be placed in turn .
* width
* height
* length
2014-01-04 19:39:49 +01:00
# # # # Example
2013-12-24 01:09:49 +01:00
Construct a rainbow - colored road 100 blocks long ...
var rainbowColors = [ blocks . wool . red , blocks . wool . orange , blocks . wool . yellow , blocks . wool . lime ,
blocks . wool . lightblue , blocks . wool . blue , blocks . wool . purple ] ;
boxa ( rainbowColors , 7 , 1 , 30 ) ;
! [ boxa example ] ( img / boxaex1 . png )
2014-01-04 19:39:49 +01:00
# # # Chaining
2013-12-24 01:09:49 +01:00
2014-06-14 16:40:19 +02:00
All of the Drone methods return a Drone object , which means methods can be 'chained' together so instead of writing this ...
2013-12-24 01:09:49 +01:00
2014-12-30 19:12:10 +01:00
drone = new Drone ( self ) ;
drone . fwd ( 3 ) ;
drone . left ( 2 ) ;
drone . box ( blocks . grass ) ; // create a grass block
2013-12-24 01:09:49 +01:00
drone . up ( ) ;
2014-12-30 19:12:10 +01:00
drone . box ( blocks . grass ) ; // create another grass block
2013-12-24 01:09:49 +01:00
drone . down ( ) ;
... you could simply write ...
2014-12-30 19:12:10 +01:00
var drone = new Drone ( self ) . fwd ( 3 ) . left ( 2 ) . box ( blocks . grass ) . up ( ) . box ( blocks . grass ) . down ( ) ;
2013-12-24 01:09:49 +01:00
2014-06-14 16:40:19 +02:00
... since each Drone method is also a global function that constructs a drone if none is supplied , you can shorten even further to just ...
2013-12-24 01:09:49 +01:00
2014-12-30 19:12:10 +01:00
fwd ( 3 ) . left ( 2 ) . box ( blocks . grass ) . up ( ) . box ( blocks . grass ) . down ( )
2013-12-24 01:09:49 +01:00
2014-06-14 16:40:19 +02:00
The Drone object uses a [ Fluent Interface ] [ fl ] to make ScriptCraft scripts more concise and easier to write and read . Minecraft ' s in - game command prompt is limited to about 80 characters so chaining drone commands together means more can be done before hitting the command prompt limit . For complex building you should save your commands in a new script file and load it using / js load ( )
2013-12-24 01:09:49 +01:00
[ fl ] : http : //en.wikipedia.org/wiki/Fluent_interface
2014-01-04 19:39:49 +01:00
# # # Drone Properties
2013-12-24 01:09:49 +01:00
* x - The Drone ' s position along the west - east axis ( x increases as you move east )
* y - The Drone ' s position along the vertical axis ( y increses as you move up )
* z - The Drone ' s position along the north - south axis ( z increases as you move south )
* dir - The Drone ' s direction 0 is east , 1 is south , 2 is west and 3 is north .
2014-01-04 19:39:49 +01:00
# # # Extending Drone
2014-06-14 16:40:19 +02:00
The Drone object can be easily extended - new buidling recipes / blueprints can be added and can become part of a Drone ' s chain using the * static * method ` Drone.extend ` .
2013-12-24 01:09:49 +01:00
2014-01-04 19:39:49 +01:00
# # # Drone . extend ( ) static method
2013-12-24 01:09:49 +01:00
Use this method to add new methods ( which also become chainable global functions ) to the Drone object .
2014-01-04 19:39:49 +01:00
# # # # Parameters
2014-05-24 11:55:27 +02:00
* name - The name of the new method e . g . 'pyramid' .
2013-12-24 01:09:49 +01:00
* function - The method body .
2014-05-24 11:55:27 +02:00
Alternatively if you provide just a function as a parameter , then the function name will be used as the new method name . For example the following two approaches are both valid .
# # # # Example 1 Using name and function as parameters
2013-12-24 01:09:49 +01:00
// submitted by [edonaldson][edonaldson]
2014-01-29 20:49:15 +01:00
Drone . extend ( 'pyramid' , function ( block , height ) {
2013-12-24 01:09:49 +01:00
this . chkpt ( 'pyramid' ) ;
2014-01-29 20:49:15 +01:00
for ( var i = height ; i > 0 ; i -= 2 ) {
2013-12-24 01:09:49 +01:00
this . box ( block , i , 1 , i ) . up ( ) . right ( ) . fwd ( ) ;
}
return this . move ( 'pyramid' ) ;
} ) ;
2014-05-24 11:55:27 +02:00
# # # # Example 2 Using just a named function as a parameter
2014-06-14 16:40:19 +02:00
function pyramid ( block , height ) {
2014-05-24 11:55:27 +02:00
this . chkpt ( 'pyramid' ) ;
for ( var i = height ; i > 0 ; i -= 2 ) {
this . box ( block , i , 1 , i ) . up ( ) . right ( ) . fwd ( ) ;
}
return this . move ( 'pyramid' ) ;
2014-06-14 16:40:19 +02:00
}
Drone . extend ( pyramid ) ;
2014-05-24 11:55:27 +02:00
2013-12-24 01:09:49 +01:00
Once the method is defined ( it can be defined in a new pyramid . js file ) it can be used like so ...
2014-12-30 19:12:10 +01:00
var d = new Drone ( self ) ;
2013-12-24 01:09:49 +01:00
d . pyramid ( blocks . brick . stone , 12 ) ;
... or simply ...
pyramid ( blocks . brick . stone , 12 ) ;
[ edonaldson ] : https : //github.com/edonaldson
2014-01-04 19:39:49 +01:00
# # # Drone Constants
# # # # Drone . PLAYER _STAIRS _FACING
2013-12-24 01:09:49 +01:00
An array which can be used when constructing stairs facing in the Drone ' s direction ...
2014-12-30 19:12:10 +01:00
var d = new Drone ( self ) ;
2013-12-24 01:09:49 +01:00
d . box ( blocks . stairs . oak + ':' + Drone . PLAYER _STAIRS _FACING [ d . dir ] ) ;
... will construct a single oak stair block facing the drone .
2014-01-04 19:39:49 +01:00
# # # # Drone . PLAYER _SIGN _FACING
2014-06-14 16:40:19 +02:00
An array which can be used when placing signs so they face in a given direction . This is used internally by the Drone . sign ( ) method . It should also be used for placing any of the following blocks ...
2013-12-24 01:09:49 +01:00
* chest
* ladder
* furnace
* dispenser
2014-12-30 19:12:10 +01:00
By default , chests , dispensers , signs , ladders and furnaces are placed facing towards the drone so to place a chest facing the Drone just use :
2013-12-24 01:09:49 +01:00
2014-12-30 19:12:10 +01:00
drone . box ( blocks . chest ) ;
To place a chest facing _away _ from the Drone :
drone . box ( blocks . chest + ':' + Drone . PLAYER _SIGN _FACING [ ( drone . dir + 2 ) % 4 ] ) ;
2013-12-24 01:09:49 +01:00
2014-01-04 19:39:49 +01:00
# # # # Drone . PLAYER _TORCH _FACING
2014-12-30 19:12:10 +01:00
Used when placing torches . By default torches will be placed facing up . If you want to place a torch so that it faces towards the drone :
2013-12-24 01:09:49 +01:00
drone . box ( blocks . torch + ':' + Drone . PLAYER _TORCH _FACING [ drone . dir ] ) ;
2014-12-30 19:12:10 +01:00
If you want to place a torch so it faces _away _ from the drone :
drone . box ( blocks . torch + ':' + Drone . PLAYER _TORCH _FACING [ ( drone . dir + 2 ) % 4 ] ) ;
2013-12-24 01:09:49 +01:00
* * * /
//
// Implementation
// ==============
//
// There is no need to read any further unless you want to understand how the Drone object works.
//
2014-12-28 16:07:08 +01:00
function getDirFromRotation ( location ) {
// 0 = east, 1 = south, 2 = west, 3 = north
// 46 to 135 = west
// 136 to 225 = north
// 226 to 315 = east
// 316 to 45 = south
var r ;
if ( _ _plugin . canary ) {
r = location . rotation ;
}
if ( _ _plugin . bukkit ) {
r = location . yaw ;
}
// west = -270
// north = -180
// east = -90
// south = 0
r = ( r + 360 ) % 360 ; // east could be 270 or -90
if ( r > 45 && r <= 135 )
return 2 ; // west
if ( r > 135 && r <= 225 )
return 3 ; // north
if ( r > 225 && r <= 315 )
return 0 ; // east
return 1 ; // south
}
2015-01-01 13:47:36 +01:00
function putBlock ( x , y , z , blockId , metadata , world , dir , update ) {
2014-01-29 20:49:15 +01:00
if ( typeof metadata == 'undefined' ) {
metadata = 0 ;
}
2014-12-30 19:12:10 +01:00
var block = world . getBlockAt ( x , y , z ) ;
2014-12-30 15:54:38 +01:00
if ( _ _plugin . canary ) {
var BlockType = Packages . net . canarymod . api . world . blocks . BlockType ;
block . type = BlockType . fromId ( blockId ) ;
var applyProperties = require ( 'blockhelper' ) . applyProperties ;
applyProperties ( block , metadata ) ;
2015-01-01 13:47:36 +01:00
if ( typeof update === 'undefined' ) {
update = true ;
}
if ( update ) {
block . update ( ) ;
}
2014-12-30 15:54:38 +01:00
}
if ( _ _plugin . bukkit ) {
block . setTypeIdAndData ( blockId , metadata , false ) ;
block . data = metadata ;
2014-01-29 20:49:15 +01:00
}
2015-01-01 13:47:36 +01:00
return block ;
2014-12-28 16:07:08 +01:00
}
2013-12-24 01:09:49 +01:00
2014-12-23 16:56:38 +01:00
function Drone ( x , y , z , dir , world ) {
2014-01-29 20:49:15 +01:00
this . record = false ;
var usePlayerCoords = false ;
2014-04-07 21:59:09 +02:00
var player = ( typeof self !== 'undefined' ? self : null ) ;
2014-09-30 00:42:41 +02:00
var playerPos ;
if ( x . location && x . name ) {
2014-01-29 20:49:15 +01:00
player = x ;
2014-09-30 00:42:41 +02:00
}
playerPos = x . location ;
2014-01-29 20:49:15 +01:00
var that = this ;
var populateFromLocation = function ( loc ) {
that . x = loc . x ;
that . y = loc . y ;
that . z = loc . z ;
2014-12-28 16:07:08 +01:00
that . dir = getDirFromRotation ( loc ) ;
2014-01-29 20:49:15 +01:00
that . world = loc . world ;
} ;
var mp = utils . getMousePos ( player ) ;
2014-09-30 00:42:41 +02:00
if ( typeof x == 'undefined' || x . location ) {
2014-01-29 20:49:15 +01:00
if ( mp ) {
populateFromLocation ( mp ) ;
if ( playerPos ) {
2014-12-28 16:07:08 +01:00
this . dir = getDirFromRotation ( playerPos ) ;
2014-01-29 20:49:15 +01:00
}
} else {
// base it on the player's current location
usePlayerCoords = true ;
//
// it's possible that drone.js could be loaded by a non-playing op
// (from the server console)
//
if ( ! playerPos ) {
return null ;
}
populateFromLocation ( playerPos ) ;
2013-12-31 19:21:40 +01:00
}
2014-01-29 20:49:15 +01:00
} else {
2014-09-30 00:42:41 +02:00
if ( arguments [ 0 ] . x && arguments [ 0 ] . y && arguments [ 0 ] . z ) {
2014-01-29 20:49:15 +01:00
populateFromLocation ( arguments [ 0 ] ) ;
} else {
this . x = x ;
this . y = y ;
this . z = z ;
if ( typeof dir == 'undefined' ) {
2014-12-28 16:07:08 +01:00
this . dir = getDirFromRotation ( playerPos ) ;
2014-01-29 20:49:15 +01:00
} else {
this . dir = dir % 4 ;
}
if ( typeof world == 'undefined' ) {
this . world = playerPos . world ;
} else {
this . world = world ;
}
2013-12-24 01:09:49 +01:00
}
2014-01-29 20:49:15 +01:00
}
if ( usePlayerCoords ) {
this . fwd ( 3 ) ;
}
this . chkpt ( 'start' ) ;
this . record = true ;
this . history = [ ] ;
2014-03-11 00:18:33 +01:00
this . player = player ;
2014-01-29 20:49:15 +01:00
return this ;
2014-12-28 16:07:08 +01:00
}
2013-12-24 01:09:49 +01:00
2013-12-24 01:18:43 +01:00
exports . Drone = Drone ;
2013-12-25 14:39:04 +01:00
/ *
2014-01-29 20:49:15 +01:00
because this is a plugin , any of its exports will be exported globally .
Since 'blocks' is a module not a plugin it is convenient to export it via
the Drone module .
* /
2013-12-25 14:39:04 +01:00
exports . blocks = blocks ;
2014-12-28 16:07:08 +01:00
Drone . getDirFromRotation = getDirFromRotation ;
2014-02-16 19:37:51 +01:00
Drone . queue = [ ] ;
2014-04-19 18:28:43 +02:00
2014-03-08 22:01:25 +01:00
Drone . opsPerSec = 10 ;
2014-12-31 10:12:57 +01:00
Drone . processQueue = function processQueue ( ) {
2014-04-19 18:28:43 +02:00
var process ,
i = 0 ,
queues = getAllQueues ( ) ;
for ( ; i < queues . length ; i ++ ) {
process = queues [ i ] . shift ( ) ;
if ( process ) {
try {
2014-08-23 17:44:36 +02:00
process ( ) ;
2014-04-19 18:28:43 +02:00
} catch ( e ) {
2014-12-27 14:42:38 +01:00
console . log ( 'Drone build error: ' + e + ' while processing ' + process ) ;
2014-04-19 18:28:43 +02:00
}
}
2014-02-16 19:37:51 +01:00
}
2014-04-19 18:28:43 +02:00
setTimeout ( Drone . processQueue , 1000 / Drone . opsPerSec ) ;
2014-03-08 22:01:25 +01:00
} ;
2014-04-19 18:28:43 +02:00
setTimeout ( Drone . processQueue , 1000 / Drone . opsPerSec ) ;
addUnloadHandler ( function ( ) {
var pendingBuildOps = 0 ;
var allQueues = getAllQueues ( ) ;
for ( var i = 0 ; i < allQueues . length ; i ++ ) {
pendingBuildOps += allQueues [ i ] . length ;
}
2014-03-08 22:01:25 +01:00
if ( pendingBuildOps > 0 ) {
console . warn ( 'There were ' + pendingBuildOps + ' pending build operations which were cancelled' ) ;
2014-02-16 19:37:51 +01:00
}
2014-03-08 22:01:25 +01:00
} ) ;
2013-12-24 01:09:49 +01:00
//
// add custom methods to the Drone object using this function
//
2014-01-29 20:49:15 +01:00
Drone . extend = function ( name , func ) {
2014-05-24 11:55:27 +02:00
if ( arguments . length == 1 ) {
func = name ;
2014-08-23 17:44:36 +02:00
if ( ! func . name ) {
throw 'A Drone extension function must have a name!' ;
}
2014-05-24 11:55:27 +02:00
name = func . name ;
}
2014-01-29 20:49:15 +01:00
Drone . prototype [ '_' + name ] = func ;
Drone . prototype [ name ] = function ( ) {
if ( this . record ) {
this . history . push ( [ name , arguments ] ) ;
}
var oldVal = this . record ;
this . record = false ;
2014-03-11 00:18:33 +01:00
this [ '_' + name ] . apply ( this , arguments ) ;
2014-01-29 20:49:15 +01:00
this . record = oldVal ;
return this ;
} ;
global [ name ] = function ( ) {
var result = new Drone ( self ) ;
result [ name ] . apply ( result , arguments ) ;
return result ;
} ;
2013-12-24 01:09:49 +01:00
} ;
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2014-01-04 19:39:49 +01:00
# # # Drone . times ( ) Method
2014-12-28 16:07:08 +01:00
The times ( ) method makes building multiple copies of buildings
easy . It ' s possible to create rows or grids of buildings without
resorting to ` for ` or ` while ` loops .
2013-12-24 01:09:49 +01:00
2014-01-04 19:39:49 +01:00
# # # # Parameters
2013-12-24 01:09:49 +01:00
* numTimes ( optional - default 2 ) : The number of times you want to repeat the preceding statements .
2014-01-04 19:39:49 +01:00
# # # # Example
2013-12-24 01:09:49 +01:00
Say you want to do the same thing over and over . You have a couple of options ...
* You can use a for loop ...
2014-01-29 20:49:15 +01:00
d = new Drone ( ) ; for ( var i = 0 ; i < 4 ; i ++ ) { d . cottage ( ) . right ( 8 ) ; }
2013-12-24 01:09:49 +01:00
2014-12-28 16:07:08 +01:00
While this will fit on the in - game prompt , it ' s awkward . You need to
declare a new Drone object first , then write a for loop to create the
4 cottages . It ' s also error prone , even the ` for ` loop is too much
syntax for what should really be simple .
2013-12-24 01:09:49 +01:00
* You can use a while loop ...
2014-01-29 20:49:15 +01:00
d = new Drone ( ) ; var i = 4 ; while ( i -- ) { d . cottage ( ) . right ( 8 ) ; }
2013-12-24 01:09:49 +01:00
2014-12-28 16:07:08 +01:00
... which is slightly shorter but still too much syntax . Each of the
above statements is fine for creating a 1 - dimensional array of
structures . But what if you want to create a 2 - dimensional or
3 - dimensional array of structures ? Enter the ` times() ` method .
2013-12-24 01:09:49 +01:00
2014-12-28 16:07:08 +01:00
The ` times() ` method lets you repeat commands in a chain any number of
times . So to create 4 cottages in a row you would use the following
statement ...
2013-12-24 01:09:49 +01:00
cottage ( ) . right ( 8 ) . times ( 4 ) ;
2014-12-28 16:07:08 +01:00
... which will build a cottage , then move right 8 blocks , then do it
again 4 times over so that at the end you will have 4 cottages in a
row . What ' s more the ` times() ` method can be called more than once in
a chain . So if you wanted to create a * grid * of 20 houses ( 4 x 5 ) ,
you would do so using the following statement ...
2013-12-24 01:09:49 +01:00
cottage ( ) . right ( 8 ) . times ( 4 ) . fwd ( 8 ) . left ( 32 ) . times ( 5 ) ;
... breaking it down ...
2014-06-14 16:40:19 +02:00
1. The first 3 calls in the chain ( ` cottage() ` , ` right(8) ` , ` times(4) ` ) build a single row of 4 cottages .
2013-12-24 01:09:49 +01:00
2014-06-14 16:40:19 +02:00
2. The last 3 calls in the chain ( ` fwd(8) ` , ` left(32) ` , ` times(5) ` ) move the drone forward 8 then left 32 blocks ( 4 x 8 ) to return to the original x coordinate , then everything in the chain is repeated again 5 times so that in the end , we have a grid of 20 cottages , 4 x 5. Normally this would require a nested loop but the ` times() ` method does away with the need for loops when repeating builds .
2013-12-24 01:09:49 +01:00
Another example : This statement creates a row of trees 2 by 3 ...
oak ( ) . right ( 10 ) . times ( 2 ) . left ( 20 ) . fwd ( 10 ) . times ( 3 )
... You can see the results below .
! [ times example 1 ] ( img / times - trees . png )
* * * /
2014-01-29 20:49:15 +01:00
Drone . prototype . times = function ( numTimes , commands ) {
if ( typeof numTimes == 'undefined' ) {
numTimes = 2 ;
}
if ( typeof commands == 'undefined' ) {
commands = this . history . concat ( ) ;
}
this . history = [ [ 'times' , [ numTimes + 1 , commands ] ] ] ;
var oldVal = this . record ;
this . record = false ;
for ( var j = 1 ; j < numTimes ; j ++ ) {
for ( var i = 0 ; i < commands . length ; i ++ ) {
var command = commands [ i ] ;
var methodName = command [ 0 ] ;
var args = command [ 1 ] ;
this [ methodName ] . apply ( this , args ) ;
2013-12-24 01:09:49 +01:00
}
2014-01-29 20:49:15 +01:00
}
this . record = oldVal ;
return this ;
2013-12-24 01:09:49 +01:00
} ;
2014-01-29 20:49:15 +01:00
2014-12-28 16:07:08 +01:00
Drone . prototype . getBlock = function ( ) {
return this . world . getBlockAt ( this . x , this . y , this . z ) ;
} ;
2015-01-01 13:47:36 +01:00
Drone . prototype . setBlock = function ( blockType , data , ow , oh , od , update ) {
if ( typeof ow == 'undefined' )
ow = 0 ;
if ( typeof oh == 'undefined' )
oh = 0 ;
if ( typeof od == 'undefined' )
od = 0 ;
this
. right ( ow )
. up ( oh )
. fwd ( od ) ;
var result = putBlock ( this . x , this . y , this . z , blockType , data , this . world , this . dir , update ) ;
this
. left ( ow )
. down ( oh )
. back ( od ) ;
return result ;
2014-12-28 16:07:08 +01:00
} ;
Drone . prototype . traverseWidth = function ( width , callback ) {
_traverse [ this . dir ] . width ( this , width , callback ) ;
} ;
Drone . prototype . traverseHeight = function ( height , callback ) {
traverseHeight ( this , height , callback ) ;
} ;
Drone . prototype . traverseDepth = function ( depth , callback ) {
_traverse [ this . dir ] . depth ( this , depth , callback ) ;
2013-12-24 01:09:49 +01:00
} ;
//
// building
//
2014-01-29 20:49:15 +01:00
2014-04-19 18:28:43 +02:00
var playerQueues = { } ;
/ *
if the drone has an associated player , then use that player ' s queue otherwise
use the global queue .
* /
function getQueue ( drone ) {
if ( drone . player ) {
var playerName = '' + drone . player . name ;
var result = playerQueues [ playerName ] ;
if ( result === undefined ) {
playerQueues [ playerName ] = [ ] ;
return playerQueues [ playerName ] ;
}
return result ;
} else {
return Drone . queue ;
}
}
function getAllQueues ( ) {
var result = [ Drone . queue ] ;
for ( var pq in playerQueues ) {
result . push ( playerQueues [ pq ] ) ;
}
return result ;
}
2014-03-11 22:35:59 +01:00
Drone . prototype . cuboida = function ( /* Array */ blocks , w , h , d , overwrite , immediate ) {
2014-08-23 17:44:36 +02:00
//
// wph 20140823 make a copy because don't want to modify array in background
//
var blocksForBuild = blocks . slice ( ) ;
var len = blocksForBuild . length ,
2014-03-11 22:35:59 +01:00
i = 0 ;
2014-02-19 01:15:44 +01:00
2014-03-11 22:35:59 +01:00
if ( ! immediate ) {
for ( ; i < len ; i ++ ) {
2014-08-23 17:44:36 +02:00
blocksForBuild [ i ] = this . _getBlockIdAndMeta ( blocksForBuild [ i ] ) ;
2014-03-11 22:35:59 +01:00
}
var clone = Drone . clone ( this ) ;
2014-08-23 17:44:36 +02:00
var impl = this . cuboida . bind ( clone , blocksForBuild , w , h , d , overwrite , true ) ;
getQueue ( this ) . push ( function cuboida ( ) { impl ( ) ; } ) ;
2014-03-11 22:35:59 +01:00
return this ;
}
2014-02-19 01:15:44 +01:00
if ( typeof overwrite == 'undefined' ) {
overwrite = true ;
}
2014-01-29 20:49:15 +01:00
if ( typeof h == 'undefined' ) {
h = 1 ;
}
if ( typeof d == 'undefined' ) {
d = 1 ;
}
if ( typeof w == 'undefined' ) {
w = 1 ;
}
var bi = 0 ;
2014-12-28 16:07:08 +01:00
traverseDHW ( this , d , h , w , function traverseWidthCallback ( ) {
var properBlock = blocksForBuild [ bi % len ] ;
this . setBlock ( properBlock [ 0 ] , properBlock [ 1 ] ) ;
bi ++ ;
2014-01-29 20:49:15 +01:00
} ) ;
return this ;
2013-12-24 01:09:49 +01:00
} ;
2014-12-28 16:07:08 +01:00
Drone . MAX _VOLUME = 1 * MILLION ;
Drone . MAX _SIDE = 1 * THOUSAND ;
2014-03-13 20:23:32 +01:00
var tooBig = function ( w , h , d ) {
return ( w * h * d ) >= Drone . MAX _VOLUME ||
( w >= Drone . MAX _SIDE ) ||
( h >= Drone . MAX _SIDE ) ||
( d >= Drone . MAX _SIDE ) ;
} ;
2013-12-24 01:09:49 +01:00
/ *
2014-01-29 20:49:15 +01:00
faster cuboid because blockid , meta and world must be provided
use this method when you need to repeatedly place blocks
* /
2014-03-08 22:01:25 +01:00
Drone . prototype . cuboidX = function ( blockType , meta , w , h , d , immediate ) {
2014-01-29 20:49:15 +01:00
if ( typeof h == 'undefined' ) {
h = 1 ;
}
if ( typeof d == 'undefined' ) {
d = 1 ;
}
if ( typeof w == 'undefined' ) {
w = 1 ;
}
2014-03-13 20:23:32 +01:00
if ( tooBig ( w , h , d ) ) {
2014-03-08 22:01:25 +01:00
this . sign ( [
'Build too Big!' ,
'width:' + w ,
'height:' + h ,
'depth:' + d
] , 68 ) ;
console . warn ( 'Build too big! ' + w + ' X ' + h + ' X ' + d ) ;
return this ;
}
if ( ! immediate ) {
var clone = Drone . clone ( this ) ;
2014-08-23 17:44:36 +02:00
var impl = this . cuboidX . bind ( clone , blockType , meta , w , h , d , true ) ;
getQueue ( this ) . push ( function cuboidX ( ) { impl ( ) ; } ) ;
2014-03-08 22:01:25 +01:00
return this ;
}
2014-12-28 16:07:08 +01:00
traverseDHW ( this , d , h , w , function ( ) {
this . setBlock ( blockType , meta ) ;
} ) ;
2014-01-29 20:49:15 +01:00
return this ;
2013-12-24 01:09:49 +01:00
} ;
2014-12-27 14:42:38 +01:00
/ *
deferred execution of a drone method
* /
Drone . prototype . then = function ( next ) {
getQueue ( this ) . push ( next . bind ( Drone . clone ( this ) ) ) ;
} ;
2015-01-03 12:08:40 +01:00
Drone . prototype . cuboid = function ( block , w , h , d , immediate ) {
2014-01-29 20:49:15 +01:00
var bm = this . _getBlockIdAndMeta ( block ) ;
2015-01-03 12:08:40 +01:00
return this . cuboidX ( bm [ 0 ] , bm [ 1 ] , w , h , d , immediate ) ;
2013-12-24 01:09:49 +01:00
} ;
2014-01-29 20:49:15 +01:00
2015-01-03 12:08:40 +01:00
Drone . prototype . cuboid0 = function ( block , w , h , d , immediate ) {
var start = 'cuboid0' + w + h + d + immediate ;
this
. chkpt ( start )
. cuboid ( block , w , h , 1 , immediate ) // Front wall
. cuboid ( block , 1 , h , d , immediate ) // Left wall
. right ( w - 1 )
. cuboid ( block , 1 , h , d , immediate ) // Right wall
. left ( w - 1 )
. fwd ( d - 1 )
. cuboid ( block , w , h , 1 , immediate ) // Back wall
. move ( start ) ;
2013-12-24 01:09:49 +01:00
} ;
2014-01-29 20:49:15 +01:00
2014-12-27 20:03:30 +01:00
2014-02-19 01:15:44 +01:00
2013-12-24 01:09:49 +01:00
// player dirs: 0 = east, 1 = south, 2 = west, 3 = north
// block dirs: 0 = east, 1 = west, 2 = south , 3 = north
// sign dirs: 5 = east, 3 = south, 4 = west, 2 = north
2014-01-29 20:49:15 +01:00
Drone . PLAYER _STAIRS _FACING = [ 0 , 2 , 1 , 3 ] ;
2014-12-29 23:42:00 +01:00
2013-12-24 01:09:49 +01:00
// for blocks 68 (wall signs) 65 (ladders) 61,62 (furnaces) 23 (dispenser) and 54 (chest)
2014-01-29 20:49:15 +01:00
Drone . PLAYER _SIGN _FACING = [ 4 , 2 , 5 , 3 ] ;
Drone . PLAYER _TORCH _FACING = [ 2 , 4 , 1 , 3 ] ;
2014-08-23 17:44:36 +02:00
Drone . extend ( 'box' , Drone . prototype . cuboid ) ;
2014-01-29 20:49:15 +01:00
Drone . extend ( 'box0' , Drone . prototype . cuboid0 ) ;
Drone . extend ( 'boxa' , Drone . prototype . cuboida ) ;
2013-12-24 01:09:49 +01:00
//
// show the Drone's position and direction
//
2014-01-29 20:49:15 +01:00
Drone . prototype . toString = function ( ) {
var dirs = [ 'east' , 'south' , 'west' , 'north' ] ;
return 'x: ' + this . x + ' y: ' + this . y + ' z: ' + this . z + ' dir: ' + this . dir + ' ' + dirs [ this . dir ] ;
2013-12-24 01:09:49 +01:00
} ;
2014-01-29 20:49:15 +01:00
Drone . prototype . debug = function ( ) {
2014-04-25 21:51:15 +02:00
console . log ( this . toString ( ) ) ;
2014-01-29 20:49:15 +01:00
return this ;
2013-12-24 01:09:49 +01:00
} ;
2014-01-29 20:49:15 +01:00
2014-12-23 16:56:38 +01:00
function _getBlockIdAndMeta ( b ) {
2014-03-11 22:35:59 +01:00
var defaultMeta = 0 ,
i = 0 ,
bs ,
md ,
sp ;
2014-12-30 15:54:38 +01:00
if ( typeof b === 'number' || /^[0-9]+$/ . test ( b ) ) {
// wph 20130414 - use sensible defaults for certain blocks e.g. stairs
// should face the drone.
switch ( b ) {
case blocks . stairs . oak :
case blocks . stairs . cobblestone :
case blocks . stairs . brick :
case blocks . stairs . stone :
case blocks . stairs . nether :
case blocks . stairs . sandstone :
case blocks . stairs . spruce :
case blocks . stairs . jungle :
case blocks . stairs . quartz :
defaultMeta = Drone . PLAYER _STAIRS _FACING [ this . dir % 4 ] ;
break ;
case blocks . sign :
case blocks . ladder :
// bug: furnace, chest, dispenser don't always use the right metadata
case blocks . furnace :
case blocks . furnace _burning :
case blocks . chest :
case blocks . enderchest :
case blocks . dispenser :
defaultMeta = Drone . PLAYER _SIGN _FACING [ this . dir % 4 ] ;
break ;
case blocks . sign _post :
defaultMeta = ( 12 + ( ( this . dir + 2 ) * 4 ) ) % 16 ;
break ;
}
return [ b , defaultMeta ] ;
}
if ( typeof b === 'string' ) {
2014-03-11 22:35:59 +01:00
bs = b ;
sp = bs . indexOf ( ':' ) ;
2014-01-29 20:49:15 +01:00
if ( sp == - 1 ) {
2014-12-30 15:54:38 +01:00
b = parseInt ( bs ) ;
2014-03-11 22:35:59 +01:00
return [ b , defaultMeta ] ;
2014-01-29 20:49:15 +01:00
}
b = parseInt ( bs . substring ( 0 , sp ) ) ;
2014-03-11 22:35:59 +01:00
md = parseInt ( bs . substring ( sp + 1 , bs . length ) ) ;
2014-01-29 20:49:15 +01:00
return [ b , md ] ;
2014-12-30 15:54:38 +01:00
}
if ( b . id ) {
// wph 20141230 we are dealing with an object
var blockInfo = b ;
var metadata = { } ;
for ( i in b ) {
if ( i !== 'id' )
metadata [ i ] = b [ i ] ;
2013-12-24 01:09:49 +01:00
}
2014-12-30 15:54:38 +01:00
return [ b . id , metadata ] ;
2014-01-29 20:49:15 +01:00
}
2014-12-30 15:54:38 +01:00
}
2013-12-24 01:09:49 +01:00
var _traverse = [ { } , { } , { } , { } ] ;
// east
2014-12-28 16:07:08 +01:00
function walkWidthEast ( drone , n , callback ) {
var s = drone . z , e = s + n ;
for ( ; drone . z < e ; drone . z ++ ) {
callback . call ( drone , drone . z - s ) ;
2014-01-29 20:49:15 +01:00
}
2014-12-28 16:07:08 +01:00
drone . z = s ;
2014-08-23 17:44:36 +02:00
}
2014-12-28 16:07:08 +01:00
function walkDepthEast ( drone , n , callback ) {
var s = drone . x , e = s + n ;
for ( ; drone . x < e ; drone . x ++ ) {
callback . call ( drone , drone . x - s ) ;
2014-01-29 20:49:15 +01:00
}
2014-12-28 16:07:08 +01:00
drone . x = s ;
2014-08-23 17:44:36 +02:00
}
2014-12-28 16:07:08 +01:00
function walkWidthSouth ( drone , n , callback ) {
var s = drone . x , e = s - n ;
for ( ; drone . x > e ; drone . x -- ) {
callback . call ( drone , s - drone . x ) ;
2014-01-29 20:49:15 +01:00
}
2014-12-28 16:07:08 +01:00
drone . x = s ;
2014-08-23 17:44:36 +02:00
}
2014-12-28 16:07:08 +01:00
function walkWidthWest ( drone , n , callback ) {
var s = drone . z , e = s - n ;
for ( ; drone . z > e ; drone . z -- ) {
callback . call ( drone , s - drone . z ) ;
2014-01-29 20:49:15 +01:00
}
2014-12-28 16:07:08 +01:00
drone . z = s ;
2014-08-23 17:44:36 +02:00
}
_traverse [ 0 ] . width = walkWidthEast ;
_traverse [ 0 ] . depth = walkDepthEast ;
// south
_traverse [ 1 ] . width = walkWidthSouth ;
_traverse [ 1 ] . depth = walkWidthEast ;
// west
_traverse [ 2 ] . width = walkWidthWest ;
_traverse [ 2 ] . depth = walkWidthSouth ;
2013-12-24 01:09:49 +01:00
// north
2014-08-23 17:44:36 +02:00
_traverse [ 3 ] . width = walkDepthEast ;
_traverse [ 3 ] . depth = walkWidthWest ;
2014-12-28 16:07:08 +01:00
function traverseHeight ( drone , n , callback ) {
var s = drone . y , e = s + n ;
for ( ; drone . y < e ; drone . y ++ ) {
callback . call ( drone , drone . y - s ) ;
2014-01-29 20:49:15 +01:00
}
2014-12-28 16:07:08 +01:00
drone . y = s ;
2013-12-24 01:09:49 +01:00
} ;
2014-12-28 16:07:08 +01:00
function traverseDHW ( drone , d , h , w , callback ) {
_traverse [ drone . dir ] . depth ( drone , d , function traverseDepthCallback ( ) {
traverseHeight ( this , h , function traverseHeightCallback ( ) {
_traverse [ this . dir ] . width ( this , w , callback ) ;
} ) ;
} ) ;
2013-12-24 01:09:49 +01:00
}
2014-12-23 16:56:38 +01:00
2014-03-08 22:01:25 +01:00
Drone . clone = function ( origin ) {
2014-12-27 14:42:38 +01:00
var result = new Drone ( origin . x , origin . y , origin . z , origin . dir , origin . world ) ;
2014-03-08 22:01:25 +01:00
return result ;
} ;
2013-12-24 01:09:49 +01:00
//
// wph 20130130 - make this a method - extensions can use it.
//
Drone . prototype . _getBlockIdAndMeta = _getBlockIdAndMeta ;
2015-01-01 13:47:36 +01:00
Drone . bountiful = _ _plugin . canary ? parseFloat ( server . canaryModVersion ) > 1.7 : false ;