Hacked scriptcraft 3.2.0 drone javascript. A lot of building functions now implemented.

master
Dennis Payne 2016-10-29 08:34:55 -04:00
parent 58345c8292
commit 6bc6712dfd
25 changed files with 3616 additions and 295 deletions

246
drone.c
View File

@ -1,246 +0,0 @@
#include "scriptmine.h"
duk_ret_t drone_box(duk_context *ctx)
{
duk_push_this(ctx); // [b w h d this]
duk_get_prop_string(ctx, -1, "x");
int x = duk_to_int(ctx, -1);
duk_remove(ctx, -1);
duk_get_prop_string(ctx, -1, "y");
int y = duk_to_int(ctx, -1);
duk_remove(ctx, -1);
duk_get_prop_string(ctx, -1, "z");
int z = duk_to_int(ctx, -1);
duk_remove(ctx, -1);
duk_get_prop_string(ctx, -1, "facing");
int facing = duk_to_int(ctx, -1);
duk_remove(ctx, -1);
const char *blockID = duk_to_string(ctx, -5);
int w = duk_to_int(ctx, -4);
int h = duk_to_int(ctx, -3);
int d = duk_to_int(ctx, -2);
if (w < 1)
w = 1;
if (h < 1)
h = 1;
if (d < 1)
d = 1;
const char *nodeName = blockID_to_node_name(blockID);
lua_getfield(Lg, LUA_GLOBALSINDEX, "minetest"); // [minetest]
lua_getfield(Lg, -1, "set_node"); // [minetest new_node]
lua_remove(Lg, -2); // [set_node]
for (int changeW = 0; changeW < w; changeW++)
{
for (int changeH = 0; changeH < h; changeH++)
{
for (int changeD = 0; changeD < d; changeD++)
{
lua_pushvalue(Lg, -1); // [set_node set_node]
lua_newtable(Lg);
int fx = x;
int fz = z;
switch (facing)
{
case 0:
fx -= changeD;
fz += changeW;
break;
case 1:
fz += changeD;
fx += changeW;
break;
case 2:
fx += changeD;
fz -= changeW;
break;
case 3:
fz -= changeD;
fx -= changeW;
break;
};
lua_pushnumber(Lg, fx);
lua_setfield(Lg, -2, "x");
lua_pushnumber(Lg, y + changeH);
lua_setfield(Lg, -2, "y");
lua_pushnumber(Lg, fz);
lua_setfield(Lg, -2, "z");
lua_newtable(Lg);
lua_pushstring(Lg, nodeName);
lua_setfield(Lg, -2, "name");
lua_call(Lg, 2, 0);
}
}
}
lua_remove(Lg, -1);
return 0;
}
duk_ret_t drone_box0(duk_context *ctx)
{
duk_push_this(ctx); // [b w h d this]
duk_get_prop_string(ctx, -1, "x");
int x = duk_to_int(ctx, -1);
duk_remove(ctx, -1);
duk_get_prop_string(ctx, -1, "y");
int y = duk_to_int(ctx, -1);
duk_remove(ctx, -1);
duk_get_prop_string(ctx, -1, "z");
int z = duk_to_int(ctx, -1);
duk_remove(ctx, -1);
duk_get_prop_string(ctx, -1, "facing");
int facing = duk_to_int(ctx, -1);
duk_remove(ctx, -1);
const char *blockID = duk_to_string(ctx, -5);
int w = duk_to_int(ctx, -4);
int h = duk_to_int(ctx, -3);
int d = duk_to_int(ctx, -2);
if (w < 1)
w = 1;
if (h < 1)
h = 1;
if (d < 1)
d = 1;
const char *nodeName = blockID_to_node_name(blockID);
lua_getfield(Lg, LUA_GLOBALSINDEX, "minetest"); // [minetest]
lua_getfield(Lg, -1, "set_node"); // [minetest new_node]
lua_remove(Lg, -2); // [set_node]
for (int changeW = 0; changeW < w; changeW++)
{
for (int changeH = 0; changeH < h; changeH++)
{
for (int changeD = 0; changeD < d; changeD++)
{
if ((changeW != 0) && (changeW != w - 1) && (changeD != 0) && (changeD != d - 1))
continue;
lua_pushvalue(Lg, -1); // [set_node set_node]
lua_newtable(Lg);
int fx = x;
int fz = z;
switch (facing)
{
case 0:
fx -= changeD;
fz += changeW;
break;
case 1:
fz += changeD;
fx += changeW;
break;
case 2:
fx += changeD;
fz -= changeW;
break;
case 3:
fz -= changeD;
fx -= changeW;
break;
};
lua_pushnumber(Lg, fx);
lua_setfield(Lg, -2, "x");
lua_pushnumber(Lg, y + changeH);
lua_setfield(Lg, -2, "y");
lua_pushnumber(Lg, fz);
lua_setfield(Lg, -2, "z");
lua_newtable(Lg);
lua_pushstring(Lg, nodeName);
lua_setfield(Lg, -2, "name");
lua_call(Lg, 2, 0);
}
}
}
lua_remove(Lg, -1);
return 0;
}
duk_ret_t drone_constructor(duk_context *ctx)
{
if (!duk_is_constructor_call(ctx))
{
return DUK_RET_TYPE_ERROR;
}
lua_getfield(Lg, LUA_GLOBALSINDEX, "minetest"); // [minetest]
lua_getfield(Lg, -1, "get_player_by_name"); // [minetest get_player_by_name]
lua_remove(Lg, -2); // [get_player_by_name]
lua_pushstring(Lg, name); // [get_player_by_name name]
lua_call(Lg, 1, 1); // [player]
lua_getmetatable(Lg, -1); // [player metatable]
lua_pushstring(Lg, "__index"); // [player metatable __index]
lua_rawget(Lg, -2); // [player metatable __index]
lua_pushstring(Lg, "getpos"); // [player metatable __index getpos]
lua_rawget(Lg, -2); // [player metatable __index getpos]
lua_pushvalue(Lg, -4); // [player metatable __index getpos player]
lua_call(Lg, 1, 1); // [player metatable __index postable]
lua_getfield(Lg, -1, "x");
int x = lua_tointeger(Lg, -1);
lua_remove(Lg, -1);
lua_getfield(Lg, -1, "y");
int y = lua_tointeger(Lg, -1);
lua_remove(Lg, -1);
lua_getfield(Lg, -1, "z");
int z = lua_tointeger(Lg, -1);
lua_remove(Lg, -1);
lua_remove(Lg, -1); // [player metatable __index]
lua_pushstring(Lg, "get_look_dir");
lua_rawget(Lg, -2); // [player metatable __index get_look_dir]
lua_pushvalue(Lg, -4); // [player metatable __index get_look_dir player]
lua_call(Lg, 1, 1); // [player metatable __index postable]
lua_getfield(Lg, -1, "x");
double xv = lua_tonumber(Lg, -1);
lua_remove(Lg, -1);
lua_getfield(Lg, -1, "z");
double zv = lua_tonumber(Lg, -1);
lua_remove(Lg, -1);
lua_remove(Lg, -1); // [player metatable __index]
lua_remove(Lg, -1); // [player metatable]
lua_remove(Lg, -1); // [player]
lua_remove(Lg, -1);
int facing = 0;
if (fabs(xv) > fabs(zv))
{
if (xv > 0)
{
facing = 2;
x += 2;
}
else
x -= 2;
}
else
{
if (zv > 0)
{
facing = 1;
z += 2;
}
else
{
facing = 3;
z -= 2;
}
}
y += 1;
duk_push_this(ctx);
duk_push_number(ctx, x);
duk_put_prop_string(ctx, -2, "x");
duk_push_number(ctx, y);
duk_put_prop_string(ctx, -2, "y");
duk_push_number(ctx, z);
duk_put_prop_string(ctx, -2, "z");
duk_push_number(ctx, facing);
duk_put_prop_string(ctx, -2, "facing");
return 0; /* use default instance */
}
void drone_init(duk_context *ctx)
{
duk_push_c_function(ctx, drone_constructor, 0);
duk_push_object(ctx);
duk_push_c_function(ctx, drone_box, 4);
duk_put_prop_string(ctx, -2, "box");
duk_push_c_function(ctx, drone_box0, 4);
duk_put_prop_string(ctx, -2, "box0");
duk_put_prop_string(ctx, -2, "prototype");
duk_put_global_string(ctx, "Drone");
}

View File

@ -1,42 +0,0 @@
Duktape.modSearch = function (id)
{
var res;
print('loading module:', id);
res = readFile(id);
if (typeof res === 'string')
{
return res;
}
throw new Error('module not found: ' + id);
}
function box()
{
var d = new Drone();
if (arguments.length >= 4)
d.box(arguments[0], arguments[1], arguments[2], arguments[3]);
else if (arguments.length == 3)
d.box(arguments[0], arguments[1], arguments[2]);
else if (arguments.length == 2)
d.box(arguments[0], arguments[1]);
else if (arguments.length == 1)
d.box(arguments[0]);
return d;
}
function box0()
{
var d = new Drone();
if (arguments.length >= 4)
d.box0(arguments[0], arguments[1], arguments[2], arguments[3]);
else if (arguments.length == 3)
d.box0(arguments[0], arguments[1], arguments[2]);
else if (arguments.length == 2)
d.box0(arguments[0], arguments[1]);
else if (arguments.length == 1)
d.box0(arguments[0]);
return d;
}

19
js/block-colors.js Normal file
View File

@ -0,0 +1,19 @@
var colors = {
white: 0,
orange: 1,
magenta: 2,
lightblue: 3,
yellow: 4,
lime: 5,
pink: 6,
gray: 7,
lightgray: 8,
cyan: 9,
purple: 10,
blue: 11,
brown: 12,
green: 13,
red: 14,
black: 15
};
module.exports = colors;

336
js/blocks.js Normal file
View File

@ -0,0 +1,336 @@
/************************************************************************
## Blocks Module
You hate having to lookup [Data Values][dv] when you use ScriptCraft's
Drone() functions. So do I. So I created this blocks object which is
a helper object for use in construction.
### Examples
box( blocks.oak ); // creates a single oak wood block
box( blocks.sand, 3, 2, 1 ); // creates a block of sand 3 wide x 2 high x 1 long
box( blocks.wool.green, 2 ); // creates a block of green wool 2 blocks wide
Color aliased properties that were a direct descendant of the blocks
object are no longer used to avoid confusion with carpet and stained
clay blocks. In addition, there's a convenience array `blocks.rainbow`
which is an array of the 7 colors of the rainbow (or closest
approximations).
The blocks module is globally exported by the Drone module.
***/
var colors = require('./block-colors');
var blocks = {
air: 0,
stone: 1,
grass: 2,
dirt: 3,
cobblestone: 4,
oak: 5, spruce: '5:1', birch: '5:2', jungle: '5:3',
sapling: { oak: 6, spruce: '6:1', birch: '6:2', jungle: '6:3' },
bedrock: 7,
water: 8,
water_still: 9,
lava: 10,
lava_still: 11,
sand: 12,
gravel: 13,
gold_ore: 14,
iron_ore: 15,
coal_ore: 16,
wood: 17,
leaves: 18,
sponge: 19,
glass: 20,
lapis_lazuli_ore: 21,
lapis_lazuli_block: 22,
dispenser: 23,
sandstone: 24,
note: 25,
bed: 26,
powered_rail: 27,
detector_rail: 28,
sticky_piston: 29,
cobweb: 30,
grass_tall: 31,
dead_bush: 32,
piston: 33,
piston_extn: 34, piston_head: 34,
wool: { white: 35 /* All other colors added below */ },
piston_extended: 36,
dandelion: 37, flower_yellow: 37,
rose: 38, flower_red: 38,
mushroom_brown: 39,
mushroom_red: 40,
gold: 41,
iron: 42,
//http://minecraft.gamepedia.com/Data_values#Double_Stone_Slabs
double_slab: {
stone: 43,
sandstone: '43:1',
wooden: '43:2',
cobblestone: '43:3',
brick: '43:4',
stonebrick: '43:5',
netherbrick:'43:6',
quartz: '43:7',
smooth_stone: '43:8',
smooth_sandstone: '43:9',
tile_quartz: '43:15'
},
slab: {
sandstone: '44:1',
wooden: '44:2',
cobblestone: '44:3',
brick: '44:4',
stonebrick: '44:5',
netherbrick:'44:6',
quartz: '44:7',
upper: {
stone: '44:8',
sandstone: '44:9',
wooden: '44:10',
cobblestone: '44:11',
brick: '44:12',
stonebrick: '44:13',
netherbrick:'44:14',
quartz: '44:15',
oak: '126:8',
spruce: '126:9',
birch: '126:10',
jungle: '126:11'
},
snow: 78,
stone: 44,
oak: 126,
spruce: '126:1',
birch: '126:2',
jungle: '126:3'
},
// see brick.red 45
tnt: 46,
bookshelf: 47,
moss_stone: 48,
obsidian: 49,
torch: 50,
fire: 51,
monster_spawner: 52,
stairs: {
oak: 53,
cobblestone: 67,
brick: 108,
stone: 109,
nether: 114,
sandstone: 128,
spruce: 134,
birch: 135,
jungle: 136,
quartz: 156
},
chest: 54,
redstone_wire: 55,
diamond_ore: 56,
diamond: 57,
crafting_table: 58,
wheat_seeds: 59,
farmland: 60,
furnace: 61,
furnace_burning: 62,
sign_post: 63,
door_wood: 64,
ladder: 65,
rail: 66,
sign: 68,
lever: 69,
pressure_plate_stone: 70,
door_iron: 71,
pressure_plate_wood: 72,
redstone_ore: 73,
redstone_ore_glowing: 74,
torch_redstone: 75,
torch_redstone_active: 76,
stone_button: 77,
ice: 79,
snow: 80,
cactus: 81,
clay: 82,
sugar_cane: 83,
jukebox: 84,
fence: 85,
pumpkin: 86,
netherrack: 87,
soulsand: 88,
glowstone: 89,
netherportal: 90,
jackolantern: 91,
cake: 92,
redstone_repeater: 93,
redeston_repeater_active: 94,
stained_glass: {
white: 95 // all other colors added below
},
trapdoor: 96,
monster_egg: 97,
brick: {
stone: 98,
mossy: '98:1',
cracked: '98:2',
chiseled: '98:3',
red: 45
},
mushroom_brown_huge: 99,
mushroom_red_huge: 100,
iron_bars: 101,
glass_pane: 102,
melon: 103,
pumpkin_stem: 104,
melon_stem: 105,
vines: 106,
fence_gate: 107,
mycelium: 110,
lily_pad: 111,
nether: 112,
nether_fence: 113,
netherwart: 115,
table_enchantment: 116,
brewing_stand: 117,
cauldron: 118,
endportal: 119,
endportal_frame: 120,
endstone: 121,
dragon_egg: 122,
redstone_lamp: 123,
redstone_lamp_active: 124,
cocoa: 127,
emerald_ore: 129,
enderchest: 130,
tripwire_hook: 131,
tripwire: 132,
emerald: 133,
command: 137,
beacon: 138,
cobblestone_wall: 139,
flowerpot: 140,
carrots: 141,
potatoes: 142,
button_wood: 143,
skull: 144, mobhead: 144,
anvil: 145,
chest_trapped: 146,
pressure_plate_weighted_light: 147,
pressure_plate_weighted_heavy: 148,
redstone_comparator: 149,
redstone_comparator_active: 150,
daylight_sensor: 151,
redstone: 152,
quartzore: 153, netherquartzore: 153,
hopper: 154,
quartz: 155,
quartz_chiseled: '155:1',
quartz_pillar_vertical: '155:2',
quartz_pillar_horizontal: '155:3',
quartz_pillar_cap: '155:4',
// see stairs.quartz
rail_activator: 157,
dropper: 158,
stained_clay: {
white: 159 // All other colors added below
},
stained_glass_pane: {
white: 160 // all other colors added below
},
slime: 165,
barrier: 166,
trapdoor_iron: 167,
prismarine: 168,
prismarine_brick: '168:1',
prismarine_dark: '168:2',
sealantern: 169,
hay: 170,
carpet: {
white: 171 // All other colors added below
},
hardened_clay: 172,
coal_block: 173,
packed_ice: 174,
double_plant: 175,
sunflower: 175,
flower: {
sunflower: 175,
lilac: '175:1',
tallgrass: '175:2',
fern: '175:3',
rosebush: '175:4',
peony: '175:5',
yellow: 37,
dandelion: 37,
rose: 38,
red: 38
},
bonemeal: '351:15',
banner: {
standing: 176,
wallmounted: 177
},
daylight_sensor_inverted: 178,
gate: {
spruce: 183,
birch: 184,
jungle: 185,
oak: 186,
acacia: 187
},
fence: {
spruce: 188,
birch: 189,
jungle: 190,
oak: 191,
acacia: 192
}
};
// Add all available colors to colorized block collections
var colorized_blocks = [
'wool',
'stained_clay',
'carpet',
'stained_glass',
'stained_glass_pane'
];
for (var i = 0, len = colorized_blocks.length; i < len; i++) {
var block = colorized_blocks[i],
data_value = blocks[block].white;
for (var color in colors) {
blocks[block][color] = data_value + ':' + colors[color];
}
};
/*
rainbow colors - a convenience
Color aliased properties that were a direct descendant of the blocks
object are no longer used to avoid confusion with carpet and stained
clay blocks.
*/
blocks.rainbow = [
blocks.stained_glass.red,
blocks.stained_glass.orange,
blocks.stained_glass.yellow,
blocks.stained_glass.lime,
blocks.stained_glass.lightblue,
blocks.stained_glass.blue,
blocks.stained_glass.purple
];
blocks.isStair = function(id){
var p;
for (p in this.stairs){
if (this.stairs[p] == id)
return true;
}
return false;
};
module.exports = blocks;

267
js/drone/arc.js Normal file
View File

@ -0,0 +1,267 @@
/*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
***/
/*
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' );
};
module.exports = function(Drone){
Drone.extend(function arc( params ) {
params.drone = this;
arcImpl( params );
});
};

55
js/drone/bed.js Normal file
View File

@ -0,0 +1,55 @@
'use strict';
/*global require, Packages, __plugin, module*/
var blocks = require('blocks');
/************************************************************************
### Drone.bed() method
Creates a bed. The foot of the bed will be at the drone's location and
the head of the bed will extend away from the drone.
#### Example
To create a bed at the in-game prompt, look at a block then type:
```javascript
/js bed()
```
Like most Drone methods, this returns the drone so it can be chained like so:
```javascript
this
.fwd(3)
.bed()
.back(3)
```
***/
var bedDirections = {
0:3, // east
1:0, // south
2:1, // west
3:2 // north
};
module.exports = function(Drone){
Drone.extend( function bed(){
this.then(function(){
var foot = this.setBlock(blocks.bed, bedDirections[this.dir], 0,0,0, false);
var head = this.setBlock(blocks.bed, bedDirections[this.dir] + 8, 0,0,1, false);
if (Drone.bountiful){
var prop = require('blockhelper').property;
var BedHalf = Packages.net.canarymod.api.world.blocks.properties.helpers.BedProperties.Half;
prop(foot)
.set('facing',this.dir)
.set('part', BedHalf.FOOT);
prop(head)
.set('facing',this.dir)
.set('part', BedHalf.HEAD);
}
if (__plugin.canary){
foot.update();
head.update();
}
});
});
};

412
js/drone/blocktype.js Normal file
View File

@ -0,0 +1,412 @@
var blocks = require('blocks');
/************************************************************************
### Drone.blocktype() method
Creates the text out of blocks. Useful for large-scale in-game signs.
#### Parameters
* message - The message to create - (use `\n` for newlines)
* foregroundBlock (default: black wool) - The block to use for the foreground
* backgroundBlock (default: none) - The block to use for the background
#### Example
To create a 2-line high message using glowstone...
blocktype('Hello\nWorld', blocks.glowstone);
![blocktype example][imgbt1]
[imgbt1]: img/blocktype1.png
***/
var bitmaps = {
raw: {
'0':' ### '+
' # # '+
' # # '+
' # # '+
' ### ',
'1':' # '+
' ## '+
' # '+
' # '+
' ### ',
'2':' ### '+
' # '+
' ### '+
' # '+
' ### ',
'3':' ### '+
' # '+
' ## '+
' # '+
' ### ',
'4':' # '+
' ## '+
' # # '+
' ### '+
' # ',
'5':' ### '+
' # '+
' ### '+
' # '+
' ### ',
'6':' ### '+
' # '+
' ### '+
' # # '+
' ### ',
'7':' ### '+
' # '+
' # '+
' # '+
' # ',
'8':' ### '+
' # # '+
' ### '+
' # # '+
' ### ',
'9':' ### '+
' # # '+
' ### '+
' # '+
' ### ',
'a':' ### '+
' # # '+
' ### '+
' # # '+
' # # ',
'b':' ## '+
' # # '+
' ## '+
' # # '+
' ## ',
'c':' ## '+
' # '+
' # '+
' # '+
' ## ',
'd':' ## '+
' # # '+
' # # '+
' # # '+
' ## ',
'e':' ### '+
' # '+
' ## '+
' # '+
' ### ',
'f':' ### '+
' # '+
' ## '+
' # '+
' # ',
'g':' ### '+
' # '+
' # '+
' # # '+
' ### ',
'h':' # # '+
' # # '+
' ### '+
' # # '+
' # # ',
'i':' ### '+
' # '+
' # '+
' # '+
' ### ',
'j':' ### '+
' # '+
' # '+
' # '+
' # ',
'k':' # '+
' # # '+
' ## '+
' # # '+
' # # ',
'l':' # '+
' # '+
' # '+
' # '+
' ### ',
'm':' # # '+
' ### '+
' # # '+
' # # '+
' # # ',
'n':' ## '+
' # # '+
' # # '+
' # # '+
' # # ',
'o':' # '+
' # # '+
' # # '+
' # # '+
' # ',
'p':' ### '+
' # # '+
' ### '+
' # '+
' # ',
'q':' ### '+
' # # '+
' # # '+
' ### '+
' # ',
'r':' ## '+
' # # '+
' ## '+
' # # '+
' # # ',
's':' ## '+
' # '+
' ### '+
' # '+
' ## ',
't':' ### '+
' # '+
' # '+
' # '+
' # ',
'u':' # # '+
' # # '+
' # # '+
' # # '+
' ### ',
'v':' # # '+
' # # '+
' # # '+
' # # '+
' # ',
'w':' # # '+
' # # '+
' # # '+
' ### '+
' # # ',
'x':' # # '+
' # # '+
' # '+
' # # '+
' # # ',
'y':' # # '+
' # # '+
' # # '+
' # '+
' # ',
'z':' ### '+
' # '+
' # '+
' # '+
' ### ',
'!':' # '+
' # '+
' # '+
' '+
' # ',
':':' '+
' # '+
' '+
' # '+
' ',
';':' '+
' # '+
' '+
' # '+
' # ',
',':' '+
' '+
' '+
' # '+
' # ',
'/':' # '+
' # '+
' # '+
' # '+
' # ',
'+':' '+
' # '+
' ### '+
' # '+
' ',
'-':' '+
' '+
' ### '+
' '+
' ',
'.':' '+
' '+
' '+
' '+
' # ',
"'":' # '+
' # '+
' '+
' '+
' ',
'(': ' # '+
' # '+
' # '+
' # '+
' # ',
')': ' # '+
' # '+
' # '+
' # '+
' # ',
' ':' '+
' '+
' '+
' '+
' '
},
computed: {}
};
/*
wph 20130121 compute the width, and x,y coords of pixels ahead of time
*/
var c,
bits,
width,
bmInfo,
j;
for ( c in bitmaps.raw ) {
bits = bitmaps.raw[c];
width = bits.length/5;
bmInfo = { width: width, pixels:[] };
bitmaps.computed[c] = bmInfo;
for ( j = 0; j < bits.length; j++ ) {
if ( bits.charAt(j) != ' ' ) {
bmInfo.pixels.push( [
j % width,
Math.ceil( j / width )
] );
}
}
}
function blocktype( message, fg, bg, immediate ) {
var bmfg,
bmbg,
lines,
lineCount,
h,
line,
i,
x,
y,
ch,
bits,
charWidth,
j;
this.chkpt('blocktext');
if ( typeof fg == 'undefined' ) {
fg = blocks.wool.black;
}
bmfg = this.getBlockIdAndMeta( fg );
bmbg = null;
if ( typeof bg != 'undefined' ) {
bmbg = this.getBlockIdAndMeta( bg );
}
lines = (''+ message).split( '\n' );
lineCount = lines.length;
for ( h = 0; h < lineCount; h++) {
line = lines[h];
line = line.toLowerCase().replace( /[^0-9a-z \.\-\+\/\;\'\:\!]/g, '' );
this.up( 7 * ( lineCount - ( h + 1 ) ) );
for ( i =0; i < line.length; i++) {
ch = line.charAt( i );
bits = bitmaps.computed[ ch ];
if ( typeof bits == 'undefined' ) {
bits = bitmaps.computed[' '];
}
charWidth = bits.width;
if ( typeof bg != 'undefined' ) {
this.cuboidX( bmbg[0], bmbg[1], charWidth, 7, 1 , immediate);
}
for ( j = 0; j < bits.pixels.length; j++ ) {
this.chkpt( 'btbl' );
x = bits.pixels[ j ][ 0 ];
y = bits.pixels[ j ][ 1] ;
this.up( 6 - y ).right( x ).cuboidX( bmfg[ 0 ], bmfg[ 1 ], 1, 1, 1, immediate);
this.move( 'btbl' );
}
this.right( charWidth - 1 );
}
this.move( 'blocktext' );
}
return this.move( 'blocktext' );
}
module.exports = function(Drone){
Drone.extend(blocktype);
};

159
js/drone/copypaste.js Normal file
View File

@ -0,0 +1,159 @@
'use strict';
/*global require, module*/
/************************************************************************
### Copy & Paste using Drone
A drone can be used to copy and paste areas of the game world.
#### Deprecated
As of January 10 2015 the copy-paste functions in Drone are no longer
supported. Copy/Paste is:
1. Difficult to do correctly in a way which works for both Minecraft 1.7 and 1.8
due to how blocks changed in 1.8
2. Not aligned with the purpose of ScriptCraft's Drone module which is to provide
a simple set of functions for scripting and in-game building.
### 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' );
***/
var clipBoard = {};
function paste( name, immediate ){
console.warn('Drone copy/paste is no longer in active development');
var Drone = this.constructor;
var ccContent = 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,
c,
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 ( 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 ( 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 ) {
console.warn('Drone copy/paste is no longer in active development');
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};
} );
} );
} );
clipBoard[name] = {dir: this.dir, blocks: ccContent};
}
module.exports = function(Drone){
Drone.extend( copy );
Drone.extend( paste );
};

76
js/drone/cylinders.js Normal file
View File

@ -0,0 +1,76 @@
'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)
***/
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 );
};
module.exports = function(Drone){
Drone.extend(cylinder0 );
Drone.extend(cylinder );
};

101
js/drone/doors.js Normal file
View File

@ -0,0 +1,101 @@
/*global module*/
'use strict';
/*************************************************************************
### 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(self);
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 blocks = require('blocks');
/*global require, Packages, __plugin*/
function door( doorMaterial, hinge) {
if ( typeof doorMaterial == 'undefined' ) {
doorMaterial = blocks.door_wood; // wood
}
if (typeof hinge == 'undefined') {
hinge = 'left';
}
var Drone = this.constructor;
this.then(function(){
var lower = this.setBlock(doorMaterial, this.dir, 0, 0, 0, false);
var upper = this.setBlock(doorMaterial, hinge=='left' ? 8 : 9, 0,1,0, false);
if (Drone.bountiful){
var DoorHalf = Packages.net.minecraft.block.BlockDoor.EnumDoorHalf,
HingePosition = Packages.net.minecraft.block.BlockDoor.EnumHingePosition,
prop = require('blockhelper').property;
prop(lower)
.set('facing', this.dir)
.set('half', DoorHalf.LOWER );
prop(upper)
.set('hinge', hinge == 'left' ? HingePosition.LEFT: HingePosition.RIGHT)
.set('half', DoorHalf.UPPER);
}
if (__plugin.canary){
lower.update();
upper.update();
}
});
}
module.exports = function(Drone){
Drone.extend( door );
Drone.extend( function door_iron( ) {
this.door(blocks.door_iron);
} );
Drone.extend( function door2( doorMaterial ) {
if ( typeof doorMaterial == 'undefined' ) {
doorMaterial = blocks.door_wood;
}
this
.door( doorMaterial, 'left')
.right()
.door( doorMaterial, 'right')
.left();
} );
Drone.extend( function door2_iron( ) {
this.door2( blocks.door_iron );
} );
};

21
js/drone/firework.js Normal file
View File

@ -0,0 +1,21 @@
'use strict';
/*global module, require*/
var fireworks = require('fireworks');
/*************************************************************************
### Drone.firework() method
Launches a firework at the drone's location.
#### Example
To launch a firework:
var drone = new Drone(self);
drone.firework();
***/
module.exports = function(Drone){
Drone.extend( function firework( ) {
fireworks.firework( this.getLocation() );
});
};

49
js/drone/garden.js Normal file
View File

@ -0,0 +1,49 @@
/*global module, require*/
'use strict';
/************************************************************************
### 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 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();
}
module.exports = function(Drone){
Drone.extend(garden);
};

897
js/drone/index.js Normal file
View File

@ -0,0 +1,897 @@
'use strict';
/*global __plugin, require, org, setTimeout, addUnloadHandler, global, Packages, server, module*/
var //utils = require('utils'),
blocks = require('blocks'),
THOUSAND = 1000,
MILLION = THOUSAND * THOUSAND;
/*********************************************************************
## Drone Plugin
The Drone is a convenience class for building.
It uses a fluent interface which means all of the Drone's methods return `this` and can be chained together like so...
var theDrone = new Drone(self);
theDrone.up().left().box(blocks.oak).down().fwd(3).cylinder0(blocks.lava,8);
### Constructing a Drone Object
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 )
... creates a 1x1x1 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 ...
var d = new Drone(self).box( blocks.oak )
... All of the Drone's methods return `this` so you can chain operations together like this...
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...
d = new Drone(self)
...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...
Plan View:
^
|
|
D---->
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...
d = new Drone(self).up();
... 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);
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.
4. Create a new Drone based on a Location object...
d = new Drone(location);
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...
events.blockBreak( function( event ) {
var location = event.block.location;
var drone = new Drone(location);
// do more stuff with the drone here...
});
#### Parameters
* 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.
### Drone.box() method
the box() method is a convenience method for building things. (For the more performance-oriented method - see cuboid)
#### parameters
* 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`
* w (optional - default 1) - the width of the structure
* h (optional - default 1) - the height of the structure
* 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.
#### Example
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...
var drone = new Drone(self);
drone.box(blocks.wool.black, 4, 9, 1);
![box example 1](img/boxex1.png)
### Drone.box0() method
Another convenience method - this one creates 4 walls with no floor or ceiling.
#### 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 (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.
#### Example
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)
### Drone.boxa() method
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.
#### Parameters
* blocks - An array of blocks - each block in the array will be placed in turn.
* width
* height
* length
#### Example
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)
### Chaining
All of the Drone methods return a Drone object, which means methods can be 'chained' together so instead of writing this...
drone = new Drone( self );
drone.fwd( 3 );
drone.left( 2 );
drone.box( blocks.grass ); // create a grass block
drone.up();
drone.box( blocks.grass ); // create another grass block
drone.down();
...you could simply write ...
var drone = new Drone(self).fwd(3).left(2).box(blocks.grass).up().box(blocks.grass).down();
... since each Drone method is also a global function that constructs a drone if none is supplied, you can shorten even further to just...
fwd(3).left(2).box(blocks.grass).up().box(blocks.grass).down()
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()
[fl]: http://en.wikipedia.org/wiki/Fluent_interface
### Drone Properties
* 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.
### Extending Drone
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`.
### Drone.extend() static method
Use this method to add new methods (which also become chainable global functions) to the Drone object.
#### Parameters
* name - The name of the new method e.g. 'pyramid'.
* function - The method body.
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
// submitted by [edonaldson][edonaldson]
var Drone = require('drone');
Drone.extend('pyramid', function( block,height) {
this.chkpt('pyramid');
for ( var i = height; i > 0; i -= 2) {
this.box(block, i, 1, i).up().right().fwd();
}
return this.move('pyramid');
});
#### Example 2 Using just a named function as a parameter
var Drone = require('drone');
function pyramid( block,height) {
this.chkpt('pyramid');
for ( var i = height; i > 0; i -= 2) {
this.box(block, i, 1, i).up().right().fwd();
}
return this.move('pyramid');
}
Drone.extend( pyramid );
Once the method is defined (it can be defined in a new pyramid.js file) it can be used like so...
var d = new Drone(self);
d.pyramid(blocks.brick.stone, 12);
... or simply ...
pyramid(blocks.brick.stone, 12);
[edonaldson]: https://github.com/edonaldson
### Drone Constants
#### Drone.PLAYER_STAIRS_FACING
An array which can be used when constructing stairs facing in the Drone's direction...
var d = new Drone(self);
d.box(blocks.stairs.oak + ':' + Drone.PLAYER_STAIRS_FACING[d.dir]);
... will construct a single oak stair block facing the drone.
#### Drone.PLAYER_SIGN_FACING
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...
* chest
* ladder
* furnace
* dispenser
By default, chests, dispensers, signs, ladders and furnaces are placed facing towards the drone so to place a chest facing the Drone just use:
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]);
#### Drone.PLAYER_TORCH_FACING
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:
drone.box( blocks.torch + ':' + Drone.PLAYER_TORCH_FACING[drone.dir]);
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]);
***/
//
// Implementation
// ==============
//
// There is no need to read any further unless you want to understand how the Drone object works.
//
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
}
/*
low-level function to place a block in the world - all drone methods which
place blocks ultimately invoke this function.
*/
function putBlock( x, y, z, blockId, metadata, world, update ) {
if ( typeof metadata == 'undefined' ) {
metadata = 0;
}
set_node(x, y, z, blockId);
return undefined;
}
/*
Drone constructs a new Drone object
*/
function Drone( x, y, z, dir, world ) {
this.record = false;
var usePlayerCoords = false;
/* var player = (typeof self !== 'undefined' ? self : null);
var playerPos;
if ( x.location && x.name) {
player = x;
}
playerPos = x.location;
var that = this;
var populateFromLocation = function( loc ) {
that.x = loc.x;
that.y = loc.y;
that.z = loc.z;
that.dir = getDirFromRotation(loc);
that.world = loc.world;
};*/
// var mp = utils.getMousePos( player );
if ( typeof x == 'undefined' || x.location ) {
var location = get_player_location();
this.x = location["x"];
this.y = location["y"];
this.z = location["z"];
this.dir = location["facing"];
usePlayerCoords = true;
/*if ( mp ) {
populateFromLocation( mp );
if ( playerPos ) {
this.dir = getDirFromRotation(playerPos);
}
} 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 );
}*/
} else {
if ( arguments[0].x && arguments[0].y && arguments[0].z ) {
populateFromLocation( arguments[ 0 ] );
} else {
this.x = x;
this.y = y;
this.z = z;
if ( typeof dir == 'undefined' ) {
this.dir = 1; //getDirFromRotation( playerPos);
} else {
this.dir = dir%4;
}
/* if ( typeof world == 'undefined' ) {
this.world = playerPos.world;
} else*/ {
this.world = world;
}
}
}
if ( usePlayerCoords ) {
this.fwd( 3 );
}
this.chkpt( 'start' );
this.record = true;
this.history = [];
// this.player = player;
return this;
}
/*Drone.getDirFromRotation = getDirFromRotation;
Drone.opsPerSec = 10;
var theQueue = [];
function processQueue(){
var process,
i = 0,
queues = getAllQueues();
for ( ; i < queues.length; i++ ) {
process = queues[i].shift();
if (process){
try {
process();
} catch( e ) {
console.log('Drone build error: ' + e + ' while processing ' + process);
}
}
}
setTimeout( processQueue, 1000 / Drone.opsPerSec );
};
setTimeout( processQueue, 1000 / Drone.opsPerSec );
addUnloadHandler( function() {
var pendingBuildOps = 0;
var allQueues = getAllQueues();
for (var i = 0; i < allQueues.length; i++){
pendingBuildOps += allQueues[i].length;
}
if (pendingBuildOps > 0){
console.warn('There were ' + pendingBuildOps + ' pending build operations which were cancelled');
}
});*/
//
// add custom methods to the Drone object using this function
//
Drone.extend = function( name, func ) {
if (arguments.length == 1){
func = name;
if ( !func.name ){
throw 'A Drone extension function must have a name!';
}
name = func.name;
}
Drone.prototype[ '_' + name ] = func;
Drone.prototype[ name ] = function( ) {
if ( this.record ) {
this.history.push( [ name, arguments ] );
}
var oldVal = this.record;
this.record = false;
this[ '_' + name ].apply( this, arguments );
this.record = oldVal;
return this;
};
global[name] = function( ) {
var result = new Drone();
result[name].apply( result, arguments );
return result;
};
};
/**************************************************************************
### Drone.times() Method
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.
#### Parameters
* numTimes : The number of times you want to repeat the preceding statements.
#### Limitation
For now, don't use `times()` inside a Drone method implementation &ndash; only use it at the in-game prompt as a short-hand workaround for loops.
#### Example
Say you want to do the same thing over and over. You have a couple of options:
* You can use a `for` loop &hellip;
d = new Drone(); for ( var i = 0; i < 4; i++ ) { d.cottage().right(8); }
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 &ndash; even the `for` loop is too much
syntax for what should really be simple.
* You can use a `while` loop &hellip;
d = new Drone(); var i=4; while (i--) { d.cottage().right(8); }
&hellip; 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.
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:
cottage().right(8).times(4);
&hellip; 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:
cottage().right(8).times(4).fwd(8).left(32).times(5);
&hellip; breaking it down &hellip;
1. The first 3 calls in the chain ( `cottage()`, `right(8)`, `times(4)` ) build a single row of 4 cottages.
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.
Another example: This statement creates a row of trees 2 by 3:
oak().right(10).times(2).left(20).fwd(10).times(3)
&hellip; You can see the results below.
![times example 1](img/times-trees.png)
***/
Drone.prototype.times = function( numTimes, commands ) {
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 );
}
}
this.record = oldVal;
return this;
};
Drone.prototype.getBlock = function(){
return undefined; //this.world.getBlockAt(this.x,this.y,this.z);
};
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, update);
this
.left(ow)
.down(oh)
.back(od);
return result;
};
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);
};
//
// building
//
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 theQueue;
}
}
function getAllQueues() {
var result = [ theQueue ];
for (var pq in playerQueues) {
result.push(playerQueues[pq]) ;
}
return result;
}
Drone.prototype.cuboida = function(/* Array */ blocks, w, h, d, overwrite) {
if ( typeof overwrite == 'undefined' ) {
overwrite = true;
}
if ( typeof h == 'undefined' ) {
h = 1;
}
if ( typeof d == 'undefined' ) {
d = 1;
}
if ( typeof w == 'undefined' ) {
w = 1;
}
//
// wph 20140823 make a copy because don't want to modify array in background
//
var blocksForBuild = blocks.slice();
var len = blocksForBuild.length,
i = 0;
for ( ; i < len; i++ ) {
blocksForBuild[i] = this.getBlockIdAndMeta( blocksForBuild[ i ] );
}
this.then(function(){
var bi = 0;
traverseDHW( this, d,h,w, function traverseWidthCallback( ) {
var properBlock = blocksForBuild[ bi % len ];
this.setBlock(properBlock[0], properBlock[1]);
bi++;
});
});
return this;
};
Drone.MAX_VOLUME = 1 * MILLION;
Drone.MAX_SIDE = 1 * THOUSAND;
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 );
};
/*
faster cuboid because blockid, meta and world must be provided
use this method when you need to repeatedly place blocks
*/
Drone.prototype.cuboidX = function( blockType, meta, w, h, d, immediate ) {
if ( typeof h == 'undefined' ) {
h = 1;
}
if ( typeof d == 'undefined' ) {
d = 1;
}
if ( typeof w == 'undefined' ) {
w = 1;
}
if ( tooBig( w, h, d ) ) {
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 ) {
this.then(function(){
traverseDHW( this, d,h,w, function( ) {
this.setBlock( blockType, meta );
});
});
} else*/ {
traverseDHW( this, d,h,w, function( ) {
this.setBlock( blockType, meta );
});
}
return this;
};
/*
deferred execution of a drone method
*/
var thenID = 0;
Drone.prototype.then = function( next ){
var chkptThen = '_now' + (thenID++);
this.chkpt(chkptThen);
var thisNext = next.bind(this);
function wrapperFn(){
var chkNow = '_now' + (thenID++);
this.chkpt(chkNow);
this.move(chkptThen);
thisNext();
this.move(chkNow);
}
getQueue(this).push( wrapperFn.bind(this) );
return this;
};
Drone.prototype.cuboid = function( block, w, h, d, immediate ) {
var bm = this.getBlockIdAndMeta( block );
return this.cuboidX( bm[0], bm[1], w, h, d, immediate);
};
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 );
};
// 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
Drone.PLAYER_STAIRS_FACING = [ 0, 2, 1, 3 ];
// for blocks 68 (wall signs) 65 (ladders) 61,62 (furnaces) 23 (dispenser) and 54 (chest)
Drone.PLAYER_SIGN_FACING = [ 4, 2, 5, 3 ];
Drone.PLAYER_TORCH_FACING = [ 2, 4, 1, 3 ];
Drone.extend('box', Drone.prototype.cuboid );
Drone.extend('box0',Drone.prototype.cuboid0 );
//Drone.extend('boxa',Drone.prototype.cuboida );
//
// show the Drone's position and direction
//
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];
};
Drone.prototype.debug = function( ) {
console.log(this.toString( ) );
return this;
};
function getBlockIdAndMeta( b ) {
var defaultMeta = 0,
i = 0,
bs,
md,
sp;
/* if (typeof b === 'number' || /^[0-9]+$/.test(b)) {
// wph 20130414 - use sensible defaults for certain blocks e.g. stairs
// should face the drone.
if ( blocks.isStair(b) ) {
defaultMeta = Drone.PLAYER_STAIRS_FACING[ this.dir % 4 ];
} else {
switch (b) {
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' ) {
bs = b;
sp = bs.indexOf(':' );
if ( sp == -1 ) {
b = parseInt( bs );
return [ b, defaultMeta ];
}
b = parseInt(bs.substring(0,sp ) );
md = parseInt(bs.substring(sp+1,bs.length ) );
return [b,md];
}
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];
}
return [b.id, metadata];
}*/
}
var _traverse = [{},{},{},{}];
// east
function walkWidthEast( drone, n,callback ) {
var s = drone.z, e = s + n;
for ( ; drone.z < e; drone.z++ ) {
callback.call(drone ,drone.z-s );
}
drone.z = s;
}
function walkDepthEast( drone,n,callback ) {
var s = drone.x, e = s+n;
for ( ;drone.x < e;drone.x++ ) {
callback.call(drone, drone.x-s );
}
drone.x = s;
}
function walkWidthSouth( drone,n,callback ) {
var s = drone.x, e = s-n;
for ( ;drone.x > e;drone.x-- ) {
callback.call(drone, s-drone.x );
}
drone.x = s;
}
function walkWidthWest( drone,n,callback ) {
var s = drone.z, e = s-n;
for ( ;drone.z > e;drone.z-- ) {
callback.call(drone, s-drone.z );
}
drone.z = s;
}
_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;
// north
_traverse[3].width = walkDepthEast;
_traverse[3].depth = walkWidthWest;
function traverseHeight( drone,n,callback ) {
var s = drone.y, e = s + n;
for ( ; drone.y < e; drone.y++ ) {
callback.call(drone, drone.y-s );
}
drone.y = s;
};
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);
});
});
}
//
// wph 20130130 - make this a method - extensions can use it.
//
Drone.prototype.getBlockIdAndMeta = getBlockIdAndMeta;
Drone.prototype._getBlockIdAndMeta = function(b){
console.warn('_getBlockIdAndMeta is deprecated. Use .getBlockIdAndMeta() instead');
return this.getBlockIdAndMeta(b);
};
/*Drone.bountiful = __plugin.canary ? parseFloat(server.canaryModVersion) > 1.7 : false;*/
var droneCoreExts = [
'./arc',
// './bed',
'./blocktype',
// './copypaste',
'./cylinders',
// './doors',
// './firework',
// './garden',
// './ladder',
'./movement',
// './prism',
'./rand',
// './sign',
'./sphere'
// './stairs',
// './trees'
];
for(var i = 0; i < droneCoreExts.length; ++i)
{
require(droneCoreExts[i])(Drone);
};
module.exports = Drone;

46
js/drone/ladder.js Normal file
View File

@ -0,0 +1,46 @@
'use strict';
/*global require, module*/
/************************************************************************
### Drone.ladder() method
Creates a ladder extending skyward.
#### Parameters
* height (optional - default 1)
#### Example
To create a ladder extending 10 blocks high:
var drone = new Drone(self);
drone.ladder(10)
At the in-game prompt, look at a block and then type:
/js ladder(10)
A ladder 10 blocks high will be created at the point you were looking at.
#### Since
##### 3.0.3
***/
var blocks = require('blocks');
function ladder( height ){
this.then(function ladderLater(){
var block = this.getBlock();
if (block.typeId == blocks.air || block.typeId == blocks.ladder){
this.box(blocks.ladder, 1, height, 1, true);
} else {
this
.back()
.box(blocks.ladder, 1, height, 1, true)
.fwd();
}
});
}
module.exports = function(Drone){
Drone.extend( ladder );
};

189
js/drone/movement.js Normal file
View File

@ -0,0 +1,189 @@
'use strict';
/*global require,__plugin, module, Packages, org*/
/************************************************************************
### 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;
function turn( n ) {
if ( typeof n == 'undefined' ) {
n = 1;
}
this.dir += n;
this.dir %=4;
}
function chkpt( name ) {
this._checkpoints[ name ] = { x:this.x, y:this.y, z:this.z, dir:this.dir };
}
function move( ) {
var Drone = this.constructor;
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];
}
}
}
function right( n ) {
if ( typeof n == 'undefined' ) {
n = 1;
}
_movements[ this.dir ].right( this, n );
}
function left( n ) {
if ( typeof n == 'undefined') {
n = 1;
}
_movements[ this.dir ].left( this, n );
}
function fwd( n ) {
if ( typeof n == 'undefined' ) {
n = 1;
}
_movements[ this.dir ].fwd( this, n );
}
function back( n ) {
if ( typeof n == 'undefined' ) {
n = 1;
}
_movements[ this.dir ].back( this, n );
}
function up( n ) {
if ( typeof n == 'undefined' ) {
n = 1;
}
this.y+= n;
}
function down( n ) {
if ( typeof n == 'undefined' ) {
n = 1;
}
this.y-= n;
}
/*function getLocation( ) {
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) {
var bkLocation = org.bukkit.Location;
return new bkLocation( this.world, this.x, this.y, this.z );
}
}*/
module.exports = function(Drone){
Drone.prototype._checkpoints = {};
// Drone.prototype.getLocation = getLocation;
Drone.extend( chkpt );
Drone.extend( move );
Drone.extend( turn );
Drone.extend( right );
Drone.extend( left );
Drone.extend( fwd );
Drone.extend( back );
Drone.extend( up );
Drone.extend( down );
};

98
js/drone/prism.js Normal file
View File

@ -0,0 +1,98 @@
'use strict';
/*global require, module*/
/************************************************************************
### 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();
}
}
module.exports = function(Drone){
Drone.extend(prism0);
Drone.extend(prism);
};

67
js/drone/rand.js Normal file
View File

@ -0,0 +1,67 @@
'use strict';
/*global require, module*/
/************************************************************************
### 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.
***/
//
// 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;
}
function rand( dist, width, height, depth, overwrite ) {
if ( typeof overwrite == 'undefined' ) {
overwrite = true;
}
var randomized = _rand( dist );
this.boxa( randomized, width, height, depth, overwrite);
}
module.exports = function(Drone){
Drone.extend( rand );
};

144
js/drone/sign.js Normal file
View File

@ -0,0 +1,144 @@
'use strict';
/*global require, echo,__plugin, module*/
var blocks = require('blocks');
/************************************************************************
### Drone.wallsign() method
Creates a wall sign (A sign attached to a wall)
#### Parameters
* message - can be a string or an array of strings
#### Example
drone.wallsign(['Welcome','to','Scriptopia']);
![wall sign](img/signex2.png)
### Drone.signpost() method
Creates a free-standing signpost
#### Parameters
* message - can be a string or an array of strings
#### Example
drone.signpost(['Hello','World']);
![ground sign](img/signex1.png)
### Drone.sign() method
Deprecated: Use signpost() or wallsign() methods instead.
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"], blocks.sign_post);
![ground sign](img/signex1.png)
... to create a wall mounted sign...
drone.sign(["Welcome","to","Scriptopia"], blocks.sign );
![wall sign](img/signex2.png)
***/
function putSign( drone, texts, blockId, meta ) {
var i,
len = texts.length,
block,
state,
getState,
isSign,
setLine;
if ( blockId != blocks.sign_post && blockId != blocks.sign ) {
throw new Error( 'Invalid Parameter: blockId must be blocks.sign_post or blocks.sign' );
}
block = drone.setBlock( blockId, meta);
if (__plugin.canary){
isSign = function(block){
var sign = block.getTileEntity();
return sign.setTextOnLine;
};
setLine = function( block, i) {
var sign = block.getTileEntity();
sign.setTextOnLine( texts[i], i );
sign.update();
};
}
if (__plugin.bukkit){
isSign = function(block){ return block.state && block.state.setLine; };
setLine = function( block, i) {
var sign = block.state;
sign.setLine( i, texts[i] );
sign.update(true);
};
}
if ( isSign(block) ) {
if (len > 4){
len = 4;
}
for ( i = 0; i < len; i++ ) {
setLine(block, i, texts[ i ] );
}
}
};
function signpost( message ){
this.then(function(){
this.sign(message, blocks.sign_post);
});
}
function wallsign( message ){
/*
must allow for /js wallsign() while looking at a wall block
*/
this.then(function(){
var block = this.getBlock();
if (block.typeId == blocks.air || block.typeId == blocks.sign){
this.sign(message, blocks.sign);
} else {
this
.back()
.sign(message, blocks.sign)
.fwd();
}
});
}
function sign( message, block ) {
if ( message.constructor != Array ) {
message = [message];
}
var bm = this.getBlockIdAndMeta( block );
block = bm[0];
var meta = bm[1];
if ( block !== blocks.sign_post && block !== blocks.sign ) {
var usage = 'Usage: sign("message", blocks.sign_post) or sign("message", blocks.sign)';
if ( this.player ) {
echo( this.player, usage);
}
console.error(usage);
return;
}
putSign( this, message, block, meta);
}
module.exports = function(Drone){
Drone.extend(sign);
Drone.extend(signpost);
Drone.extend(wallsign);
};

396
js/drone/sphere.js Normal file
View File

@ -0,0 +1,396 @@
'use strict';
/*global module*/
/************************************************************************
### Drone.sphere() method
Creates a sphere.
#### Parameters
* block - The block the sphere will be made of.
* radius - The radius of the sphere.
#### Example
To create a sphere of Iron with a radius of 10 blocks...
sphere( blocks.iron, 10);
![sphere example](img/sphereex1.png)
Spheres are time-consuming to make. You *can* make large spheres (250 radius) but expect the
server to be very busy for a couple of minutes while doing so.
***/
function sphere( block, radius ) {
var lastRadius = radius,
slices = [ [ radius , 0 ] ],
diameter = radius * 2,
bm = this.getBlockIdAndMeta( block ),
r2 = radius * radius,
i = 0,
newRadius,
yOffset,
sr,
sh,
v,
h;
if ( radius > 127 ) {
throw new Error('Sphere radius must be less than 128 blocks');
}
for ( i = 0; i <= radius; i++ ) {
newRadius = Math.round( Math.sqrt( r2 - i * i ) );
if ( newRadius == lastRadius ) {
slices[ slices.length - 1 ][ 1 ]++;
} else {
slices.push( [ newRadius , 1 ] );
}
lastRadius = newRadius;
}
this.chkpt( 'sphere' );
//
// mid section
//
this.up( radius - slices[0][1] )
.cylinder( block, radius, ( slices[0][1]*2 ) - 1, { blockType: bm[0], meta: bm[1] } )
.down( radius - slices[0][1] );
yOffset = -1;
for ( i = 1; i < slices.length; i++ ) {
yOffset += slices[i-1][1];
sr = slices[i][0];
sh = slices[i][1];
v = radius + yOffset;
h = radius - sr;
// northern hemisphere
this.up( v )
.fwd( h )
.right( h )
.cylinder( block, sr, sh, { blockType: bm[0], meta: bm[1] } )
.left( h )
.back( h )
.down( v );
// southern hemisphere
v = radius - ( yOffset + sh + 1 );
this.up( v )
.fwd( h )
.right( h )
.cylinder( block, sr, sh, { blockType: bm[0], meta: bm[1]} )
.left( h )
.back( h )
.down( v );
}
return this.move( 'sphere' );
}
/************************************************************************
### Drone.sphere0() method
Creates an empty sphere.
#### Parameters
* block - The block the sphere will be made of.
* radius - The radius of the sphere.
#### Example
To create a sphere of Iron with a radius of 10 blocks...
sphere0( blocks.iron, 10);
Spheres are time-consuming to make. You *can* make large spheres (250 radius) but expect the
server to be very busy for a couple of minutes while doing so.
***/
function sphere0(block,radius)
{
var lastRadius = radius,
slices = [ [ radius, 0 ] ],
diameter = radius * 2,
bm = this.getBlockIdAndMeta( block ),
r2 = radius*radius,
i,
newRadius,
sr,
sh,
v,
h,
len,
yOffset;
if ( radius > 127 ) {
throw new Error('Sphere radius must be less than 128 blocks');
}
for ( i = 0; i <= radius; i++ ) {
newRadius = Math.round( Math.sqrt( r2 - i * i ) );
if ( newRadius == lastRadius ) {
slices[ slices.length - 1 ][ 1 ]++;
} else {
slices.push( [ newRadius, 1 ] );
}
lastRadius = newRadius;
}
this.chkpt( 'sphere0' );
//
// mid section
//
this.up( radius - slices[0][1] )
.arc({ blockType: bm[0],
meta: bm[1],
radius: radius,
strokeWidth: 2,
stack: (slices[0][1]*2)-1,
fill: false
})
.down( radius - slices[0][1] );
yOffset = -1;
len = slices.length;
for ( i = 1; i < len; i++ ) {
yOffset += slices[i-1][1];
sr = slices[i][0];
sh = slices[i][1];
v = radius + yOffset;
h = radius-sr;
// northern hemisphere
// .cylinder(block,sr,sh,{blockType: bm[0],meta: bm[1]})
this.up( v ).fwd( h ).right( h )
.arc({
blockType: bm[0],
meta: bm[1],
radius: sr,
stack: sh,
fill: false,
strokeWidth: i < len - 1 ? 1 + ( sr - slices[ i + 1 ][ 0 ] ) : 1
})
.left( h ).back( h ).down( v );
// southern hemisphere
v = radius - ( yOffset + sh + 1 );
this.up( v ).fwd( h ).right( h )
.arc({
blockType: bm[0],
meta: bm[1],
radius: sr,
stack: sh,
fill: false,
strokeWidth: i < len - 1 ? 1 + ( sr - slices[ i + 1 ][ 0 ] ) : 1
})
.left( h ).back( h ). down( v );
}
this.move( 'sphere0' );
return this;
}
/************************************************************************
### Drone.hemisphere() method
Creates a hemisphere. Hemispheres can be either north or south.
#### Parameters
* block - the block the hemisphere will be made of.
* radius - the radius of the hemisphere
* northSouth - whether the hemisphere is 'north' or 'south'
#### Example
To create a wood 'north' hemisphere with a radius of 7 blocks...
hemisphere(blocks.oak, 7, 'north');
![hemisphere example](img/hemisphereex1.png)
***/
function hemisphere( block, radius, northSouth ) {
var lastRadius = radius,
slices = [ [ radius, 0 ] ],
diameter = radius * 2,
bm = this.getBlockIdAndMeta(block),
r2 = radius * radius,
i = 0,
newRadius;
if ( radius > 255 ) {
throw new Error('Hemisphere radius must be less than 256 blocks');
}
for ( i = 0; i <= radius; i++ ) {
newRadius = Math.round( Math.sqrt( r2 - i * i ) );
if ( newRadius == lastRadius ) {
slices[ slices.length - 1 ][ 1 ]++;
} else {
slices.push( [ newRadius, 1 ] );
}
lastRadius = newRadius;
}
this.chkpt( 'hsphere' );
//
// mid section
//
if ( northSouth == 'north' ) {
this.cylinder( block, radius, slices[0][1], { blockType: bm[0], meta: bm[1] } );
} else {
this.up( radius - slices[0][1] )
.cylinder( block, radius, slices[0][1], { blockType: bm[0], meta: bm[1] } )
.down( radius - slices[0][1] );
}
var yOffset = -1;
for ( i = 1; i < slices.length; i++ ) {
yOffset += slices[i-1][1];
var sr = slices[i][0];
var sh = slices[i][1];
var v = yOffset, h = radius-sr;
if ( northSouth == 'north' ) {
// northern hemisphere
this.up( v ).fwd( h ).right( h )
.cylinder( block, sr, sh, { blockType: bm[0], meta: bm[1] } )
.left( h ).back( h ).down( v );
} else {
// southern hemisphere
v = radius - ( yOffset + sh + 1 );
this.up( v ).fwd( h ).right( h )
.cylinder( block, sr, sh, { blockType: bm[0], meta: bm[1] } )
.left( h ).back( h ).down( v );
}
}
return this.move( 'hsphere' );
}
/************************************************************************
### Drone.hemisphere0() method
Creates a hollow hemisphere. Hemispheres can be either north or south.
#### Parameters
* block - the block the hemisphere will be made of.
* radius - the radius of the hemisphere
* northSouth - whether the hemisphere is 'north' or 'south'
#### Example
To create a glass 'north' hemisphere with a radius of 20 blocks...
hemisphere0(blocks.glass, 20, 'north');
![hemisphere example](img/hemisphereex2.png)
***/
function hemisphere0( block, radius, northSouth ) {
if ( radius > 255 ) {
throw new Error('Hemisphere radius must be less than 256 blocks');
}
var lastRadius = radius,
slices = [ [ radius, 0 ] ],
diameter = radius * 2,
bm = this.getBlockIdAndMeta(block),
r2 = radius * radius,
i = 0,
len,
newRadius;
if ( radius > 255 ) {
throw new Error('Hemisphere radius must be less than 256 blocks');
}
for ( i = 0; i <= radius; i++ ) {
newRadius = Math.round( Math.sqrt( r2 - i * i ) );
if ( newRadius == lastRadius ) {
slices[ slices.length - 1 ][ 1 ]++;
} else {
slices.push( [ newRadius, 1 ] );
}
lastRadius = newRadius;
}
this.chkpt( 'hsphere0' );
//
// mid section
//
if ( northSouth == 'north' ) {
this.arc({
blockType: bm[0],
meta: bm[1],
radius: radius,
strokeWidth: 1,
stack: slices[0][1],
fill: false
});
} else {
this.up( radius - slices[0][1] );
this.arc({
blockType: bm[0],
meta: bm[1],
radius: radius,
strokeWidth: 1,
stack: slices[0][1],
fill: false
});
this.down( radius - slices[0][1] );
}
var yOffset = -1;
len = slices.length;
for ( i = 1; i < slices.length; i++ ) {
yOffset += slices[i-1][1];
var sr = slices[i][0];
var sh = slices[i][1];
var v = yOffset, h = radius-sr;
if ( northSouth == 'north' ) {
// northern hemisphere
this.up( v )
.fwd( h )
.right( h );
this.arc( {
blockType: bm[0],
meta: bm[1],
radius: sr,
stack: sh,
fill: false,
strokeWidth: i < len - 1 ? 1 + ( sr - slices[ i + 1 ][ 0 ] ) : 1
} );
this.left( h )
.back( h )
.down( v );
} else {
// southern hemisphere
v = radius - ( yOffset + sh + 1 );
this.up( v )
.fwd( h )
.right( h );
this.arc({
blockType: bm[0],
meta: bm[1],
radius: sr,
stack: sh,
fill: false,
strokeWidth: i < len - 1 ? 1 + ( sr - slices[ i + 1 ][ 0 ] ) : 1
});
this.left( h )
.back( h )
.down( v );
}
}
return this.move( 'hsphere0' );
}
module.exports = function(Drone){
Drone.extend( sphere );
Drone.extend( sphere0 );
Drone.extend( hemisphere );
Drone.extend( hemisphere0 );
};

61
js/drone/stairs.js Normal file
View File

@ -0,0 +1,61 @@
'use strict';
/*global module*/
/**************************************************************************
### 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 blocks = require('blocks');
/*global require*/
function stairs(blockType, width, height){
if (typeof width === 'undefined')
width = 1;
if (typeof height === 'undefined')
height = 1;
if (typeof blockType === 'undefined'){
blockType = blocks.stairs.oak;
}
var bm = this.getBlockIdAndMeta(blockType);
this.then(function(){
this.chkpt('_stairs');
while (height > 0) {
this.traverseWidth(width, function(){
this.setBlock(bm[0], bm[1]);
});
this.fwd().up();
height -= 1;
}
this.move('_stairs');
});
}
module.exports = function(Drone){
Drone.extend(stairs);
};

26
js/drone/test.js Normal file
View File

@ -0,0 +1,26 @@
'use strict';
/*global module*/
function testHorizontalStrokeWidth(){
this.arc({
blockType: 42,
meta: 0,
radius: 8,
orientation: 'horizontal',
strokeWidth: 3,
quadrants: {topright:true,topleft:true,bottomleft:true,bottomright:true}
});
}
function testVerticalStrokeWidth(){
this.arc({
blockType: 42,
meta: 0,
radius: 8,
orientation: 'vertical',
strokeWidth: 3,
quadrants: {topright:true,topleft:true,bottomleft:true,bottomright:true}
});
}
module.exports = function(Drone){
Drone.prototype.testHorizontalStrokeWidth = testHorizontalStrokeWidth;
Drone.prototype.testVerticalStrokeWidth = testVerticalStrokeWidth;
};

99
js/drone/trees.js Normal file
View File

@ -0,0 +1,99 @@
'use strict';
/*global require, __plugin, Packages, org, echo, module */
var blocks = require('blocks');
/************************************************************************
### 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.
***/
function bukkitTreeFactory( k, v ) {
return function( ) {
var block = this.getBlock();
if ( block.typeId == blocks.grass ) {
this.up( );
}
var treeLoc = this.getLocation();
var successful = treeLoc.world.generateTree(treeLoc,v );
if ( block.typeId == blocks.grass ) {
this.down( );
}
};
}
function canaryTreeFactory( k, v ){
return function(){
var block = this.getBlock();
if ( block.typeId == blocks.grass ) {
this.up( );
}
var treeLoc = this.getLocation();
if (!treeLoc.world.generateTree){
var msg = k + '() is not supported in this version';
if (this.player){
echo(this.player, msg);
}
console.log(msg);
return;
}
var cmTreeType = Packages.net.canarymod.api.world.TreeType;
var trees = {
oak: cmTreeType.BIGOAK,
birch: cmTreeType.BIRCH,
jungle: cmTreeType.JUNGLE,
spruce: cmTreeType.SPRUCE
};
var successful = treeLoc.world.generateTree(treeLoc, trees[k] );
if ( block.typeId == blocks.grass ) {
this.down( );
}
};
}
module.exports = function (Drone){
var trees = {
oak: null,
birch: null,
jungle: null,
spruce: null
};
var p;
if (__plugin.canary){
for (p in trees ) {
Drone.extend(p, canaryTreeFactory ( p, trees[p] ) );
}
}
if (__plugin.bukkit){
var bkTreeType = org.bukkit.TreeType;
trees = {
oak: bkTreeType.BIG_TREE ,
birch: bkTreeType.BIRCH ,
jungle: bkTreeType.JUNGLE,
spruce: bkTreeType.REDWOOD
};
for (p in trees ) {
Drone.extend(p, bukkitTreeFactory ( p, trees[p] ) );
}
}
};

18
js/scriptmine.js Normal file
View File

@ -0,0 +1,18 @@
Duktape.modSearch = function (id)
{
var res;
print('loading module:', id);
res = readFile(id);
if (typeof res === 'string')
{
return res;
}
throw new Error('module not found: ' + id);
}
var global = this;
var blocks = require("blocks");
var Drone = require("drone");

View File

@ -129,11 +129,12 @@ duk_ret_t readFile(duk_context *ctx)
{
strcpy(filename, "js/drone/");
strcat(filename, text);
strcat(filename, ".js");
FILE *f = fopen(filename, "r");
strcat(filename, ".js");
f = fopen(filename, "r");
if (NULL == f)
{
duk_push_undefined(ctx);
return 1;
}
}
fclose(f);
@ -144,9 +145,9 @@ duk_ret_t readFile(duk_context *ctx)
duk_ret_t set_node(duk_context *ctx)
{
int x = duk_to_int(ctx, -4);
int z = duk_to_int(ctx, -4);
int y = duk_to_int(ctx, -3);
int z = duk_to_int(ctx, -2);
int x = duk_to_int(ctx, -2);
const char *blockID = duk_to_string(ctx, -1);
const char *nodeName = blockID_to_node_name(blockID);
lua_getfield(Lg, LUA_GLOBALSINDEX, "minetest"); // [minetest]
@ -166,6 +167,78 @@ duk_ret_t set_node(duk_context *ctx)
return 1;
}
duk_ret_t get_player_location(duk_context *ctx)
{
lua_getfield(Lg, LUA_GLOBALSINDEX, "minetest"); // [minetest]
lua_getfield(Lg, -1, "get_player_by_name"); // [minetest get_player_by_name]
lua_remove(Lg, -2); // [get_player_by_name]
lua_pushstring(Lg, name); // [get_player_by_name name]
lua_call(Lg, 1, 1); // [player]
lua_getmetatable(Lg, -1); // [player metatable]
lua_pushstring(Lg, "__index"); // [player metatable __index]
lua_rawget(Lg, -2); // [player metatable __index]
lua_pushstring(Lg, "getpos"); // [player metatable __index getpos]
lua_rawget(Lg, -2); // [player metatable __index getpos]
lua_pushvalue(Lg, -4); // [player metatable __index getpos player]
lua_call(Lg, 1, 1); // [player metatable __index postable]
lua_getfield(Lg, -1, "x");
int x = lua_tointeger(Lg, -1);
lua_remove(Lg, -1);
lua_getfield(Lg, -1, "y");
int y = lua_tointeger(Lg, -1);
lua_remove(Lg, -1);
lua_getfield(Lg, -1, "z");
int z = lua_tointeger(Lg, -1);
lua_remove(Lg, -1);
lua_remove(Lg, -1); // [player metatable __index]
lua_pushstring(Lg, "get_look_dir");
lua_rawget(Lg, -2); // [player metatable __index get_look_dir]
lua_pushvalue(Lg, -4); // [player metatable __index get_look_dir player]
lua_call(Lg, 1, 1); // [player metatable __index postable]
lua_getfield(Lg, -1, "x");
double xv = lua_tonumber(Lg, -1);
lua_remove(Lg, -1);
lua_getfield(Lg, -1, "z");
double zv = lua_tonumber(Lg, -1);
lua_remove(Lg, -1);
lua_remove(Lg, -1); // [player metatable __index]
lua_remove(Lg, -1); // [player metatable]
lua_remove(Lg, -1); // [player]
lua_remove(Lg, -1);
int facing = 0;
if (fabs(xv) > fabs(zv))
{
if (xv > 0)
{
facing = 1;
}
else
facing = 3;
}
else
{
if (zv > 0)
{
facing = 0;
}
else
{
facing = 2;
}
}
y += 1;
duk_idx_t ary_indx = duk_push_array(ctx);
duk_push_int(ctx, z);
duk_put_prop_string(ctx, ary_indx, "x");
duk_push_int(ctx, y);
duk_put_prop_string(ctx, ary_indx, "y");
duk_push_int(ctx, x);
duk_put_prop_string(ctx, ary_indx, "z");
duk_push_int(ctx, facing);
duk_put_prop_string(ctx, ary_indx, "facing");
return 1;
}
static int javascript(lua_State *L)
{
const char *cmd = lua_tostring(L, -1);
@ -180,7 +253,7 @@ static int loadscript(lua_State *L)
const char *modpath = lua_tostring(L, -1);
char *fullpath = malloc(strlen(modpath) + 10);
strcpy(fullpath, modpath);
strcat(fullpath, "/drone.js");
strcat(fullpath, "/js/scriptmine.js");
if (duk_peval_file_noresult(ctx, fullpath) != 0) {
printf("Error: %s\n", duk_safe_to_string(ctx, -1));
exit(1);
@ -192,7 +265,6 @@ static int loadscript(lua_State *L)
int luaopen_scriptmine(lua_State *L)
{
ctx = duk_create_heap_default();
drone_init(ctx);
duk_push_global_object(ctx);
duk_push_c_function(ctx, echo, 1);
duk_put_prop_string(ctx, -2, "echo");
@ -200,6 +272,8 @@ int luaopen_scriptmine(lua_State *L)
duk_put_prop_string(ctx, -2, "readFile");
duk_push_c_function(ctx, set_node, 4);
duk_put_prop_string(ctx, -2, "set_node");
duk_push_c_function(ctx, get_player_location, 0);
duk_put_prop_string(ctx, -2, "get_player_location");
if (!ctx)
{
printf("Failed to create a Duktape heap.\n");

View File

@ -7,4 +7,3 @@ extern lua_State *Lg;
extern const char *name;
extern const char *blockID_to_node_name(const char *blockID);
extern void drone_init(duk_context *ctx);