Reorganization of Drone from 1 monolithic module to smaller modules.

This commit is contained in:
walterhiggins 2014-12-28 15:07:08 +00:00
parent 8056da0d3b
commit b0e15bfa80
15 changed files with 1370 additions and 1278 deletions

View file

@ -1052,51 +1052,29 @@ following code sends a message to any player who breaks a block in the
game... game...
```javascript ```javascript
events.on('block.BlockBreakEvent', function ( event ) { function myBlockDestroyHook( event ){
var breaker = event.player; var breaker = event.player;
breaker.sendMessage('You broke a block'); echo( breaker, 'You broke a block');
} ); }
events.blockDestroy( myBlockDestroyHook );
``` ```
The `events.on()` function is how you *register* a function which you The `events.blockDestroy()` function is just one of the many `events` functions which can be used to *register* a function to be called whenever a particular type of event occurs. In the
want to be called whenever a particular type of event occurs. In the above code the blockDestroy function takes as a parameter a function
above code the first parameter `'block.BlockBreakEvent'` is the type
of event I want to listen for and the second parameter is the function
I want to be called when that event occurs. The function I want called I want to be called when that event occurs. The function I want called
in turn takes 1 parameter. The `event` object has all the information in turn takes 1 parameter. The `event` object has all the information
about the event which just occurred. I can tell who broke the block about the event which just occurred. I can tell who broke the block
and send a message to the player. The important thing to note is that and send a message to the player. The important thing to note is that
the function defined above will not be called until a player breaks a the `myBlockDestroyHook` function defined above will not be called until a player breaks a
block. Try it - save the above code in a new file in the block. Try it - save the above code in a new file in the
`scriptcraft/plugins` directory then type `/js refresh()` to reload `scriptcraft/plugins` directory then type `/js refresh()` to reload
scriptcraft. Then break a block in the game and you should see the scriptcraft. Then break a block in the game and you should see the
message 'You broke a block'. message 'You broke a block'.
There are many types of events you can listen for in Minecraft. You can There are many types of events you can listen for in Minecraft. You can
browse [all possible Bukkit events][bkevts] (click the 'Next browse [all possible Canary events][cmevts] .
Package' and 'Previous Package' links to browse).
It's important to note that when browsing the Bukkit API's For custom events (events which aren't in the net.canarymod.hook tree)
[org.bukkit.event][bkevts] package, if you see a class called
'org.bukkit.events.entity.EntityShootBowEvent', then when calling
`events.on()` you can listen to such an event using either the fully
qualified Class name...
events.on(org.bukkit.events.entity.EntityShootBowEvent, function( event ) {
...
});
or an abbreviated name in string form...
events.on('entity.EntityShootBowEvent', function( event ) {
...
});
If the `events.on()` function gets a String (text) as its first
parameter it automatically converts it to the appropriate Class by
prepending the 'org.bukkit.events' package.
For custom events (events which aren't in the org.bukkit.event tree)
just specify the fully qualified class name instead. E.g. ... just specify the fully qualified class name instead. E.g. ...
events.on ( net.yourdomain.events.YourEvent, function( event ) { events.on ( net.yourdomain.events.YourEvent, function( event ) {
@ -1108,9 +1086,9 @@ just specify the fully qualified class name instead. E.g. ...
If you want an event handler to only execute once, you can remove the handler like this... If you want an event handler to only execute once, you can remove the handler like this...
```javascript ```javascript
events.on('block.BlockBreakEvent', function( evt ) { events.blockDestroy( function( evt ) {
var breaker = evt.player; var breaker = evt.player;
breaker.sendMessage('You broke a block'); echo( breaker, 'You broke a block');
this.unregister(); this.unregister();
} ); } );
``` ```
@ -1124,12 +1102,10 @@ to stop listening for events.
To unregister a listener *outside* of the listener function... To unregister a listener *outside* of the listener function...
```javascript ```javascript
var myBlockBreakListener = events.on( 'block.BlockBreakEvent', function( evt ) { ... } ); var myBlockBreakListener = events.blockDestroy(function( evt ) { ... } );
... ...
myBlockBreakListener.unregister(); myBlockBreakListener.unregister();
``` ```
## Keeping Score - Lookup tables in Javascript ## Keeping Score - Lookup tables in Javascript
In the *Event-Driven Programming* section, I defined a function which In the *Event-Driven Programming* section, I defined a function which
@ -1288,6 +1264,7 @@ different objects and methods available for use by ScriptCraft.
[api]: API-Reference.md [api]: API-Reference.md
[twl]: http://www.barebones.com/products/textwrangler/ [twl]: http://www.barebones.com/products/textwrangler/
[bkevts]: http://jd.bukkit.org/dev/apidocs/org/bukkit/event/package-summary.html [bkevts]: http://jd.bukkit.org/dev/apidocs/org/bukkit/event/package-summary.html
[cmevts]: https://ci.visualillusionsent.net/job/CanaryLib/javadoc/net/canarymod/hook/package-summary.html
[img_echo_date]: img/ypgpm_echo_date.png [img_echo_date]: img/ypgpm_echo_date.png
[img_3d_shapes]: img/ypgpm_3dshapes.jpg [img_3d_shapes]: img/ypgpm_3dshapes.jpg
[img_whd]: img/ypgpm_whd.jpg [img_whd]: img/ypgpm_whd.jpg

View file

@ -1016,51 +1016,29 @@ following code sends a message to any player who breaks a block in the
game... game...
```javascript ```javascript
events.on('block.BlockBreakEvent', function ( event ) { function myBlockDestroyHook( event ){
var breaker = event.player; var breaker = event.player;
breaker.sendMessage('You broke a block'); echo( breaker, 'You broke a block');
} ); }
events.blockDestroy( myBlockDestroyHook );
``` ```
The `events.on()` function is how you *register* a function which you The `events.blockDestroy()` function is just one of the many `events` functions which can be used to *register* a function to be called whenever a particular type of event occurs. In the
want to be called whenever a particular type of event occurs. In the above code the blockDestroy function takes as a parameter a function
above code the first parameter `'block.BlockBreakEvent'` is the type
of event I want to listen for and the second parameter is the function
I want to be called when that event occurs. The function I want called I want to be called when that event occurs. The function I want called
in turn takes 1 parameter. The `event` object has all the information in turn takes 1 parameter. The `event` object has all the information
about the event which just occurred. I can tell who broke the block about the event which just occurred. I can tell who broke the block
and send a message to the player. The important thing to note is that and send a message to the player. The important thing to note is that
the function defined above will not be called until a player breaks a the `myBlockDestroyHook` function defined above will not be called until a player breaks a
block. Try it - save the above code in a new file in the block. Try it - save the above code in a new file in the
`scriptcraft/plugins` directory then type `/js refresh()` to reload `scriptcraft/plugins` directory then type `/js refresh()` to reload
scriptcraft. Then break a block in the game and you should see the scriptcraft. Then break a block in the game and you should see the
message 'You broke a block'. message 'You broke a block'.
There are many types of events you can listen for in Minecraft. You can There are many types of events you can listen for in Minecraft. You can
browse [all possible Bukkit events][bkevts] (click the 'Next browse [all possible Canary events][cmevts] .
Package' and 'Previous Package' links to browse).
It's important to note that when browsing the Bukkit API's For custom events (events which aren't in the net.canarymod.hook tree)
[org.bukkit.event][bkevts] package, if you see a class called
'org.bukkit.events.entity.EntityShootBowEvent', then when calling
`events.on()` you can listen to such an event using either the fully
qualified Class name...
events.on(org.bukkit.events.entity.EntityShootBowEvent, function( event ) {
...
});
or an abbreviated name in string form...
events.on('entity.EntityShootBowEvent', function( event ) {
...
});
If the `events.on()` function gets a String (text) as its first
parameter it automatically converts it to the appropriate Class by
prepending the 'org.bukkit.events' package.
For custom events (events which aren't in the org.bukkit.event tree)
just specify the fully qualified class name instead. E.g. ... just specify the fully qualified class name instead. E.g. ...
events.on ( net.yourdomain.events.YourEvent, function( event ) { events.on ( net.yourdomain.events.YourEvent, function( event ) {
@ -1072,9 +1050,9 @@ just specify the fully qualified class name instead. E.g. ...
If you want an event handler to only execute once, you can remove the handler like this... If you want an event handler to only execute once, you can remove the handler like this...
```javascript ```javascript
events.on('block.BlockBreakEvent', function( evt ) { events.blockDestroy( function( evt ) {
var breaker = evt.player; var breaker = evt.player;
breaker.sendMessage('You broke a block'); echo( breaker, 'You broke a block');
this.unregister(); this.unregister();
} ); } );
``` ```
@ -1088,12 +1066,10 @@ to stop listening for events.
To unregister a listener *outside* of the listener function... To unregister a listener *outside* of the listener function...
```javascript ```javascript
var myBlockBreakListener = events.on( 'block.BlockBreakEvent', function( evt ) { ... } ); var myBlockBreakListener = events.blockDestroy(function( evt ) { ... } );
... ...
myBlockBreakListener.unregister(); myBlockBreakListener.unregister();
``` ```
## Keeping Score - Lookup tables in Javascript ## Keeping Score - Lookup tables in Javascript
In the *Event-Driven Programming* section, I defined a function which In the *Event-Driven Programming* section, I defined a function which
@ -1252,6 +1228,7 @@ different objects and methods available for use by ScriptCraft.
[api]: API-Reference.md [api]: API-Reference.md
[twl]: http://www.barebones.com/products/textwrangler/ [twl]: http://www.barebones.com/products/textwrangler/
[bkevts]: http://jd.bukkit.org/dev/apidocs/org/bukkit/event/package-summary.html [bkevts]: http://jd.bukkit.org/dev/apidocs/org/bukkit/event/package-summary.html
[cmevts]: https://ci.visualillusionsent.net/job/CanaryLib/javadoc/net/canarymod/hook/package-summary.html
[img_echo_date]: img/ypgpm_echo_date.png [img_echo_date]: img/ypgpm_echo_date.png
[img_3d_shapes]: img/ypgpm_3dshapes.jpg [img_3d_shapes]: img/ypgpm_3dshapes.jpg
[img_whd]: img/ypgpm_whd.jpg [img_whd]: img/ypgpm_whd.jpg

View file

@ -0,0 +1,268 @@
/*global require*/
'use strict';
/************************************************************************
### Drone.arc() method
The arc() method can be used to create 1 or more 90 degree arcs in the
horizontal or vertical planes. This method is called by cylinder() and
cylinder0() and the sphere() and sphere0() methods.
#### Parameters
arc() takes a single parameter - an object with the following named properties...
* radius - The radius of the arc.
* blockType - The type of block to use - this is the block Id only (no meta). See [Data Values][dv].
* meta - The metadata value. See [Data Values][dv].
* orientation (default: 'horizontal' ) - the orientation of the arc - can be 'vertical' or 'horizontal'.
* stack (default: 1 ) - the height or length of the arc (depending on the orientation - if orientation is horizontal then this parameter refers to the height, if vertical then it refers to the length ).
* strokeWidth (default: 1 ) - the width of the stroke (how many blocks) - if drawing nested arcs it's usually a good idea to set strokeWidth to at least 2 so that there are no gaps between each arc. The arc method uses a [bresenham algorithm][bres] to plot points along the circumference.
* fill - If true (or present) then the arc will be filled in.
* quadrants (default: `{topleft:true,topright:true,bottomleft:true,bottomright:true}` - An object with 4 properties indicating which of the 4 quadrants of a circle to draw. If the quadrants property is absent then all 4 quadrants are drawn.
#### Examples
To draw a 1/4 circle (top right quadrant only) with a radius of 10 and
stroke width of 2 blocks ...
arc({blockType: blocks.iron,
meta: 0,
radius: 10,
strokeWidth: 2,
quadrants: { topright: true },
orientation: 'vertical',
stack: 1,
fill: false
} );
![arc example 1](img/arcex1.png)
[bres]: http://en.wikipedia.org/wiki/Midpoint_circle_algorithm
[dv]: http://www.minecraftwiki.net/wiki/Data_values
***/
var Drone = require('./drone').Drone;
/*
do the bresenham thing
*/
function bresenham( x0,y0,radius, setPixel, quadrants ) {
//
// credit: Following code is copied almost verbatim from
// http://en.wikipedia.org/wiki/Midpoint_circle_algorithm
// Bresenham's circle algorithm
//
var f = 1 - radius;
var ddF_x = 1;
var ddF_y = -2 * radius;
var x = 0;
var y = radius;
var defaultQuadrants = {topleft: true, topright: true, bottomleft: true, bottomright: true};
quadrants = quadrants?quadrants:defaultQuadrants;
/*
II | I
------------
III | IV
*/
if ( quadrants.topleft || quadrants.topright )
setPixel(x0, y0 + radius ); // quadrant I/II topmost
if ( quadrants.bottomleft || quadrants.bottomright )
setPixel(x0, y0 - radius ); // quadrant III/IV bottommost
if ( quadrants.topright || quadrants.bottomright )
setPixel(x0 + radius, y0 ); // quadrant I/IV rightmost
if ( quadrants.topleft || quadrants.bottomleft )
setPixel(x0 - radius, y0 ); // quadrant II/III leftmost
while ( x < y ) {
if(f >= 0 ) {
y--;
ddF_y += 2;
f += ddF_y;
}
x++;
ddF_x += 2;
f += ddF_x;
if ( quadrants.topright ) {
setPixel(x0 + x, y0 + y ); // quadrant I
setPixel(x0 + y, y0 + x ); // quadrant I
}
if ( quadrants.topleft ) {
setPixel(x0 - x, y0 + y ); // quadrant II
setPixel(x0 - y, y0 + x ); // quadrant II
}
if ( quadrants.bottomleft ) {
setPixel(x0 - x, y0 - y ); // quadrant III
setPixel(x0 - y, y0 - x ); // quadrant III
}
if ( quadrants.bottomright ) {
setPixel(x0 + x, y0 - y ); // quadrant IV
setPixel(x0 + y, y0 - x ); // quadrant IV
}
}
};
function getStrokeDir( x,y ) {
var absY = Math.abs(y );
var absX = Math.abs(x );
var strokeDir = 0;
if ( y > 0 && absY >= absX )
strokeDir = 0 ; //down
else if ( y < 0 && absY >= absX )
strokeDir = 1 ; // up
else if ( x > 0 && absX >= absY )
strokeDir = 2 ; // left
else if ( x < 0 && absX >= absY )
strokeDir = 3 ; // right
return strokeDir;
};
/*
The daddy of all arc-related API calls -
if you're drawing anything that bends it ends up here.
*/
function arcImpl( params ) {
var drone = params.drone;
var orientation = params.orientation?params.orientation:'horizontal';
var quadrants = params.quadrants?params.quadrants:{
topright:1,
topleft:2,
bottomleft:3,
bottomright:4
};
var stack = params.stack?params.stack:1;
var radius = params.radius;
var strokeWidth = params.strokeWidth?params.strokeWidth:1;
drone.chkpt('arc2' );
var x0, y0, gotoxy,setPixel;
if ( orientation == 'horizontal' ) {
gotoxy = function( x,y ) { return drone.right(x ).fwd(y );};
drone.right(radius ).fwd(radius ).chkpt('center' );
switch ( drone.dir ) {
case 0: // east
case 2: // west
x0 = drone.z;
y0 = drone.x;
break;
case 1: // south
case 3: // north
x0 = drone.x;
y0 = drone.z;
}
setPixel = function( x, y ) {
x = ( x-x0 );
y = ( y-y0 );
if ( params.fill ) {
// wph 20130114 more efficient esp. for large cylinders/spheres
if ( y < 0 ) {
drone
.fwd( y ).right( x )
.cuboidX( params.blockType, params.meta, 1, stack, Math.abs( y * 2 ) + 1 )
.back( y ).left( x );
}
}else{
if ( strokeWidth == 1 ) {
gotoxy(x,y )
.cuboidX( params.blockType, params.meta,
1, // width
stack, // height
strokeWidth // depth
)
.move('center' );
} else {
var strokeDir = getStrokeDir( x, y );
var width = 1, depth = 1;
switch ( strokeDir ) {
case 0: // down
y = y-( strokeWidth - 1 );
depth = strokeWidth;
break;
case 1: // up
depth = strokeWidth;
break;
case 2: // left
width = strokeWidth;
x = x-(strokeWidth-1 );
break;
case 3: // right
width = strokeWidth;
break;
}
gotoxy( x, y )
.cuboidX( params.blockType, params.meta, width, stack, depth )
.move( 'center' );
}
}
};
}else{
// vertical
gotoxy = function( x,y ) { return drone.right(x ).up(y );};
drone.right(radius ).up(radius ).chkpt('center' );
switch ( drone.dir ) {
case 0: // east
case 2: // west
x0 = drone.z;
y0 = drone.y;
break;
case 1: // south
case 3: // north
x0 = drone.x;
y0 = drone.y;
}
setPixel = function( x, y ) {
x = ( x - x0 );
y = ( y - y0 );
if ( params.fill ) {
// wph 20130114 more efficient esp. for large cylinders/spheres
if ( y < 0 ) {
drone
.up( y ).right( x )
.cuboidX( params.blockType, params.meta, 1, Math.abs( y * 2 ) + 1, stack )
.down( y ).left( x );
}
}else{
if ( strokeWidth == 1 ) {
gotoxy( x, y )
.cuboidX( params.blockType, params.meta, strokeWidth, 1, stack )
.move( 'center' );
}else{
var strokeDir = getStrokeDir( x,y );
var width = 1, height = 1;
switch ( strokeDir ) {
case 0: // down
y = y - ( strokeWidth - 1 );
height = strokeWidth;
break;
case 1: // up
height = strokeWidth;
break;
case 2: // left
width = strokeWidth;
x = x - ( strokeWidth - 1 );
break;
case 3: // right
width = strokeWidth;
break;
}
gotoxy(x,y )
.cuboidX(params.blockType, params.meta, width, height, stack )
.move('center' );
}
}
};
}
/*
setPixel assumes a 2D plane - need to put a block along appropriate plane
*/
bresenham(x0,y0,radius,setPixel,quadrants );
params.drone.move('arc2' );
};
Drone.extend(function arc( params ) {
params.drone = this;
arcImpl(params );
} );

View file

@ -1,32 +1,44 @@
var Drone = require('../drone').Drone; 'use strict';
var bkMaterial = org.bukkit.Material; /*global require, __plugin, org*/
var Drone = require('../drone').Drone,
bkMaterial = org.bukkit.Material,
blocks = require('blocks');
function canHang( material ) { function canHang( block ) {
if ( material.equals(bkMaterial.AIR) || if (__plugin.bukkit){
material.equals(bkMaterial.VINE) ) { if ( block.type.equals(bkMaterial.AIR) ||
block.type.equals(bkMaterial.VINE) ) {
return true; return true;
} else {
return false;
} }
}
if (__plugin.canary){
if (block.typeId == blocks.air ||
block.typeid == blocks.vines ) {
return true;
}
}
return false;
} }
function hangtorch() { function hangtorch() {
var torch = '50:' + Drone.PLAYER_TORCH_FACING[this.dir]; var torch = '50:' + Drone.PLAYER_TORCH_FACING[this.dir];
var moves = 0; var moves = 0;
var block = this.world.getBlockAt(this.x, this.y, this.z); var block = this.getBlock();
while ( !canHang(block.type) ){ while ( !canHang(block) ){
moves++; moves++;
this.back(); this.back();
if (moves == 10){ if (moves == 10){
this.fwd(moves); this
.fwd(moves);
console.log('nowhere to hang torch'); console.log('nowhere to hang torch');
return; return;
} }
block = this.world.getBlockAt(this.x, this.y, this.z); block = this.getBlock();
} }
this.box(torch) this
.box(torch)
.fwd(moves); .fwd(moves);
} }
Drone.extend(hangtorch); Drone.extend(hangtorch);

View file

@ -0,0 +1,143 @@
'use strict';
/*global require*/
var Drone = require('./drone').Drone;
/************************************************************************
### Copy & Paste using Drone
A drone can be used to copy and paste areas of the game world.
### Drone.copy() method
Copies an area so it can be pasted elsewhere. The name can be used for
pasting the copied area elsewhere...
#### Parameters
* name - the name to be given to the copied area (used by `paste`)
* width - the width of the area to copy
* height - the height of the area to copy
* length - the length of the area (extending away from the drone) to copy
#### Example
drone.copy('somethingCool',10,5,10 ).right(12 ).paste('somethingCool' );
### Drone.paste() method
Pastes a copied area to the current location.
#### Example
To copy a 10x5x10 area (using the drone's coordinates as the starting
point) into memory. the copied area can be referenced using the name
'somethingCool'. The drone moves 12 blocks right then pastes the copy.
drone.copy('somethingCool',10,5,10 )
.right(12 )
.paste('somethingCool' );
***/
function paste( name, immediate )
{
var ccContent = Drone.clipBoard[name];
if (ccContent == undefined){
console.warn('Nothing called ' + name + ' in clipboard!');
return;
}
var srcBlocks = ccContent.blocks;
var srcDir = ccContent.dir; // direction player was facing when copied.
var dirOffset = (4 + (this.dir - srcDir ) ) %4;
this.traverseWidth(srcBlocks.length,function( ww ) {
var h = srcBlocks[ww].length;
this.traverseHeight(h,function( hh ) {
var d = srcBlocks[ww][hh].length;
this.traverseDepth(d,function( dd ) {
var b = srcBlocks[ww][hh][dd],
cb = b.type,
md = b.data,
newDir,
dir,
a,
len;
//
// need to adjust blocks which face a direction
//
switch ( cb ) {
//
// doors
//
case 64: // wood
case 71: // iron
// top half of door doesn't need to change
if ( md < 8 ) {
md = (md + dirOffset ) % 4;
}
break;
//
// stairs
//
case 53: // oak
case 67: // cobblestone
case 108: // red brick
case 109: // stone brick
case 114: // nether brick
case 128: // sandstone
case 134: // spruce
case 135: // birch
case 136: // junglewood
dir = md & 0x3;
a = Drone.PLAYER_STAIRS_FACING;
len = a.length;
for ( var c=0;c < len;c++ ) {
if ( a[c] == dir ) {
break;
}
}
c = (c + dirOffset ) %4;
newDir = a[c];
md = (md >>2<<2 ) + newDir;
break;
//
// signs , ladders etc
//
case 23: // dispenser
case 54: // chest
case 61: // furnace
case 62: // burning furnace
case 65: // ladder
case 68: // wall sign
a = Drone.PLAYER_SIGN_FACING;
len = a.length;
for ( var c=0;c < len;c++ ) {
if ( a[c] == md ) {
break;
}
}
c = (c + dirOffset ) %4;
newDir = a[c];
md = newDir;
break;
}
this.setBlock(cb,md);
} );
} );
} );
}
function copy( name, w, h, d ) {
var ccContent = [];
this.traverseWidth(w,function( ww ) {
ccContent.push([] );
this.traverseHeight(h,function( hh ) {
ccContent[ww].push([] );
this.traverseDepth(d,function( dd ) {
var b = this.getBlock();
ccContent[ww][hh][dd] = {type:b.getTypeId(), data:b.data};
} );
} );
} );
Drone.clipBoard[name] = {dir: this.dir, blocks: ccContent};
}
Drone.clipBoard = {};
Drone.extend( copy );
Drone.extend( paste );

View file

@ -0,0 +1,75 @@
'use strict';
/**************************************************************************
### Drone.cylinder() method
A convenience method for building cylinders. Building begins radius blocks to the right and forward.
#### Parameters
* 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`
* radius
* height
#### Example
To create a cylinder of Iron 7 blocks in radius and 1 block high...
cylinder(blocks.iron, 7 , 1);
![cylinder example](img/cylinderex1.png)
### Drone.cylinder0() method
A version of cylinder that hollows out the middle.
#### Example
To create a hollow cylinder of Iron 7 blocks in radius and 1 block high...
cylinder0(blocks.iron, 7, 1);
![cylinder0 example](img/cylinder0ex1.png)
***/
var Drone = require('./drone').Drone;
function cylinder0( block,radius,height,exactParams ) {
var arcParams = {
radius: radius,
fill: false,
orientation: 'horizontal',
stack: height
};
if ( exactParams ) {
for ( var p in exactParams ) {
arcParams[p] = exactParams[p];
}
}else{
var md = this._getBlockIdAndMeta(block );
arcParams.blockType = md[0];
arcParams.meta = md[1];
}
return this.arc(arcParams );
};
function cylinder( block,radius,height,exactParams ) {
var arcParams = {
radius: radius,
fill: true,
orientation: 'horizontal',
stack: height
};
if ( exactParams ) {
arcParams.blockType = exactParams.blockType;
arcParams.meta = exactParams.meta;
}else{
var md = this._getBlockIdAndMeta(block );
arcParams.blockType = md[0];
arcParams.meta = md[1];
}
return this.arc(arcParams );
};
Drone.extend(cylinder0 );
Drone.extend(cylinder );

View file

@ -0,0 +1,96 @@
/*************************************************************************
### Drone.door() method
create a door - if a parameter is supplied an Iron door is created otherwise a wooden door is created.
#### Parameters
* doorType (optional - default wood) - If a parameter is provided then the door is Iron.
#### Example
To create a wooden door at the crosshairs/drone's location...
var drone = new Drone();
drone.door();
To create an iron door...
drone.door( blocks.door_iron );
![iron door](img/doorex1.png)
### Drone.door_iron() method
create an Iron door.
### Drone.door2() method
Create double doors (left and right side)
#### Parameters
* doorType (optional - default wood) - If a parameter is provided then the door is Iron.
#### Example
To create double-doors at the cross-hairs/drone's location...
drone.door2();
![double doors](img/door2ex1.png)
### Drone.door2_iron() method
Create double iron doors
***/
var Drone = require('./drone').Drone;
/*global require*/
function door( doorMaterial, hinge) {
if ( typeof doorMaterial == 'undefined' ) {
doorMaterial = 64; // wood
}
if (typeof hinge == 'undefined') {
hinge = 'left';
}
this.then(function(){
this.setBlock(doorMaterial, this.dir);
this.setBlock(doorMaterial, hinge=='left' ? 8 : 9, 0,1,0);
if ( this.bountiful ){
// 1.8
var prop = require('blockhelper').property;
var lower = this.getBlock();
var upper = this.getBlock();
prop(upper)
.set('half','upper')
.set('hinge',hinge);
prop(lower)
.set('facing',this.dir)
.set('half','lower');
upper.update();
lower.update();
}
});
}
Drone.extend( door );
Drone.extend( function door_iron( ) {
this.door(71);
} );
Drone.extend( function door2( doorMaterial ) {
if ( typeof doorMaterial == 'undefined' ) {
doorMaterial = 64;
}
this
.door( doorMaterial, 'left')
.right()
.door( doorMaterial, 'right')
.left();
} );
Drone.extend( function door2_iron( ) {
this.door2( 71 );
} );

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,46 @@
/************************************************************************
### Drone.garden() method
places random flowers and long grass (similar to the effect of placing bonemeal on grass)
#### Parameters
* width - the width of the garden
* length - how far from the drone the garden extends
#### Example
To create a garden 10 blocks wide by 5 blocks long...
garden(10,5);
![garden example](img/gardenex1.png)
***/
var Drone = require('./drone').Drone;
var blocks = require('blocks');
function garden( width, depth ) {
if ( typeof width == 'undefined' ) {
width = 10;
}
if ( typeof depth == 'undefined' ) {
depth = width;
}
// make sure grass is present first
this
.box( blocks.grass, width, 1, depth )
.up();
// make flowers more common than long grass
var dist = { };
dist[blocks.rose] = 3;
dist[blocks.dandelion] = 3;
dist[blocks.grass_tall] = 2;
dist[blocks.air] = 1;
this
.rand( dist, width, 1, depth, false /* don't overwrite */ )
.down();
}
Drone.extend(garden);

View file

@ -0,0 +1,185 @@
'use strict';
/*global require,__plugin*/
var Drone = require('./drone').Drone,
bkLocation = org.bukkit.Location;
/************************************************************************
### Drone Movement
Drones can move freely in minecraft's 3-D world. You control the
Drone's movement using any of the following methods..
* up()
* down()
* left()
* right()
* fwd()
* back()
* turn()
... Each of these methods takes a single optional parameter
`numBlocks` - the number of blocks to move in the given direction. If
no parameter is given, the default is 1.
To change direction use the `turn()` method which also takes a single
optional parameter (numTurns) - the number of 90 degree turns to
make. Turns are always clock-wise. If the drone is facing north, then
drone.turn() will make the turn face east. If the drone is facing east
then drone.turn(2) will make the drone turn twice so that it is facing
west.
### Drone Positional Info
* getLocation() - Returns a native Java Location object for the drone
### Drone Markers
Markers are useful when your Drone has to do a lot of work. You can
set a check-point and return to the check-point using the move()
method. If your drone is about to undertake a lot of work -
e.g. building a road, skyscraper or forest you should set a
check-point before doing so if you want your drone to return to its
current location.
A 'start' checkpoint is automatically created when the Drone is first created.
Markers are created and returned to using the followng two methods...
* chkpt - Saves the drone's current location so it can be returned to later.
* move - moves the drone to a saved location. Alternatively you can provide a Java Location object or x,y,z and direction parameters.
#### Parameters
* name - the name of the checkpoint to save or return to.
#### Example
drone.chkpt('town-square');
//
// the drone can now go off on a long excursion
//
for ( i = 0; i< 100; i++) {
drone.fwd(12).box(6);
}
//
// return to the point before the excursion
//
drone.move('town-square');
***/
var _movements = [{},{},{},{}];
// east
_movements[0].right = function( drone,n ) { drone.z +=n; return drone;};
_movements[0].left = function( drone,n ) { drone.z -=n; return drone;};
_movements[0].fwd = function( drone,n ) { drone.x +=n; return drone;};
_movements[0].back = function( drone,n ) { drone.x -= n; return drone;};
// south
_movements[1].right = _movements[0].back;
_movements[1].left = _movements[0].fwd;
_movements[1].fwd = _movements[0].right;
_movements[1].back = _movements[0].left;
// west
_movements[2].right = _movements[0].left;
_movements[2].left = _movements[0].right;
_movements[2].fwd = _movements[0].back;
_movements[2].back = _movements[0].fwd;
// north
_movements[3].right = _movements[0].fwd;
_movements[3].left = _movements[0].back;
_movements[3].fwd = _movements[0].left;
_movements[3].back = _movements[0].right;
Drone.prototype._checkpoints = {};
Drone.extend(function chkpt( name ) {
this._checkpoints[ name ] = { x:this.x, y:this.y, z:this.z, dir:this.dir };
});
Drone.extend(function move( ) {
if ( arguments[0].x && arguments[0].y && arguments[0].z) {
this.x = arguments[0].x;
this.y = arguments[0].y;
this.z = arguments[0].z;
this.dir = Drone.getDirFromRotation(arguments[0] );
this.world = arguments[0].world;
} else if ( typeof arguments[0] === 'string' ) {
var coords = this._checkpoints[arguments[0]];
if ( coords ) {
this.x = coords.x;
this.y = coords.y;
this.z = coords.z;
this.dir = coords.dir%4;
}
} else {
// expect x,y,z,dir
switch( arguments.length ) {
case 4:
this.dir = arguments[3];
case 3:
this.z = arguments[2];
case 2:
this.y = arguments[1];
case 1:
this.x = arguments[0];
}
}
});
Drone.extend( function turn( n ) {
if ( typeof n == 'undefined' ) {
n = 1;
}
this.dir += n;
this.dir %=4;
} );
Drone.extend( function right( n ) {
if ( typeof n == 'undefined' ) {
n = 1;
}
_movements[ this.dir ].right( this, n );
});
Drone.extend( function left( n ) {
if ( typeof n == 'undefined') {
n = 1;
}
_movements[ this.dir ].left( this, n );
});
Drone.extend( function fwd( n ) {
if ( typeof n == 'undefined' ) {
n = 1;
}
_movements[ this.dir ].fwd( this, n );
});
Drone.extend( function back( n ) {
if ( typeof n == 'undefined' ) {
n = 1;
}
_movements[ this.dir ].back( this, n );
});
Drone.extend( function up( n ) {
if ( typeof n == 'undefined' ) {
n = 1;
}
this.y+= n;
});
Drone.extend( function down( n ) {
if ( typeof n == 'undefined' ) {
n = 1;
}
this.y-= n;
});
Drone.prototype.getLocation = function( ) {
if (__plugin.canary) {
var cmLocation = Packages.net.canarymod.api.world.position.Location;
return new cmLocation( this.world, this.x, this.y, this.z, 0, 0);
}
if (__plugin.bukkit) {
return new bkLocation( this.world, this.x, this.y, this.z );
}
};

View file

@ -0,0 +1,97 @@
'use strict';
/*global require*/
var Drone = require('./drone').Drone;
/************************************************************************
### Drone.prism() method
Creates a prism. This is useful for roofs on houses.
#### Parameters
* 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`
* width - the width of the prism
* length - the length of the prism (will be 2 time its height)
#### Example
prism(blocks.oak,3,12);
![prism example](img/prismex1.png)
### Drone.prism0() method
A variation on `prism` which hollows out the inside of the prism. It
uses the same parameters as `prism`.
***/
var STAIRBLOCKS = {
53: '5:0' // oak wood
,67: 4 // cobblestone
,108: 45 // brick
,109: 98 // stone brick
,114: 112 // nether brick
,128: 24 // sandstone
,134: '5:1' // spruce wood
,135: '5:2' // birch wood
,136: '5:3' // jungle wood
,156: 155 // quartz
};
//
// prism private implementation
//
function prism( block, w, d ) {
var stairEquiv = STAIRBLOCKS[block];
if ( stairEquiv ) {
this
.fwd()
.prism( stairEquiv,w,d-2 )
.back()
.stairs(block, w, d / 2)
.fwd(d - 1)
.right(w - 1)
.turn(2)
.stairs(block, w, d / 2)
.turn(2)
.left(w - 1)
.back(d - 1);
}else{
var c = 0;
var d2 = d;
while ( d2 >= 1 ) {
this.cuboid(block,w,1,d2 );
d2 -= 2;
this.fwd( ).up( );
c++;
}
this.down(c ).back(c );
}
return this;
};
//
// prism0 private implementation
//
function prism0( block,w,d ) {
this
.stairs(block,w,d/2)
.fwd(d-1)
.right(w-1)
.turn(2)
.stairs(block,w,d/2)
.turn(2)
.left(w-1)
.back(d-1);
var se = STAIRBLOCKS[block];
if (se) {
this
.fwd()
.prism(se,1,d-2)
.right(w-1)
.prism(se,1,d-2)
.left(w-1)
.back();
}
}
Drone.extend(prism0);
Drone.extend(prism);

View file

@ -0,0 +1,66 @@
'use strict';
/*global require*/
/************************************************************************
### Drone.rand() method
rand takes either an array (if each blockid has the same chance of occurring) or an object where each property is a blockid and the value is it's weight (an integer)
#### Example
place random blocks stone, mossy stone and cracked stone (each block has the same chance of being picked)
rand( [blocks.brick.stone, blocks.brick.mossy, blocks.brick.cracked ],w,d,h)
to place random blocks stone has a 50% chance of being picked,
var distribution = {};
distribution[ blocks.brick.stone ] = 5;
distribution[ blocks.brick.mossy ] = 3;
distribution[ blocks.brick.cracked ] = 2;
rand( distribution, width, height, depth)
regular stone has a 50% chance, mossy stone has a 30% chance and cracked stone has just a 20% chance of being picked.
***/
var Drone = require('./drone').Drone;
//
// standard fisher-yates shuffle algorithm
//
function fisherYates( myArray ) {
var i = myArray.length;
if ( i == 0 ) return false;
while ( --i ) {
var j = Math.floor( Math.random( ) * ( i + 1 ) );
var tempi = myArray[i];
var tempj = myArray[j];
myArray[i] = tempj;
myArray[j] = tempi;
}
}
function _rand( blockDistribution ) {
if ( !(blockDistribution.constructor == Array ) ) {
var a = [];
for ( var p in blockDistribution ) {
var n = blockDistribution[p];
for ( var i = 0;i < n;i++ ) {
a.push(p );
}
}
blockDistribution = a;
}
while ( blockDistribution.length < 1000 ) {
// make array bigger so that it's more random
blockDistribution = blockDistribution.concat(blockDistribution );
}
fisherYates(blockDistribution );
return blockDistribution;
}
Drone.extend( function rand( dist, width, height, depth, overwrite ) {
if ( typeof overwrite == 'undefined' ) {
overwrite = true;
}
var randomized = _rand( dist );
this.boxa( randomized, width, height, depth, overwrite);
} );

View file

@ -0,0 +1,102 @@
'use strict';
/*global require, echo,__plugin*/
var Drone = require('./drone').Drone;
/************************************************************************
### Drone.sign() method
Signs must use block 63 (stand-alone signs) or 68 (signs on walls)
#### Parameters
* message - can be a string or an array of strings.
* block - can be 63 or 68
#### Example
To create a free-standing sign...
drone.sign(["Hello","World"],63);
![ground sign](img/signex1.png)
... to create a wall mounted sign...
drone.sign(["Welcome","to","Scriptopia"], 68 );
![wall sign](img/signex2.png)
***/
function putSign( drone, texts, blockId, meta ) {
var i,
block,
state,
getState,
isSign,
setLine;
if ( blockId != 63 && blockId != 68 ) {
throw new Error( 'Invalid Parameter: blockId must be 63 or 68' );
}
drone.setBlock( blockId, meta);
block = drone.getBlock();
if (__plugin.canary){
isSign = function(block){
var sign = block.getTileEntity();
return sign.setTextOnLine;
};
setLine = function( block, i, text) {
var sign = block.getTileEntity();
sign.setTextOnLine( text, i );
sign.update();
};
if ( drone.bountiful ) {
// 1.8
var prop = require('blockhelper').property;
prop(block).set('facing',(drone.dir+2)%4);
block.update();
}
}
if (__plugin.bukkit){
isSign = function(block){ return block.state && block.state.setLine; };
setLine = function( block, i, text) {
var sign = block.state;
sign.setLine( i, text );
sign.update(true);
};
}
if ( isSign(block) ) {
for ( i = 0; i < texts.length; i++ ) {
setLine(block, i % 4, texts[ i ] );
}
}
};
function sign( message, block ) {
if ( message.constructor != Array ) {
message = [message];
}
var bm = this._getBlockIdAndMeta( block );
block = bm[0];
var meta = bm[1];
if ( block != 63 && block != 68 ) {
var usage = 'Usage: sign("message", "63:1") or sign("message","68:1")';
if ( this.player ) {
echo( this.player, usage);
}
console.error(usage);
return;
}
if ( block == 68 ) {
meta = Drone.PLAYER_SIGN_FACING[ this.dir % 4 ];
this.back();
}
if ( block == 63 ) {
meta = ( 12 + ( ( this.dir + 2 ) * 4 ) ) % 16;
}
this.then(function(){
putSign( this, message, block, meta);
if ( block == 68 ) {
this.fwd();
}
});
}
Drone.extend(sign);

View file

@ -0,0 +1,58 @@
/**************************************************************************
### Drone.stairs() function
The stairs() function will build a flight of stairs
#### Parameters
* blockType - should be one of the following:
* blocks.stairs.oak
* blocks.stairs.cobblestone
* blocks.stairs.brick
* blocks.stairs.stone
* blocks.stairs.nether
* blocks.stairs.sandstone
* blocks.stairs.spruce
* blocks.stairs.birch
* blocks.stairs.jungle
* blocks.stairs.quartz
* width - The width of the staircase - default is 1
* height - The height of the staircase - default is 1
#### Example
To build an oak staircase 3 blocks wide and 5 blocks tall:
/js stairs(blocks.stairs.oak, 3, 5)
Staircases do not have any blocks beneath them.
***/
var Drone = require('./drone').Drone;
/*global require*/
function stairs(blockType, width, height){
if (typeof width === 'undefined')
width = 1;
if (typeof height === 'undefined')
height = 1;
this.chkpt('_stairs');
while (height > 0) {
this.traverseWidth(width, function(){
this.setBlock(blockType, Drone.PLAYER_STAIRS_FACING[this.dir]);
if ( this.bountiful ){
// 1.8
var prop = require('blockhelper').property;
var block = this.getBlock();
prop(block).set('facing',that.dir);
block.update();
}
});
this.fwd().up();
height -= 1;
}
this.move('_stairs');
}
Drone.extend(stairs);

View file

@ -0,0 +1,58 @@
'use strict';
/*global require,__plugin*/
/************************************************************************
### Drone Trees methods
* oak()
* spruce()
* birch()
* jungle()
#### Example
To create 4 trees in a row, point the cross-hairs at the ground then type `/js ` and ...
up( ).oak( ).right(8 ).spruce( ).right(8 ).birch( ).right(8 ).jungle( );
Trees won't always generate unless the conditions are right. You
should use the tree methods when the drone is directly above the
ground. Trees will usually grow if the drone's current location is
occupied by Air and is directly above an area of grass (That is why
the `up()` method is called first).
![tree example](img/treeex1.png)
None of the tree methods require parameters. Tree methods will only be
successful if the tree is placed on grass in a setting where trees can
grow.
***/
var Drone = require('./drone').Drone;
var bkTreeType = org.bukkit.TreeType;
var _trees = {
oak: bkTreeType.BIG_TREE ,
birch: bkTreeType.BIRCH ,
jungle: bkTreeType.JUNGLE,
spruce: bkTreeType.REDWOOD
};
function bukkitTreeFactory( k, v ) {
return function( ) {
var block = this.getBlock();
if ( block.typeId == 2 ) {
this.up( );
}
var treeLoc = this.getLocation();
var successful = treeLoc.world.generateTree(treeLoc,v );
if ( block.typeId == 2 ) {
this.down( );
}
};
}
function canaryTreeFactory( k, v ){
return function(){
console.log(k + ' not yet implemented.');
};
}
for ( var p in _trees ) {
Drone.extend(p, (__plugin.canary? canaryTreeFactory : bukkitTreeFactory) ( p, _trees[p] ) );
}