diff --git a/build.xml b/build.xml index e63da8c..159438f 100644 --- a/build.xml +++ b/build.xml @@ -61,7 +61,7 @@ - + @@ -72,6 +72,27 @@ + + + + + + + + + + + + + + +
# The Young Person's Guide to Programming in Minecraft + +
+ + +
+
diff --git a/docs/YoungPersonsGuideToProgrammingMinecraft.md b/docs/YoungPersonsGuideToProgrammingMinecraft.md index 88a296f..0cd95d2 100644 --- a/docs/YoungPersonsGuideToProgrammingMinecraft.md +++ b/docs/YoungPersonsGuideToProgrammingMinecraft.md @@ -1,7 +1,6 @@ # The Young Person's Guide to Programming in Minecraft ## Table of Contents - * [Introduction](#introduction) * [Installation](#installation) * [Learning Javascript](#learning-javascript) @@ -11,14 +10,14 @@ * [Building stuff in Minecraft](#building-stuff-in-minecraft) * [Common Block Materials](#common-block-materials) * [Dimensions](#dimensions) - * [More Shapes](#more-shapes) + * [More shapes](#more-shapes) * [The Drone Object](#the-drone-object) * [Movement](#movement) - * [Chaining - Combining Building and Movement](#chaining---combining-building-and-movement) + * [Chaining - combining building and movement.](#chaining---combining-building-and-movement) * [Exercise - Build a simple dwelling](#exercise---build-a-simple-dwelling) - * [Remembering where you started](#remembering-where-you-started) + * [Remembering where you started.](#remembering-where-you-started) * [Saving your work](#saving-your-work) - * [Your first Minecraft Mod!](#your-first-minecraft-mod) + * [Your First Minecraft Mod!](#your-first-minecraft-mod) * [Parameters](#parameters) * [true or false](#true-or-false) * [More fun with `true` or `false`](#more-fun-with-true-or-false) @@ -31,7 +30,7 @@ * [Putting `for` loops to use - Building a Skyscraper](#putting-for-loops-to-use---building-a-skyscraper) * [Making Decisions](#making-decisions) * [Event-Driven programming](#event-driven-programming) - * [Stop listening to events](#stop-listening-to-events) + * [Stop listening to events.](#stop-listening-to-events) * [Keeping Score - Lookup tables in Javascript](#keeping-score---lookup-tables-in-javascript) * [Counting block break events for each player](#counting-block-break-events-for-each-player) * [Next Steps](#next-steps) @@ -1227,5 +1226,3 @@ different objects and methods available for use by ScriptCraft. [img_ssf]: img/skyscraper_floor.png [img_ss]: img/skyscraper.png -## Categories -Minecraft, Programming, ScriptCraft diff --git a/src/docs/javascript/generateTOC.js b/src/docs/javascript/generateTOC.js new file mode 100644 index 0000000..555abf2 --- /dev/null +++ b/src/docs/javascript/generateTOC.js @@ -0,0 +1,34 @@ +args = args.slice(1); + +var template = args[0]; + +var BufferedReader = java.io.BufferedReader; +var FileReader = java.io.FileReader; + +var contents = [], line = undefined; +var br = new BufferedReader( new FileReader(template) ); + +while ( (line = br.readLine()) != null){ + contents.push(line); +} +br.close(); + +println('## Table of Contents'); + +for (var i = 0; i < contents.length; i++){ + line = contents[i]; + if (line.match(/^##\s+/)){ + var h2 = line.match(/^##\s+(.*)/)[1].trim(); + var link = h2.replace(/[^a-zA-Z0-9 \-]/g,''); + link = link.replace(/ /g,'-'); + link = link.toLowerCase(); + println (' * [' + h2 + '](#' + link + ')'); + } + if (line.match(/^###\s+/)){ + var h3 = line.match(/^###\s+(.*)/)[1].trim(); + var link = h3.replace(/[^a-zA-Z0-9 \-]/g,''); + var link = link.replace(/ /g,'-'); + link = link.toLowerCase(); + println (' * [' + h3 + '](#' + link + ')'); + } +} diff --git a/src/docs/templates/ypgpm.mdt b/src/docs/templates/ypgpm.mdt new file mode 100644 index 0000000..0d7ea54 --- /dev/null +++ b/src/docs/templates/ypgpm.mdt @@ -0,0 +1,1192 @@ + +## Introduction + +Minecraft is an open-ended 3D game where you can build and craft +anything you like. Minecraft can be extended and enhanced using 'Mods' +(short for 'modifications') - additional bits of code that are added +to the Game. ScriptCraft is one such Mod - it lets you program in +Javacript right within the game, making it possible to ... + + * Build using simple javascript statements. + * Extend the game in other interesting ways - add new Items, change + the game behaviour and create mini-games. + +Minecraft can be played in single-player or multi-player mode (with +friends). Most people play Minecraft in Multi-player mode where +players connect to a Minecraft Server on the internet or locally +(running on the player's computer). + +![Cottages created using ScriptCraft in MineCraft][img_cr] + +## Installation + +CraftBukkit is a version of the Minecraft server software which allows +easy addition of 'Mods' and extensions to Minecraft. ScriptCraft is a +'Mod' for use with CraftBukkit. Adding Mods to Minecraft can be +difficult but CraftBukkit makes it easy. Follow these steps to +Install ScriptCraft on your computer... + +1. [Download and install CraftBukkit][dlbuk]. Then follow the [Bukkit Installation Instructions][bii]. +[bii]: http://wiki.bukkit.org/Setting_up_a_server + +2. Start the CraftBukkit server, then once it has started up, stop it + by typing 'stop'. If you go to the craftbukkit folder (see step 1) you + should see some new files and subfolders. + +3. [Download the latest version of the ScriptCraft Mod][sc-plugin]. Then copy the ScriptCraft.jar file to the + `craftbukkit/plugins` folder (This folder won't be created until you run Bukkit for the first time (see previous step). + +4. In the CraftBukkit command window type `op {your_username}` and hit + enter, replacing {your_username} with your own minecraft + username. This will give you `operator` access meaning you can perform + more commands than are normally available in Minecraft. You should + make yourself a server operator (Server operators have full privileges + for the server) permanently by editing the craftbukkit/ops.txt file + and adding your username (one username per line). + +5. Start up the craftbukkit server again (see [instructions for starting the server][bii]). + +6. In the CraftBukkit command window type `js 1 + 1` and hit enter. You should see `> 2` . + +... Congratulations! You just installed your own Minecraft Server with +the ScriptCraft Mod and are now ready to begin programming in Minecraft. + +Normally, Minecraft Mods are written in Java. This makes writing your +own extension or game rules difficult because you must first learn Java. +Java is different enough from Javascript. With the ScriptCraft plug-in +installed, you don't have to learn Java, you can extend and customize +Minecraft your way using Javascript. Javascript is easier to learn than +Java but it's also more flexible and powerful and is used for creating +interactive web sites and many other applications. + +## Learning Javascript + +To begin creating cool stuff in Minecraft using ScriptCraft, you don't +*have* to know much JavaScript. ScriptCraft comes with lots of functions +to help you create buildings of any size, and lets you experiment while +you play. However, as you learn Javascript you will be able to create +cooler stuff in Minecraft - not just buildings, you'll be able to add +new rules and items to the game - even create mini-games for you and +your friends. If you want to get started learning JavaScript, check out +this [fun Javascript Tutorial][ce]. If you want to dive right in to +ScriptCraft, read on... + +## First Steps + +If you don't already know Javascript, don't worry, you'll learn a little +about Programming and Javascript along the way. You've set up a +Minecraft server and are ready to connect ... + +1. Launch Minecraft (keep the Bukkit Command window open). +2. Click 'Multi-Player' +3. Click 'Add Server' +4. Type any name you like in the name field then type `localhost` in the +address field. `localhost` is a special internet address that points to +your own computer. +5. Click 'Join Server' to join the craftbukkit server. +6. Once you've joined the game, press the `/` key located at the bottom +right of your keyboard. A prompt will appear. Type the following then +press enter: `js 1 + 1` The number 2 should be displayed. + +... Well Done! You've just confirmed you can run Javascript code from +within the Minecraft Console. + +## Variables + +A variable is how you name something for the computer (and you the +programmer) to remember. You create a new variable in Javascript using +the `var` keyword... + + /js var location = 'Blackrock Castle' + +... creates a new variable called `location` and stores the text +`Blackrock Castle` in it. Now the computer has a new item in its memory +called `location`. We can use that name like this... + + /js echo( location ) + +... and the following is displayed... + + Blackrock Castle + +...You might be wondering where the `''` (called double-quotes) went. +When telling the computer to store some text, you have to put `'` +(that's the double-quote character - press Shift+2) at the start and end +of the text. The computer doesn't store these quote characters, only the +text between them. The computer will store the variables while the +Minecraft Server is running. Repeat the last command you entered by +pressing the `/` key then the UP arrow key on your keyboard, then +pressing enter. You can repeat that statement as many times as you like +and the computer will always display the same value. You can change the +value like this... + + /js location = 'Mahon Point' + +...notice this time I didn't use the `var` keyword. I didn't need to. +The `var` keyword is only needed when you first create the variable. Now +execute this command... + + /js echo( location ) + +...and it displays... + + Mahon Point + +Variables can be created and changed easily in Javascript. Along with +the variables you'll create in your in-game commands and scripts, there +are handy *free* variables created for you by ScriptCraft. One such variable is +`self`, it contains information about the current player (that's you)... + + /js echo ( self ) + +... displays the following... + + CraftPlayer{name=walterh} + +... for me but the message displayed will be different for every player. + +## Functions + +ScriptCraft comes with a couple of extra functions not normally found in +Javascript. These functions will help you build new structures and +buildings which would otherwise take hours to build by hand. Before +looking at the building functions let's look at the `echo()` function. + +`echo()` - as its name implies - will echo back at you whatever you +tell it. For example, type ... + + /js echo('Hello') + +... and the game will display... + + Hello + +... type ... + + /js echo( 5 + 7 ) + +... and the game will display... + + 12 + +... While you can now use Minecraft to help with Maths homework - I +don't recommend it. Homework and Minecraft don't mix! The `echo()` +function will display anything you tell it to - Text, Numbers and other types... + + /js echo( new Date() ) + +... prints today's date. If the statement above looks confusing - don't +worry - `new Date()` creates a new date object - I'll talk about objects +later ... + + Tue Jan 08 2013 20:53:37 GMT-0000 (GMT) + +![Today's Date][img_echo_date] + +`echo()` is a very useful function but it is not part of the +Javascript Language. You can't use it outside of Minecraft. There are +many other functions in Javascript all of which you can also +use in Minecraft. For example... + + /js Math.max( 6, 11 ) + +... returns the larger of the 2 numbers you give it (max is short for +maximum). While... + + /js Math.min( 6, 11 ) + +... returns the smaller of the 2 numbers. That's another thing - +functions can `return` stuff. You can store the result of a function +(what it returns) in a variable like this... + + /js var biggest = Math.max( 6, 11 ) + +... Now type... + + /js biggest + +... Not all Javascript functions return data but most do. As well as +the functions provided to you by the Javascript Language and +ScriptCraft, you can write your own functions like this... + + /js function whatTimeIsIt () { return new Date() } + +... Here you've created a new `function` called `whatTimeIsIt` and +told the function it should return a new `Date` object every time it's +called. You'll notice the above statement didn't actually do anything +- it certainly didn't display the current time. That's because all + you've done is is say what the function should do when it's called, + you haven't called it yet. To call the function... + + /js whatTimeIsIt() + +... The current time is displayed. Congrats! You've just written your +first Javascript function - you're well on your way to becoming a +Minecraft Modder. There are many functions for working with Text, +numbers and dates in Javascript... + + /js Math.random() + +... prints out a random number every time you call it. Try it! Then press +the `/` key then the UP Arrow key to repeat the last statement in your +in-game console. You'll see the number displayed is different each +time. Think of Math.random() as a Dice with many many sides. You can +rely on it to never return the same value twice. + +## Building stuff in Minecraft + +Now we get to the fun stuff - creating structures and buildings in +Minecraft. Building by hand is fun but tedious when you want to build +big - Towers, Castles and Fortresses. That's where ScriptCraft comes in. +ScriptCraft comes with a couple of javascript functions that can be +combined to build interesting things. Let's start small though to get a +feel for how ScriptCraft's building functions work. The function you'll +probably use most for building is called `box()` and - as its name +implies - it is used to create cubes and cuboids of any size. A cube is +a 3D shape whose sides are all the same length. A cuboid is a 3D shape +whose width, height and length can differ. + +![3D Shapes][img_3d_shapes] + +You can create a Cube or a Cuboid in ScriptCraft using the `box()` +function. You must tell the function what material you want the shape to +be made of. For example, in the game, point the cross hairs at the +ground, then type the following and hit enter... + + /js box( blocks.oak ) + +... This will change the targeted block to wood. What's happened here +is the `box()` function has created a single new wooden +block. `blocks` is another one of those *free* variables you get in +ScriptCraft, you can see a list of block materials by typing ... + + /js blocks. + +... then pressing the `TAB` key. Repeatedly pressing the `TAB` key +will cycle through all of the block materials. Alternatively, you can +see many more current materials and the numbers Minecraft uses for +them by visiting the [Minecraft Data Values][mcdv] site. + +## Common Block Materials + +In Minecraft Programming, Materials aren't known by their name, +instead numbers (sometimes 2 numbers) are used to indicate which +material should be used. For example the number 2 is grass, 1 is +cobblestone etc, while 5 is wood (oak). There are different types of +wood so the text '5:1' means Spruce, '5:2' means Birch and '5:3' means +Jungle wood. There are many different materials in the Minecraft world, the most +commonly used materials for building are: + + * '4' - Cobblestone or `blocks.cobblestone` + * '5' - Wooden Planks or `blocks.oak` + * '5:2' - Birch wood Planks (light wood) or `blocks.birch` + * '98' - Stone bricks or `blocks.brick.stone` + * '45' - Red bricks or `blocks.brick.red` + * '68' - Sign or `blocks.sign` + * '102' - Glass panes (for windows) or `blocks.glass_pane` + +You can create a single wooden block using the numeric values or the `blocks` variable. For example... + + /js box( '5' ) + +... and ... + + /js box( blocks.oak ) + +... both do exactly the same thing but I personally prefer `/js box( +blocks.oak )` because it's easier to remember. For reference, here is +a chart of all of the blocks (not items) in the Minecraft world... + +![Minecraft Data Values][img_dv] + +## Dimensions + +`box()` can do more than just +create single blocks - it can create cubes and cuboids of any +size. Take a look at the following picture which shows how shapes are +measured in 3D space. There are 3 dimensions (or sizes) to consider. + +1. Width +2. Height +3. Depth (or length) - not to be confused with how deep underground a +mine-shaft can go. Think of Depth (or length if you prefer) as how far +away you want something to extend. + +![Width, Height and Depth][img_whd] + +## More shapes + + * `box0( block, width, height, depth )` - creates an empty box (with the + insides hollowed out - perfect for dwellings. `box0` will remove both + the floor and ceiling too. + * `cylinder( block, radius, height )` - creates cylinders, perfect for + Chimneys. + * `cylinder0( block, radius, height )` - creates empty cylinders - + perfect for Towers. `cylinder0` will remove both the floor and + ceiling too. + * `prism( block, width, depth )` - creates a Prism - good for roofs. + * `prism0( block, width, depth )` - creates an empty prism. + +## The Drone Object + +ScriptCraft is a Minecraft Mod that lets you execute Javascript code +in the game. It also lets you write your own Mod in Javacript. One +such mod that comes bundled with ScriptCraft is called the `Drone` +mod. The `Drone` is an (invsible) object you create every time you +execute any of the building or movement functions. When you execute... + + /js box(5,3,2,4) + +... a new `Drone` object is created and does the work of building on +your behalf. Think of a `Drone` as something like a remote control +plane that can move about freely and build things for you. Moving the +Drone is easy... + +### Movement + + * `up( numberOfBlocks )` - moves the Drone Up. For example: `up()` + will move the Drone 1 block up. You can tell it how many blocks to + move if you want it to move more than one block. + * `down( numberOfBlocks )` - moves the Drone Down. + * `left( numberOfBlocks )` - moves the Drone Left. + * `right( numberOfBlocs )` - moves the Drone Right. + * `fwd( numberOfBlocs )` - moves the Drone Forward (away from the player). + * `back( numberOfBlocs )` - moves the Drone Back (towards the player) + * `turn( numberOfTurns )` - Turns the Drone Clock-wise (right). For example: + `turn()` will make the Drone turn right 90 degrees. `turn(2)` will + make the Drone turn twice so that it is facing in the opposite + direction. + +### Chaining - combining building and movement. + +You can make a Drone move around before and after building by +*daisy-chaining* the building and movement functions together. In the +game, point at the ground then type the following... + + /js up(1).box( blocks.oak ).fwd(3).box( blocks.oak ) + +A series of 2 boxes is created 3 blocks apart. + +![Two Boxes 3 blocks apart][img_2boxes] + +### Exercise - Build a simple dwelling + +OK. You know enough now about the `Drone` functions to be able to +build a simple dwelling. The dwelling should be a hollow building with +a sloped roof. *Don't worry about doors or windows for now*. The walls +should be made of Cobblestone ('4') and the roof made of wood ('5'). You can use +the following `Drone` functions to create a dwelling 7 blocks wide by +3 blocks high by 6 blocks long with a wooden sloped roof. It's up +to you to figure out how. + + * `up()` + * `box0()` + * `prism0()` + +Your dwelling should end up looking something like this... + +![Exercise Dwelling][img_ed] + +### Remembering where you started. + +Sometimes when you're building something big that requires lots of +manoeuvering by your Drone, you need to leave breadcrumbs as you go so +your `Drone` can return to where it started. Every new Drone has a +`'start'` checkpoint that it can return to by executing +`move('start')` ... + + /js box('5').up(3).left(4).box('1').turn(3).fwd(5).right().box('1').move('start') + +... A genius would have trouble figuring out how to get back +to where they started. Fortunately, they don't have to - the +`move('start')` function will take the Drone back to its starting +point. + + * `chkpt( breadCrumb )` - Leaves a mark at your Drone's current + location so it can return there later. Think of it as giving a name + to the place where your Drone is located. `chkpt` is short for + Check-Point - a place in a game where you usually save your + progress. + + * `move( breadCrumb )` - Moves your Drone to a location you named + using `chkpt()` . It brings your Drone back to the place where you + saved it. + +Both `chkpt()` and `mark()` are useful for when you want to build +complex things that require your Drone to move about a lot ( for +example, Castles, mansions, palaces, etc). + +## Saving your work + +You can build cool things using the in-game command-prompt and the +`/js` command but sooner or later you'll probably want to build +something more complex and save your commands so you can run them +again when you quit the game and start it up again. + +[Notepad++][np] Is a special text editor (like Notepad which comes +installed on every Windows machine) that is well suited for writing +code. If you don't already have it on your machine, you can [install +Notepad++ here][np]. I recommend using NotePad++ rather than plain old +Notepad because it understands Javascript. If you prefer coding on a +Macintosh, then [TextWrangler][twl] is a good programming editor which +also understands Javascript code. + +## Your First Minecraft Mod! + +So, You've learnt a little bit about Javascript and what the Drone() +object can do, let's use that knowledge to create a Minecraft Mod! + +Once you've installed Notepad++, Launch it, create a new file and type the following... + + exports.greet = function(player){ + player.sendMessage('Hi ' + player.name); + } + +... then save the file in a new directory +`craftbukkit/plugins/scriptcraft/plugins/{your_name}` (replace +{your_name} with your own name) and call the file `greet.js` (be sure +to change the file-type option to '*.* All Files' when saving or +NotePad++ will add a '.txt' extension to the filename. Now switch back +to the Minecraft game and type... + + /js refresh() + +... to reload all of the server plugins. Your mod has just been +loaded. Try it out by typing this command... + + /js greet(self) + +... it should display ... + + Hi {your-username-here} + +... where {your-username-here} will be replaced with your own +minecraft username. Congratulations - You've just written your very +first Minecraft Mod! With ScriptCraft installed, writing Minecraft +Mods is as simple as writing a new javascript function and saving it +in a file in the craftbukkit/plugins/scriptcraft/plugins +directory. This function will now be avaible every time you launch +minecraft. This is a deliberately trivial minecraft mod but the +principles are the same when creating more complex mods. + +The `exports` variable is a special variable you can use in your mod +to provide functions, objects and variables for others to use. If you +want to provide something for other programmers to use, you should +*export* it using the special `exports` variable. The syntax is +straightforward and you can use the same `exports` variable to export +one or more functions, objects or variables. For example... + +#### thrower.js + + exports.egg = function(player){ + player.throwEgg(); + } + exports.snowball = function(player){ + player.throwSnowball(); + } + +... is a plugin which provides 2 javascript functions called `egg()` +and `snowball()` which can be invoked from the in-game prompt like +this `/js egg(self)` or `/js snowball(self)`. + +## Parameters +If you want to change the `greet()` function so that it displays a +greeting other than 'Hi ' you can change the code in the `greet()` +function, or better still, you can use *Parameters*. Parameters are +values you provide to a function so that the function behaves +differently each time it is called. + +![greeting][img_greet] + +Change the `greet()` function so that it looks like this... + + exports.greet = function ( greeting , player) { + player.sendMessage( greeting + player.name ); + } + +... Save your greet.js file and issue the `/js refresh()` command in +minecraft. Now enter the following command in Minecraft... + + greet('Hello ',self); + +... Now try ... + + greet('Dia Dhuit ',self); + +... you should see the following messages in your chat window... + + Hello {your name} + Dia Dhuit {your name} + +... Parameters let you provide different values to functions each time +they're called. As you'll see later, Parameters are very useful when +changing the behaviour of MineCraft. + +## true or false + +Try entering each of the following statements and make a note of the +answers given by minecraft... + + /js 1 < 2 + + /js 1 > 2 + +... the answer given by the first statement ( `1 < 2` ) should be +`true` since 1 is less than 2. The `<` symbol - usually found near the +bottom right of your keyboard - means test to see if something is less +than another so `1 < 2` is a way of asking the computer "is 1 less +than 2 ?". This is a silly example of course since we know 1 is less +than 2 but when dealing with variables we might not know in advance +what its value is or whether it's greater than (bigger) or less than +(smaller) another number or value. The result of the 2nd statement (`1 > 2`) +should be `false` since 1 is not greater than 2. Now try this... + + /js 1 = 2 + +... The result won't be what you expected. You'll see an Error message +- that's OK. What's happened here is I've tried to test to see if 1 is +equal to 2 but I've made one of the most common mistakes even +experienced programmers make. If you want to test to see if two things +are the same, you use `==` that's two equals signs right next to each +other. Let's try again... + + /js 1 == 2 + +... this time you should get an answer `false` since 1 obviously isn't +equal to 2. These are the different *operators* used when comparing +things... + + * `<` Is less than ? + * `>` Is greater than ? + * `==` Is equal to ? + * `<=` Is less than or equal to ? + * `>=` Is greather than or equal to ? + * `!=` Is not equal to ? + +... try comparing some more numbers yourself - say for example, +compare the ages of your friends or siblings to your own age. + +## More fun with `true` or `false` +You can find out if you can Fly in minecraft by typing the following statement... + + /js self.allowFlight + +... the result will be `true` or `false` depending on whether you can +fly or not. You can turn on and off your ability to fly by setting +your `allowFlight` property to `true` or `false`. Try it... + + /js self.allowFlight = true + +... Now you can fly! To turn off flight... + + /js self.allowFlight = false + +... and you come crashing down to earth. This is just one example of +how `true` and `false` are used throughout ScriptCraft - these are +called `boolean` values - named after [George Boole][boole], a 19th Century +Maths Professor at University College Cork. There are plenty more +examples of boolean values in Minecraft. You can find out if monsters +are allowed in your minecraft world by typing the following +statement... + + /js self.location.world.allowMonsters + +... The result of this statement will be either `false` (Phew!) or +`true` (Yikes!) depending on how your server has been +configured. However, typing the following statement doesn't work as +expected... + + /js self.location.world.allowMonsters = true + +... This statement won't work as expected - it will give an Error +message. This is because sometimes we can read variables but we can't +change them the same way we read them (this is because of how +Javascript, Java and the CraftBukkit API work together). To turn on or +off the spawning of monsters, type the following... + + /js self.location.world.setSpawnFlags(false, true) + +... the `setSpawnFlags()` method takes 2 parameters, the first +parameter says whether or not monsters can spawn, and the 2nd says +whether or not Animals can spawn. (SIDENOTE: You may be wondering how +to change other aspects of the Minecraft game - pretty much all +aspects of the game can be changed. Changes are made using what are +called `API` calls - these are calls to functions and methods in +Minecraft - you can read more about these on the [CraftBukkit API +Reference][cbapi].) + +## ...and Again, and Again, and Again,... + +One of the things Computers are really good at is +repetition. Computers don't get tired or bored of doing the same thing +over and over again. Loops are handy, if you want to run the same +code over and over again, each time with a different value. + +### Counting to 100 + +At the in-game command prompt (hint: press 't') type the following then hit Enter... + + /js for (var i = 1 ; i <= 100 ; i = i + 1) { echo( i ); } + +... The above code will count from 1 to 100. The first thing you'll +notice if you run the above code is how quickly the count +happened. You're probably curious how long it would take to count to +1000. Try it out for yourself. Change the above line of code so that +it counts to 1000 instead of 100. If you're feeling adventurous, see +how long it takes to count to ten thousand, one hundred thousand or even one million. + +The `for` statement is useful when you want to repeat something over and over. It has 4 parts... + + 1. The initialiser: `var i = 1` - this happens once at the start of the loop. + 2. The test: `i <= 100` - this happens at the start of each run around the loop. If the test fails, then the loop ends. + 3. The increment: `i = i + 1` - this happens at the end of each run + around the loop. If you didn't have a statement here, the loop might + never finish. `i = i + 1` is often written as `i++` - it's shorter + and does basically the same thing. + 4. The body - everything that appears between the `{` and `}` (opening and closing curly braces). + + +`for` loops becomes very useful when you combine it with Arrays - +remember, an Array is just a list of things, for example - the players +connnected to a server, the worlds of a server and so on. + +### Saying "Hi!" to every player + +At the in-game command prompt type the following then hit Enter... + + /js for (var i = 0;i < server.onlinePlayers.length; i++){ server.onlinePlayers[i].sendMessage('Hi!'); } + +... Lets look at these statements in more detail. We had to enter the +statements on a single line at the in-game command prompt but the +statements could be written like this... + + var players = server.onlinePlayers; + for (var i = 0; i < players.length; i++) { + var player = players[i]; + player.sendMessage('Hi!'); + } + +... On the first line, a new variable `players` is created from the +server object's onlinePlayers property. `players` is more concise and +easier to type than the long-winded `server.onlinePlayers`. On the +second line, the for loop is declared, a counter variable `i` is set +to 0 (zero - arrays in javascript start at 0 not 1) and each time +around the loop is tested to see if it's less than the number of +players online. At the end of each run around the loop the `i` +variable is incremented (increased by 1) so that the next player can +be messaged. Inside the body of the for loop (everything between the +opening `{` and closing `}` curly braces) the `players[i]` expression +refers to the player in the players array at position[i]. Imagine +there are 4 players online on a minecraft server, the `players` array +might look like this... + + * players[0] = 'CrafterJohn' + * players[1] = 'MinerPaul' + * players[2] = 'ExplorerRingo' + * players[3] = 'TraderGeorge' + +... in this case `players.length` will be 4 (since there are 4 online +players), the for-loop will go around 4 times starting from position 0 +and going all the way up to position 3, sending a message to each of +the players in the array. It's time for a new scriptcraft +function. Open the `hi.js` file you created earlier (using NotePad++ , +TextWrangler or your editor of choice) and add the following code at +the bottom of the file... + + exports.hiAll = function (){ + var players = server.onlinePlayers; + for (var i = 0; i < players.length; i++) { + var player = players[i]; + player.sendMessage('Hi!'); + } + } + +... save the file, at the in-game command prompt type `reload` and +then type `/js hiAll()`. This will send the message `Hi!` to all of +the players connected to your server. You've done this using a `for` +loop and arrays. Arrays and `for` loops are used heavily in all types +of software, in fact there probably isn't any software that doesn't +use `for` loops and Arrays to get things done. + +## While Loops + +Another way to repeat things over and over is to use a `while` +loop. The following `while` loop counts to 100... + + var i = 1; + while (i <= 100){ + console.log( i ); + i = i + 1; + } + +A `while` loop will repeat until its condition is `false` - the +condition in the above example is `i <= 100` so while i is less than +or equal to 100 the code within the `while` block (everything between +the starting `{` and ending `}` curly braces) will run. It's important +that you change the variable being tested in a while loop, otherwise +the while loop will never it - it will run forever. Try running the +following code... + + /js var i = 1; while (i <= 100){ echo( i ); } + +The code above will contine printing out the number 1 until the end of +time (or until you unplug your computer). That's because the `i` +variable is never incremented (remember - incrementing just means +adding 1 to it) so i will always be 1 and never changes meaning the +loop goes on forever. Again - this is a mistake even experienced programmers sometimes make. + +Just like `for` loops, `while` loops can be also be used to loop +through arrays. The following loop prints out all of the players on +the server... + + var players = server.onlinePlayers; + var i = 0; + while ( i < players.length ) { + console.log( players[i] ); + i = i + 1; + } + +... whether you chose to use a `for` loop or a `while` loop is largely +a matter of personal taste, `for` loops are more commonly used with +Arrays but as you see from the example above, `while` loops can also +loop over Arrays. + +## `utils.foreach()` - Yet another way to process Arrays + +Both the `for` statement and `while` statement are standard commonly +used javascript statements used for looping. ScriptCraft also comes +with a special function for looping called `utils.foreach()`. +utils.foreach() is a convenience function, you don't have to use it if +you prefer the syntax of javascript's `for` and `while` +loops. utils.foreach() takes two parameters... + + 1. An array + 2. A function which will be called for each item in the array. + +...that's right, you can pass functions as parameters in javascript! +Let's see it in action, the following code will `console.log()` (print) the +name of each online player in the server console window... + + utils.foreach( server.onlinePlayers, console.log ); + +... in the above example, the list of online players is processed one +at a time and each item (player) is passed to the `console.log` +function. Note here that I used `console.log` not `console.log()`. The round braces +() are used to call the function. If I want to pass the function as a +parameter, I just use the function name without the round braces. The +above example uses a named function which already exists ( `console.log` ), +you can also create new functions on-the-fly and pass them to the +utils.foreach() function... + + /* + give every player the ability to fly. + */ + var utils = require('utils'); + utils.foreach( server.onlinePlayers, + function (player) { + player.setAllowFlight(true); + } + ); + +... Another example, this time each player will hear a Cat's Meow... + + /* + Play a Cat's Meow sound for each player. + */ + var utils = require('utils'); + utils.foreach( server.onlinePlayers, + function (player) { + player.playSound(player.location, + org.bukkit.Sound.CAT_MEOW, + 1, + 1); + + } + ); + +### Exercise +Try changing the above function so that different sounds are played +instead of a Cat's Meow. You'll need to lookup the [CraftBukkit API's +Sound class][soundapi] to see all of the possible sounds that can be +played. + +Loops are a key part of programming in any language. Javascript +provides `for` and `while` statements for looping and many javascript +libraries also provide their own custom looping functions. You should +use what you feel most comfortable with. + +## Putting `for` loops to use - Building a Skyscraper + +For loops can be used to build enormous structures. In this next +exercise I'm going to use a for loop to build a skyscraper. This +skyscraper will be made of Glass and Steel (just like most skyscrapers +in real-life). The first thing to do is see what a single floor of +the skyscraper will look like. Place a block (of any type) where you +want to eventually build the skyscraper, then while your cursor is +pointing at the block, type the following into the in-game prompt... + + /js var drone = box(blocks.iron,20,1,20).up().box0(blocks.glass_pane,20,3,20).up(3) + +... you should a large (20x20) iron floor with 3 block high glass all around. + +![skyscraper-floor.png][img_ssf] + +... A skyscraper with just a single floor isn't much of a skyscraper +so the next step is to repeat this over and over. This is where `for` +loops come in. Open your favorite text editor and create a new file in +your scriptcraft/plugins/{your-name} directory, name the file `myskyscraper.js`, then +type the following... + + exports.myskyscraper = function(floors) + { + floors = floors || 10; // default number of floors is 10 + this.chkpt('myskyscraper'); // saves the drone position so it can return there later + for (var i = 0; i < floors; i++) + { + this.box(blocks.iron,20,1,20).up().box0(blocks.glass_pane,20,3,20).up(3); + } + return this.move('myskyscraper'); // return to where we started + }; + + load('../drone/drone.js'); + Drone.extend('myskyscraper',myskyscraper); + +... so this takes a little explaining. First I create a new function +called myskyscraper that will take a single parameter `floors` so that +when you eventually call the `myskyscraper()` function you can tell it +how many floors you want built. The first statement in the function +`floors = floors || 10;` just sets floors to 10 if no parameter is +supplied. The next statement `this.chkpt('myskyscraper')` just saves +the position of the Drone so it can eventually return to where it +started when finished building (I don't want the drone stranded atop +the skyscraper when it's finished). Then comes the `for` loop. I loop +from 0 to `floors` and each time through the loop I build a single +floor. When the loop is done I return the drone to where it started. +The last 2 lines load the drone module (it must be loaded before I can +add new features to it) and the last line extends the 'Drone' object +so that now it can build skyscrapers among other things. Once you've +typed in the above code and saved the file, type `reload` in your +in-game prompt, then type ... + + /js myskyscraper(2); + +... A two-story skyscraper should appear. If you're feeling +adventurous, try a 10 story skyscraper! Or a 20 story skyscraper! +Minecraft has a height limit (256 blocks from bedrock) beyond which +you can't build. If you try to build higher than this then building +will stop at that height. + +![skyscraper][img_ss] + +I'll leave it as an exercise to the reader to create a city block of +skyscrapers, 5 blocks apart using a for loop. Once you've figured +that out, creating an entire city of blocks of skyscrapers is the next +logical step. Of course, Minecraft doesn't have the same constraints +as real-world densely populated areas so let your imagination go wild. + +## Making Decisions + +All the programs we have seen so far have been fairly predictable - they went +straight through the statements, and then went back to the beginning again. This is +not very useful. In practice the computer would be expected to make decisions and +act accordingly. The javascript statement used for making decisions is `if`. +While standing on the ground in-game, type the following at the command prompt... + + /js if ( self.flying ) { echo('Hey, You are flying!'); } + +... No message should appear on screen. That is - `Hey, You are +flying!` should *not* appear on screen. Now double-tap the `space` +bar to start flying in-game (tap the space bar twice in rapid +succession), then press and hold space to rise above the ground. Now +enter the same statement again (If you don't want to type the same +statement again, just press `/` then press the `UP` cursor key on your +keyboard, the statement you entered previously should reappear. + + /js if ( self.flying ) { echo('Hey, You are flying!'); } + +... this time the following message should have appeared on your screen... + + Hey, You are flying! + +The `if` statement tests to see if something is `true` or `false` and +if `true` then the block of code between the curly braces ( `{` and +`}` ) is executed - but only if the condition is true. The condition +in the above example is `self.flying` which will be `true` if you are +currently flying or `false` if you aren't. + +What if you wanted to display a message only if a condition is *not* +true ? For example to only display a message if the player is *not* +flying... + + /js if ( ! self.flying ) { echo ('You are not flying.'); } + +... This code differs in that now there's a `!` (the exclamation mark) +before `self.flying`. The `!` symbol negates (returns the opposite of) +whatever follows it. + +What if you want to display a message in both cases - whether you're +flying or not? This is where the `if - else` construct comes in handy. +Open your favorite editor and type the following code into a new file +in your scriptcraft/plugins directory... + + function flightStatus(player) + { + if ( player.flying ) + { + player.sendMessage( 'Hey, You are flying!' ); + } + else + { + player.sendMessage( 'You are not flying.' ); + } + } + +... now type `/reload` at the in-game prompt then type `/js +flightStatus(self)` and an appropriate message will appear based on +whether or not you're currently flying. Type the `/js flightStatus()` +command while on the ground and while flying. The message displayed in +each case should be different. + +## Event-Driven programming + +So far we've written code which executes when you invoke the `/js ` +command. What if - for example - you want to have some special +behaviour which occurs when a player joins the game? What if you +wanted to display a custom welcome message (in addition to the MotD - +message-of-the-day which is configurable in your server.properties +file) ? This is where *Event-Driven Programming* comes +in. Event-Driven Programming is just a fancy way of saying 'Do this +when that happens' where 'this' is a function you define, and 'that' +is some event which occurs. There are hundreds of events in the +minecraft game... + + * Every time someone joins the server - that's an event! + * Every time someone breaks a block - that's an event! + * Every time someone shoots an arrow - that's an event! and so on... + +You can write a function which will be called whenever a specific type +of event occurs, it's probably best to illustrate this by example. The +following code sends a message to any player who breaks a block in the +game... + + events.on('block.BlockBreakEvent', function (listener, event) { + var breaker = event.player; + breaker.sendMessage('You broke a block'); + }); + +The `events.on()` function is how you *register* a function which you +want to be called whenever a particular type of event occurs. In the +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 +in turn takes 2 parameters. The `event` object has all the information +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 +the 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 +`scriptcraft/plugins` directory then type `/js refresh()` to reload +scriptcraft. Then break a block in the game and you should see the +message 'You broke a block'. + +There are many types of events you can listen for in Minecraft. You can +browse [all possible Bukkit events][bkevts] (click the 'Next +Package' and 'Previous Package' links to browse). + +It's important to note that when browsing the Bukkit API's +[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( listener, event) { + ... + }); + +or an abbreviated name in string form... + + events.on('entity.EntityShootBowEvent', function( listener, 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. ... + + events.on ( net.yourdomain.events.YourEvent, function(listener, event ) { + ... + }); + +### Stop listening to events. + +If you want an event handler to only execute once, you can remove the handler like this... + + events.on('block.BlockBreakEvent', function(listener, evt) { + var breaker = evt.player; + breaker.sendMessage('You broke a block'); + evt.handlers.unregister( listener ); + }); + +The `evt.handlers.unregister( listener );` statement will remove this +function from the list of listeners for this event. + +## Keeping Score - Lookup tables in Javascript + +In the *Event-Driven Programming* section, I defined a function which +displayed a message to players every time they broke a block. Imagine +if I wanted to keep a count of how many blocks each player has broken? +This is where Javascript's Objecct literals come in handy. An object +literal in javascript is simply a way of creating a new Object +on-the-fly in your code. This is an example... + + var myNewObject = { name: 'walter', country: 'Ireland' }; + +... I created a new object with two properties 'name' and +'country'. The notation used to create this object is called JSON +which is short for JavaScript Object Notation. If I want to find out +the 'country' property of the myNewObject variable there are a few +ways I can do it... + + var playerCountry = myNewObject.country; + +... or ... + + var playerCountry = myNewObject['country'] + +... JavaScript lets you access any object property using either +dot-notation ( `object.property` ) or by index ( `object['property']` +). The result in both cases is the same - playerCountry will be +'Ireland'. When accessing the object by indexing, the property doesn't +even have to be a string literal - it can be a variable like this... + + var propertyName = 'country'; + var propertyValue = myNewObject[propertyName]; + +... in the above example, the propertyName variable is used when +indexing. What this means is that every object in JavaScript can act +like a lookup table. What's a lookup table? A table you 'look up' of +course. This is a table of names and scores... + + Name Score + -------- ----- + walter 5 + tom 6 + jane 8 + bart 7 + +... If I want to find Jane's score, I look *down* the list of names in +the name column until I find 'jane' then look *across* to get her +score. In Javascript, an object which stored such a table would look +like this... + + var scoreboard = { + walter: 5, + tom: 6, + jane: 8, + bart: 7 + }; + +... and if I wanted to write a function which took a player name as a +parameter and returned their score, I'd do it like this... + + function getScore(player){ + return scoreboard[ player ]; + } + +... I might call such a function like this... + + var janesScore = getScore('jane'); // returns 8 + +... putting it all together, a hypothetical scoreboard.js mdoule might +look something like this... + + var utils = require('utils'); + var scores = {}; + + exports.initialise = function(names){ + scores = {}; + utils.foreach(names, function(name){ + scores[name] = 0; + }); + }; + + /* changes score by diff e.g. to add 6 to the player's current score + updateScore('walter',6); // walter's new score = 5 + 6 = 11. + */ + exports.updateScore = function(name, diff){ + scores[name] += diff; + }; + + exports.getScore = function(name){ + return scores[name]; + }; + +## Counting block break events for each player + +I can use a Javascript lookup table (a plain old Javascript object) to +keep a count of how many blocks each player has broken ... + +#### block-break-counter.js + + var breaks = {}; + // every time a player joins the game reset their block-break-count to 0 + events.on('player.PlayerJoinEvent', function(listener, event){ + breaks[event.player] = 0; + }); + events.on('block.BlockBreakEvent', function(listener, event){ + var breaker = event.player; + var breakCount = breaks[breaker.name]; + breakCount++; // increment the count. + breaks[breaker.name] = breakCount; + + breaker.sendMessage('You broke ' + breakCount + ' blocks'); + + }); + +With a little more work, you could turn this into a game where players +compete against each other to break as many blocks as possible within +a given time period. + +## Next Steps + +This guide is meant as a gentle introduction to programming and +modding Minecraft using the Javascript Programming Language. +Javascript is a very powerful and widely-used programming language and +there are many more aspects and features of the language which are not +covered here. If you want to dive deeper into programming and modding +minecraft, I recommend reading the accompanying [ScriptCraft API +reference][api] which covers all of the ScriptCraft functions, objects +and methods. I also recommend reading the source code to some of the +existing scriptcraft add-ons, the *chat* module ( +`scriptcraft/plugins/chat/color.js` ) is a good place to start, followed by +[Anatomy of a ScriptCraft Plug-in][ap]. The online [Craftbukkit API +Reference][cbapi] provides lots of valuable information about the +different objects and methods available for use by ScriptCraft. + + +[buk]: http://wiki.bukkit.org/Setting_up_a_server +[dlbuk]: http://dl.bukkit.org/ +[sc-plugin]: http://scriptcraftjs.org/download/ +[ce]: http://www.codecademy.com/ +[mcdv]: http://www.minecraftwiki.net/wiki/Data_values +[np]: http://notepad-plus-plus.org/ +[cbapi]: http://jd.bukkit.org/beta/apidocs/ +[boole]: http://en.wikipedia.org/wiki/George_Boole +[soundapi]: http://jd.bukkit.org/beta/apidocs/org/bukkit/Sound.html +[ap]: Anatomy-of-a-Plugin.md +[api]: API-Reference.md +[twl]: http://www.barebones.com/products/textwrangler/ +[bkevts]: http://jd.bukkit.org/dev/apidocs/org/bukkit/event/package-summary.html +[img_echo_date]: img/ypgpm_echo_date.png +[img_3d_shapes]: img/ypgpm_3dshapes.jpg +[img_whd]: img/ypgpm_whd.jpg +[img_dv]: img/ypgpm_datavalues.png +[img_ed]: img/ypgpm_ex_dwell.png +[img_2boxes]: img/ypgpm_2boxes.png +[img_cr]: img/ypgpm_mc_cr.png +[img_greet]: img/ypgpm_greet.png +[img_ssf]: img/skyscraper_floor.png +[img_ss]: img/skyscraper.png +