diff --git a/build.xml b/build.xml
index d82e4bb..f9988f5 100644
--- a/build.xml
+++ b/build.xml
@@ -7,13 +7,6 @@
-
-
-
-
@@ -144,7 +137,7 @@ Walter Higgins
-
+
@@ -157,6 +150,6 @@ Walter Higgins
-
+
diff --git a/docs/API-Reference.md b/docs/API-Reference.md
index 7119a64..4caef0f 100644
--- a/docs/API-Reference.md
+++ b/docs/API-Reference.md
@@ -117,6 +117,8 @@ Walter Higgins
* [Example Plugin #7 - Listening for events, Greet players when they join the game.](#example-plugin-7---listening-for-events-greet-players-when-they-join-the-game)
* [Arrows Plugin](#arrows-plugin)
* [Usage:](#usage-6)
+ * [Spawn Plugin](#spawn-plugin)
+ * [Usage](#usage-7)
* [alias Plugin](#alias-plugin)
* [Examples](#examples-2)
* [Classroom Plugin](#classroom-plugin)
@@ -135,6 +137,10 @@ Walter Higgins
* [Example](#example-1)
* [SnowballFight mini-game](#snowballfight-mini-game)
* [Description](#description-2)
+ * [Cow Clicker Mini-Game](#cow-clicker-mini-game)
+ * [How to Play](#how-to-play)
+ * [Rules](#rules)
+ * [Gameplay Mechanics](#gameplay-mechanics)
## Modules in Scriptcraft
@@ -2340,6 +2346,18 @@ All of the above functions can take an optional player object or name
as a parameter. For example: `/js arrows.explosive('player23')` makes
player23's arrows explosive.
+## Spawn Plugin
+
+Allows in-game operators to easily spawn creatures at current location.
+
+### Usage
+
+ /jsp spawn cow
+ /jsp spawn sheep
+ /jsp spawn wolf
+
+See for a list of possible entities (creatures) which can be spawned.
+
## alias Plugin
The alias module lets players and server admins create their own
@@ -2621,3 +2639,44 @@ player returns to their previous mode of play (creative or
survival). Create a small arena with a couple of small buildings for
cover to make the game more fun.
+## Cow Clicker Mini-Game
+
+### How to Play
+
+At the in-game prompt type `jsp cowclicker` to start or stop
+playing. Right-Click on Cows to score points. No points for killing
+cows (hint: use the same keyboard keys you'd use for opening doors).
+
+Every time you click a cow your score increases by 1 point. Your score
+is displayed in a side-bar along the right edge of of the screen.
+
+
+
+### Rules
+
+ * You can join and leave the Cow Clicker game at any time by typing
+ `/jsp cowclicker` at the in-game prompt.
+
+ * Once you leave the game, your score is reset to zero.
+
+ * You can disconnect from the server and your score will be saved for
+ the next time you join.
+
+### Gameplay Mechanics
+
+This is meant as a trivially simple use of the [Bukkit Scoreboard
+API][bukscore]. There are many things you'll want to consider when constructing
+your own mini-game...
+
+ * Is the game itself a long-lived game - that is - should players and
+ scores be persisted (stored) between server restarts?
+
+ * What should happen when a player quits the server - should this also be
+ understood as quitting the mini-game?
+
+ * What should happen when a player who was previously playing the
+ mini-game, joins the server - should they automatically resume the
+ mini-game?
+
+[bukscore]: http://jd.bukkit.org/beta/apidocs/org/bukkit/scoreboard/package-summary.html
+
diff --git a/docs/Using-Java-APIs-In-Javascript.md b/docs/Using-Java-APIs-In-Javascript.md
index f295159..cfc2cc4 100644
--- a/docs/Using-Java-APIs-In-Javascript.md
+++ b/docs/Using-Java-APIs-In-Javascript.md
@@ -35,11 +35,11 @@ using the more succinct...
it is easier to read. The important thing to remember when using the
Bukkit (or any Java API) from Javascript is that for any Java Bean, a
property called `propertyName` will have a getter called
-`getPropertyName()` and a setter called `setPropertyName`. From this
+`getPropertyName()` and a setter called `setPropertyName()`. From this
rule you can infer what any Bukkit class properties are. For example,
the [Bukkit Player][bukpl] object has the following methods...
- * float getWalSpeed()
+ * float getWalkSpeed()
* void setWalkSpeed(float speed)
... so from this you can infer that every Player object has a
@@ -61,7 +61,7 @@ the world in which a player is located...
If you're new to Java and the [Bukkit API][bukapi] is the first time
you've browsed Java documentation, you may be wondering where the
`location` property came from - the `location` property is "inherited"
-by one of the Player classes super-classes. You'll see the
+from one of the Player class's super-classes (it's ancestors). You'll see the
`getLocation()` method listed under a section titled **Methods
inherited from interface org.bukkit.entity.Entity** in the
[Player][bukpl] javadoc page.
diff --git a/docs/img/cowclicker.png b/docs/img/cowclicker.png
new file mode 100644
index 0000000..43e2fe9
Binary files /dev/null and b/docs/img/cowclicker.png differ
diff --git a/docs/release-notes.md b/docs/release-notes.md
index 9445e24..5969b29 100644
--- a/docs/release-notes.md
+++ b/docs/release-notes.md
@@ -1,3 +1,25 @@
+# 2014 01 12
+
+## Important
+The ScriptCraft.jar file has been renamed scriptcraft.jar (see bug fix
+details below). This means that you will have to remove the existing
+`plugins/ScriptCraft.jar` file if present.
+
+Bug Fix: On Mac OS, the plugins/scriptcraft directory is copied to
+plugins/ScriptCraftPlugin the 2nd time ScriptCraftPlugin is loaded.
+This has been fixed by changing the plugin name from ScriptCraftPlugin
+to scriptcraft. The jar file has also been rename from
+ScriptCraft.jar to scriptcraft.jar.
+
+New command: `jsp spawn` lets in-game operators spawn any type of
+entity. For example `/jsp spawn cow` will spawn a cow at the in-game
+operator's current location.
+
+New minigame: Cow Clicker. A simple demonstration of using Bukkit's
+Scoreboard API. Players click cows to score points. Scores are
+displayed in a side bar on screen. Players join or leave the game by
+typing `/jsp cowclicker` at the in-game prompt.
+
# 2014 01 05
Bug Fix: On Mac OS, alias plugin caused Exceptions due to missing
diff --git a/src/docs/javascript/generateTOC.js b/src/docs/javascript/generateTOC.js
index 5724472..f2fe8f8 100644
--- a/src/docs/javascript/generateTOC.js
+++ b/src/docs/javascript/generateTOC.js
@@ -1,5 +1,12 @@
args = args.slice(1);
+// wph 20140105 trim not availabe in String on Mac OS.
+if (typeof String.prototype.trim == 'undefined'){
+ String.prototype.trim = function(){
+ return this.replace(/^\s+|\s+$/g,'');
+ };
+}
+
var template = args[0];
var BufferedReader = java.io.BufferedReader;
diff --git a/src/main/java/net/walterhiggins/scriptcraft/ScriptCraftPlugin.java b/src/main/java/net/walterhiggins/scriptcraft/ScriptCraftPlugin.java
index bbdfae3..6d6b16e 100644
--- a/src/main/java/net/walterhiggins/scriptcraft/ScriptCraftPlugin.java
+++ b/src/main/java/net/walterhiggins/scriptcraft/ScriptCraftPlugin.java
@@ -29,7 +29,7 @@ public class ScriptCraftPlugin extends JavaPlugin implements Listener
/**
* Unzips bundled javascript code.
*/
- private void unzipJS()
+ private void unzipJS() throws IOException
{
//
// does the js-plugins directory exist?
@@ -37,9 +37,13 @@ public class ScriptCraftPlugin extends JavaPlugin implements Listener
File jsPlugins = new File(JS_PLUGINS_DIR);
if (!jsPlugins.exists())
{
- getLogger().finest("Directory " + JS_PLUGINS_DIR + " does not exist.");
- getLogger().finest("Initializing " + JS_PLUGINS_DIR + " directory with contents from plugin archive.");
- jsPlugins.mkdir();
+ getLogger().info("Directory " + jsPlugins.getCanonicalPath() + " does not exist.");
+ getLogger().info("Initializing " + jsPlugins.getCanonicalPath() + " directory with contents from plugin archive.");
+ try{
+ jsPlugins.mkdirs();
+ }catch(Exception e){
+ throw new RuntimeException("Failed to create directory " + jsPlugins.getCanonicalPath() + ":" + e.getMessage());
+ }
}
ZipInputStream zis = new ZipInputStream(getResource(JS_PLUGINS_ZIP));
@@ -48,7 +52,7 @@ public class ScriptCraftPlugin extends JavaPlugin implements Listener
while ( ( entry = zis.getNextEntry() ) != null)
{
String filename = entry.getName();
- //File newFile = new File(jsPlugins.getName() + File.separator + filename);
+
File newFile = new File(jsPlugins, filename);
//create all non exists folders
@@ -59,17 +63,23 @@ public class ScriptCraftPlugin extends JavaPlugin implements Listener
//
// only write out to file if zip entry is newer than file
//
+ String reason = null;
long zTime = entry.getTime();
boolean unzip = false;
- if (!newFile.exists())
+ if (!newFile.exists()){
+ reason = "NE";
unzip = true;
+ }
else{
long fTime = newFile.lastModified();
- if (zTime > fTime)
+ if (zTime > fTime){
+ reason = "" + new Long((zTime-fTime)/3600000) + "h";
unzip = true;
+ }
+
}
if (unzip){
- getLogger().info("Unzipping " + newFile.getCanonicalPath());
+ getLogger().info("Unzipping " + newFile.getCanonicalPath() + " (" + reason + ")" );
FileOutputStream fout = new FileOutputStream(newFile);
for (int c = zis.read(); c != -1; c = zis.read()) {
fout.write(c);
@@ -90,9 +100,9 @@ public class ScriptCraftPlugin extends JavaPlugin implements Listener
@Override
public void onEnable()
{
- unzipJS();
FileReader reader = null;
try{
+ unzipJS();
ScriptEngineManager factory = new ScriptEngineManager();
File bootScript = new File(JS_PLUGINS_DIR + "/lib/scriptcraft.js");
this.engine = factory.getEngineByName("JavaScript");
@@ -103,6 +113,7 @@ public class ScriptCraftPlugin extends JavaPlugin implements Listener
}catch(Exception e){
e.printStackTrace();
+ this.getLogger().severe(e.getMessage());
}finally {
if (reader != null){
try {
diff --git a/src/main/javascript/lib/js-patch.js b/src/main/javascript/lib/js-patch.js
new file mode 100644
index 0000000..4403bbc
--- /dev/null
+++ b/src/main/javascript/lib/js-patch.js
@@ -0,0 +1,33 @@
+
+module.exports = function($){
+
+ // wph 20140105 trim not availabe in String on Mac OS.
+ if (typeof String.prototype.trim == 'undefined'){
+ String.prototype.trim = function(){
+ return this.replace(/^\s+|\s+$/g,'');
+ };
+ }
+
+ $.setTimeout = function( callback, delayInMillis){
+ /*
+ javascript programmers familiar with setTimeout know that it expects
+ a delay in milliseconds. However, bukkit's scheduler expects a delay in ticks
+ (where 1 tick = 1/20th second)
+ */
+ var bukkitTask = server.scheduler.runTaskLater(__plugin, callback, delayInMillis/50);
+ return bukkitTask;
+ };
+ $.clearTimeout = function(bukkitTask){
+ bukkitTask.cancel();
+ };
+
+ $.setInterval = function(callback, intervalInMillis){
+ var delay = intervalInMillis/ 50;
+ var bukkitTask = server.scheduler.runTaskTimer(__plugin, callback, delay, delay);
+ return bukkitTask;
+ };
+ $.clearInterval = function(bukkitTask){
+ bukkitTask.cancel();
+ };
+};
+
diff --git a/src/main/javascript/lib/persistence.js b/src/main/javascript/lib/persistence.js
new file mode 100644
index 0000000..52614e1
--- /dev/null
+++ b/src/main/javascript/lib/persistence.js
@@ -0,0 +1,37 @@
+
+var _dataDir = null;
+var _persistentData = {};
+
+module.exports = function( rootDir, $ ){
+
+ _dataDir = new java.io.File( rootDir, 'data');
+
+ $.persist = function(name, data, write){
+ var i, dataFromFile;
+ if (typeof data == 'undefined')
+ data = {};
+ if (typeof write == 'undefined')
+ write = false;
+ if (!write){
+ dataFromFile = $.load(_dataDir.canonicalPath + '/' + name + '-store.json');
+ if (dataFromFile){
+ for (i in dataFromFile){
+ data[i] = dataFromFile[i];
+ }
+ }
+ }else{
+ // flush data to file
+ $.save(data, _dataDir.canonicalPath + '/' + name + '-store.json');
+ }
+ _persistentData[name] = data;
+ return data;
+ };
+
+ $.addUnloadHandler(function(){
+ for (var name in _persistentData){
+ var data = _persistentData[name];
+ $.save(data, _dataDir.canonicalPath + '/' + name + '-store.json');
+ }
+ });
+};
+
diff --git a/src/main/javascript/lib/plugin.js b/src/main/javascript/lib/plugin.js
index 0b8cb47..d41a0ef 100644
--- a/src/main/javascript/lib/plugin.js
+++ b/src/main/javascript/lib/plugin.js
@@ -3,23 +3,6 @@ var console = require('./console');
var File = java.io.File;
var FileWriter = java.io.FileWriter;
var PrintWriter = java.io.PrintWriter;
-
-/*
- Save a javascript object to a file (saves using JSON notation)
-*/
-var _save = function(object, filename){
- var objectToStr = null;
- try{
- objectToStr = JSON.stringify(object,null,2);
- }catch(e){
- print("ERROR: " + e.getMessage() + " while saving " + filename);
- return;
- }
- var f = (filename instanceof File) ? filename : new File(filename);
- var out = new PrintWriter(new FileWriter(f));
- out.println( objectToStr );
- out.close();
-};
/*
plugin management
*/
@@ -34,25 +17,18 @@ var _plugin = function(/* String */ moduleName, /* Object */ moduleObject, isPer
return _plugins[moduleName].module;
var pluginData = {persistent: isPersistent, module: moduleObject};
- moduleObject.store = moduleObject.store || {};
+ if (typeof moduleObject.store == 'undefined')
+ moduleObject.store = {};
+
_plugins[moduleName] = pluginData;
if (isPersistent){
- if (!moduleObject.store){
- moduleObject.store = {};
- }
- var loadedStore = load(dataDir.canonicalPath + "/" + moduleName + "-store.json");
- if (loadedStore){
- for (var i in loadedStore){
- moduleObject.store[i] = loadedStore[i];
- }
- }
+ moduleObject.store = persist(moduleName, moduleObject.store);
}
return moduleObject;
};
exports.plugin = _plugin;
-exports.save = _save;
var scriptCraftDir = null;
var pluginDir = null;
@@ -65,7 +41,7 @@ exports.autoload = function(dir) {
dataDir = new File(dir, "data");
var _canonize = function(file){
- return "" + file.getCanonicalPath().replaceAll("\\\\","/");
+ return '' + file.canonicalPath.replaceAll("\\\\","/");
};
/*
recursively walk the given directory and return a list of all .js files
@@ -78,9 +54,7 @@ exports.autoload = function(dir) {
if (file.isDirectory()){
_listSourceFiles(store,file);
}else{
- if ((file.getCanonicalPath().endsWith(".js")
- || file.getCanonicalPath().endsWith(".coffee"))
- ) {
+ if ( file.canonicalPath.endsWith('.js') ){
store.push(file);
}
}
@@ -97,11 +71,11 @@ exports.autoload = function(dir) {
var len = sourceFiles.length;
if (config.verbose)
- console.info(len + " scriptcraft plugins found.");
+ console.info(len + ' scriptcraft plugins found.');
for (var i = 0;i < len; i++){
var pluginPath = _canonize(sourceFiles[i]);
if (config.verbose)
- console.info("Loading plugin: " + pluginPath);
+ console.info('Loading plugin: ' + pluginPath);
var module = {};
try {
module = require(pluginPath);
@@ -119,13 +93,3 @@ exports.autoload = function(dir) {
_reload(pluginDir);
};
-addUnloadHandler(function(){
- //
- // save all plugins which have persistent data
- //
- for (var moduleName in _plugins){
- var pluginData = _plugins[moduleName];
- if (pluginData.persistent)
- _save(pluginData.module.store, dataDir.canonicalPath + "/" + moduleName + "-store.json");
- }
-});
diff --git a/src/main/javascript/lib/require.js b/src/main/javascript/lib/require.js
index 5bce81e..30923cb 100644
--- a/src/main/javascript/lib/require.js
+++ b/src/main/javascript/lib/require.js
@@ -187,11 +187,12 @@ When resolving module names to file paths, ScriptCraft uses the following rules.
{
var file = resolveModuleToFile(path, parentFile);
if (!file){
- var errMsg = java.lang.String
- .format("require() failed to find matching file for module '%s' " +
- "while searching directory '%s' and paths %s.",
- [path, parentFile.canonicalPath, JSON.stringify(modulePaths)]);
- console.warn(errMsg);
+ var errMsg = '' + java.lang.String.format("require() failed to find matching file for module '%s' " +
+ "in working directory '%s' ", [path, parentFile.canonicalPath]);
+ if (! ( (''+path).match(/^\./) )){
+ errMsg = errMsg + ' and not found in paths ' + JSON.stringify(modulePaths);
+ }
+ logger.warning(errMsg);
throw new Error(errMsg);
}
var canonizedFilename = _canonize(file);
@@ -242,7 +243,7 @@ When resolving module names to file paths, ScriptCraft uses the following rules.
.apply(moduleInfo.exports, /* this */
parameters);
} catch (e){
- console.error("Error:" + e + " while executing module " + canonizedFilename);
+ logger.severe('Error:' + e + ' while executing module ' + canonizedFilename);
throw e;
}
if (verbose)
diff --git a/src/main/javascript/lib/scriptcraft.js b/src/main/javascript/lib/scriptcraft.js
index 6e7e854..6fa7e45 100644
--- a/src/main/javascript/lib/scriptcraft.js
+++ b/src/main/javascript/lib/scriptcraft.js
@@ -422,7 +422,9 @@ function __onEnable (__engine, __plugin, __script)
return ;
var File = java.io.File
,FileReader = java.io.FileReader
- ,BufferedReader = java.io.BufferedReader;
+ ,BufferedReader = java.io.BufferedReader
+ ,PrintWriter = java.io.PrintWriter
+ ,FileWriter = java.io.FileWriter;
var _canonize = function(file){
return "" + file.getCanonicalPath().replaceAll("\\\\","/");
@@ -432,6 +434,23 @@ function __onEnable (__engine, __plugin, __script)
var jsPluginsRootDir = libDir.parentFile; // scriptcraft
var jsPluginsRootDirName = _canonize(jsPluginsRootDir);
+ /*
+ Save a javascript object to a file (saves using JSON notation)
+ */
+ var _save = function(object, filename){
+ var objectToStr = null;
+ try{
+ objectToStr = JSON.stringify(object,null,2);
+ }catch(e){
+ print("ERROR: " + e.getMessage() + " while saving " + filename);
+ return;
+ }
+ var f = (filename instanceof File) ? filename : new File(filename);
+ var out = new PrintWriter(new FileWriter(f));
+ out.println( objectToStr );
+ out.close();
+ };
+
var _loaded = {};
/*
Load the contents of the file and evaluate as javascript
@@ -487,7 +506,7 @@ function __onEnable (__engine, __plugin, __script)
/*
now that load is defined, use it to load a global config object
*/
- var config = _load(new File(jsPluginsRootDir, "data/global-config.json" ));
+ var config = _load(new File(jsPluginsRootDir, 'data/global-config.json' ));
if (!config)
config = {verbose: false};
global.config = config;
@@ -510,27 +529,6 @@ function __onEnable (__engine, __plugin, __script)
}
};
- global.setTimeout = function( callback, delayInMillis){
- /*
- javascript programmers familiar with setTimeout know that it expects
- a delay in milliseconds. However, bukkit's scheduler expects a delay in ticks
- (where 1 tick = 1/20th second)
- */
- var bukkitTask = server.scheduler.runTaskLater(__plugin, callback, delayInMillis/50);
- return bukkitTask;
- };
- global.clearTimeout = function(bukkitTask){
- bukkitTask.cancel();
- };
-
- global.setInterval = function(callback, intervalInMillis){
- var delay = intervalInMillis/ 50;
- var bukkitTask = server.scheduler.runTaskTimer(__plugin, callback, delay, delay);
- return bukkitTask;
- };
- global.clearInterval = function(bukkitTask){
- bukkitTask.cancel();
- };
global.refresh = function(){
__plugin.pluginLoader.disablePlugin(__plugin);
__plugin.pluginLoader.enablePlugin(__plugin);
@@ -547,6 +545,7 @@ function __onEnable (__engine, __plugin, __script)
global.echo = _echo;
global.alert = _echo;
global.load = _load;
+ global.save = _save;
global.addUnloadHandler = _addUnloadHandler;
@@ -556,21 +555,30 @@ function __onEnable (__engine, __plugin, __script)
*/
var modulePaths = [jsPluginsRootDirName + '/lib/',
jsPluginsRootDirName + '/modules/'];
- global.require = fnRequire(__plugin.logger, __engine, config.verbose, jsPluginsRootDirName, modulePaths);
+ global.require = fnRequire(__plugin.logger,
+ __engine,
+ config.verbose,
+ jsPluginsRootDirName,
+ modulePaths);
+ require('js-patch')(global);
global.console = require('console');
+ /*
+ setup persistence
+ */
+ require('persistence')(jsPluginsRootDir,global);
+
global.command = require('command').command;
var plugins = require('plugin');
global.__onTabComplete = require('tabcomplete');
global.plugin = plugins.plugin;
- global.save = plugins.save;
var events = require('events');
events.on('server.PluginDisableEvent',function(l,e){
// save config
- plugins.save(global.config, new File(jsPluginsRootDir, "data/global-config.json" ));
+ save(global.config, new File(jsPluginsRootDir, "data/global-config.json" ));
_runUnloadHandlers();
org.bukkit.event.HandlerList["unregisterAll(org.bukkit.plugin.Plugin)"](__plugin);
@@ -625,10 +633,12 @@ function __onEnable (__engine, __plugin, __script)
for (var i = 0; i < legacyDirs.length; i++){
if (legacyDirs[i].exists() && legacyDirs[i].isDirectory()){
legacyExists = true;
- console.warn('Legacy ScriptCraft directory ' + legacyDirs[i].canonicalPath + ' was found. This directory is no longer used.');
+ console.warn('Legacy ScriptCraft directory %s was found. This directory is no longer used.',
+ legacyDirs[i].canonicalPath);
}
}
if (legacyExists){
- console.info('Please note that the working directory for ' + __plugin + ' is ' + jsPluginsRootDir.canonicalPath);
+ console.info('Please note that the working directory for %s is %s',
+ __plugin, jsPluginsRootDir.canonicalPath);
}
}
diff --git a/src/main/javascript/modules/utils/string-exts.js b/src/main/javascript/modules/utils/string-exts.js
index 1e7159b..bb33e23 100644
--- a/src/main/javascript/modules/utils/string-exts.js
+++ b/src/main/javascript/modules/utils/string-exts.js
@@ -77,9 +77,3 @@ for (var method in formattingCodes){
return function(){return c+this;};
}(formattingCodes[method]);
}
-// wph 20140105 trim not availabe in String on Mac OS.
-if (!String.prototype.trim){
- String.prototype.trim = function(){
- return this.replace(/^\s+|\s+$/g,'');
- }
-}
diff --git a/src/main/javascript/plugins/classroom/classroom.js b/src/main/javascript/plugins/classroom/classroom.js
index 2822b27..d674f96 100644
--- a/src/main/javascript/plugins/classroom/classroom.js
+++ b/src/main/javascript/plugins/classroom/classroom.js
@@ -47,6 +47,7 @@ var classroom = plugin("classroom", {
allowScripting: function (/* boolean: true or false */ canScript, sender) {
if (typeof sender == 'undefined'){
console.log("Attempt to set classroom scripting without credentials");
+ console.log("classroom.allowScripting(boolean, sender)");
return;
}
if (!sender.op){
diff --git a/src/main/javascript/plugins/minigames/NumberGuess.js b/src/main/javascript/plugins/minigames/NumberGuess.js
index 01424a4..a3ae132 100644
--- a/src/main/javascript/plugins/minigames/NumberGuess.js
+++ b/src/main/javascript/plugins/minigames/NumberGuess.js
@@ -15,8 +15,20 @@ Once the game begins, guess a number by typing the `/` character
followed by a number between 1 and 10.
***/
+
+var sb = function(cmd){
+ org.bukkit.Bukkit.dispatchCommand(server.consoleSender, 'scoreboard ' + cmd)
+};
+
exports.Game_NumberGuess = {
start: function(sender) {
+
+ var guesses = 0;
+
+ sb('objectives add NumberGuess dummy Guesses');
+ sb('players set ' + sender.name + ' NumberGuess ' + guesses);
+ sb('objectives setdisplay sidebar NumberGuess');
+
importPackage(org.bukkit.conversations);
var number = Math.ceil(Math.random() * 10);
@@ -38,6 +50,7 @@ exports.Game_NumberGuess = {
if (s == number){
setTimeout(function(){
ctx.forWhom.sendRawMessage("You guessed Correct!");
+ sb('objectives remove NumberGuess');
},100);
return null;
}else{
@@ -45,6 +58,9 @@ exports.Game_NumberGuess = {
ctx.setSessionData("hint","too low\n");
if (s > number)
ctx.setSessionData("hint","too high\n");
+ guesses++;
+ sb('players set ' + sender.name + ' NumberGuess ' + guesses);
+
return prompt;
}
},
diff --git a/src/main/javascript/plugins/minigames/cow-clicker.js b/src/main/javascript/plugins/minigames/cow-clicker.js
new file mode 100644
index 0000000..4abb5ef
--- /dev/null
+++ b/src/main/javascript/plugins/minigames/cow-clicker.js
@@ -0,0 +1,225 @@
+/*************************************************************************
+## Cow Clicker Mini-Game
+
+### How to Play
+
+At the in-game prompt type `jsp cowclicker` to start or stop
+playing. Right-Click on Cows to score points. No points for killing
+cows (hint: use the same keyboard keys you'd use for opening doors).
+
+Every time you click a cow your score increases by 1 point. Your score
+is displayed in a side-bar along the right edge of of the screen.
+
+
+
+### Rules
+
+ * You can join and leave the Cow Clicker game at any time by typing
+ `/jsp cowclicker` at the in-game prompt.
+
+ * Once you leave the game, your score is reset to zero.
+
+ * You can disconnect from the server and your score will be saved for
+ the next time you join.
+
+### Gameplay Mechanics
+
+This is meant as a trivially simple use of the [Bukkit Scoreboard
+API][bukscore]. There are many things you'll want to consider when constructing
+your own mini-game...
+
+ * Is the game itself a long-lived game - that is - should players and
+ scores be persisted (stored) between server restarts?
+
+ * What should happen when a player quits the server - should this also be
+ understood as quitting the mini-game?
+
+ * What should happen when a player who was previously playing the
+ mini-game, joins the server - should they automatically resume the
+ mini-game?
+
+[bukscore]: http://jd.bukkit.org/beta/apidocs/org/bukkit/scoreboard/package-summary.html
+
+***/
+
+var store = {};
+
+var scoreboardConfig = {
+ cowclicker: {SIDEBAR: 'Cows Clicked'}
+};
+
+/*
+ The scoreboard is a simple wrapper around the Bukkit Scoreboard API.
+ It's only concerned with display of scores, not maintaining them - that's the game's job.
+*/
+var scoreboard = (function(options){
+ var temp = {};
+ var ccScoreboard;
+ var DisplaySlot = org.bukkit.scoreboard.DisplaySlot;
+
+ return {
+ start: function(){
+ var objective, slot;
+ ccScoreboard = server.scoreboardManager.getNewScoreboard();
+ for (objective in options){
+ var ccObj = ccScoreboard.registerNewObjective(objective,'dummy');
+ for (slot in options[objective]){
+ ccObj.displaySlot = DisplaySlot[slot];
+ ccObj.displayName = options[objective][slot];
+ }
+ }
+ },
+ stop: function(){
+ var objective, slot;
+ for (objective in options){
+ ccScoreboard.getObjective(objective).unregister();
+ for (slot in options[objective]){
+ ccScoreboard.clearSlot(DisplaySlot[slot]);
+ }
+ }
+ },
+ update: function(objective,player,score){
+ if (player.scoreboard && player.scoreboard != ccScoreboard)
+ {
+ temp[player.name] = player.scoreboard;
+ player.scoreboard = ccScoreboard;
+ }
+ ccScoreboard.getObjective(objective).getScore(player).score = score;
+ },
+ restore: function(player){
+ // offlineplayers don't have a scoreboard
+ if (player.scoreboard)
+ player.scoreboard = temp[player.name];
+ }
+ };
+}(scoreboardConfig));
+
+var _onPlayerInteract = function(listener, event){
+ var player = event.player;
+ var Bukkit = org.bukkit.Bukkit;
+
+ if (!store[player.name])
+ return;
+
+ var clickedEntity = event.rightClicked;
+ var loc = clickedEntity.location;
+ var sound = function(snd,vol,pitch){
+ loc.world.playSound(loc,snd,vol,pitch);
+ };
+ if (clickedEntity instanceof org.bukkit.entity.Cow)
+ {
+ store[player.name].score++;
+ scoreboard.update('cowclicker', player, store[player.name].score);
+
+ Bukkit.dispatchCommand(player, 'me clicked a cow!');
+ sound(org.bukkit.Sound.CLICK,1,1);
+ setTimeout(function(){
+ sound(org.bukkit.Sound.COW_HURT,10,0.85)
+ },200);
+ }
+};
+var _onPlayerQuit = function(listener, event){
+ _removePlayer(event.player)
+};
+var _onPlayerJoin = function(listener, event){
+ var gamePlayer = store[event.player.name];
+ if (gamePlayer)
+ _addPlayer(event.player, gamePlayer.score);
+};
+
+var _startGame = function(){
+ if (config.verbose)
+ console.log('Staring game: Cow Clicker');
+
+ events.on('player.PlayerQuitEvent', _onPlayerQuit);
+ events.on('player.PlayerJoinEvent', _onPlayerJoin);
+ events.on('player.PlayerInteractEntityEvent', _onPlayerInteract);
+
+ scoreboard.start();
+
+ store = persist('cowclicker',store);
+ for (var p in store){
+ var player = server.getPlayer(p);
+ if (player){
+ /*
+ only add online players
+ */
+ var score = store[p].score;
+ _addPlayer(player, score);
+ }
+ }
+};
+var _addPlayer = function(player,score){
+ if (config.verbose)
+ console.log('Adding player %s to Cow Clicker game',player);
+
+ if (typeof score == 'undefined')
+ score = 0;
+ store[player.name] = {score: score};
+ scoreboard.update('cowclicker', player,store[player.name].score);
+
+ player.sendMessage('Go forth and click some cows!');
+};
+
+var _removePlayer = function(player,notify){
+
+ if (player instanceof org.bukkit.OfflinePlayer && player.player)
+ player = player.player;
+
+ if (!store[player.name])
+ return;
+ if (config.verbose)
+ console.log('Removing player %s from Cow Clicker', player);
+
+ var playerScore = store[player.name].score;
+
+ scoreboard.restore(player);
+
+ delete store[player.name];
+ if (notify && player){
+ player.sendMessage('You clicked ' + playerScore + ' cows! ' +
+ 'You must be tired after all that clicking.');
+ }
+};
+var _removeAllPlayers = function(notify){
+ if (typeof notify == 'undefined')
+ notify = false;
+ for (var p in store){
+ var player = server.getOfflinePlayer(p);
+ if (player)
+ _removePlayer(player,notify);
+ delete store[p];
+ }
+}
+var _stopGame = function(removePlayers){
+ if (typeof removePlayers == 'undefined')
+ removePlayers = true;
+ if (config.verbose)
+ console.log('Stopping game: Cow Clicker');
+ scoreboard.stop();
+ if (!removePlayers)
+ return;
+ _removeAllPlayers(false);
+ persist('cowclicker',store.pers,'w');
+
+};
+/*
+ start the game automatically when this module is loaded.
+*/
+_startGame();
+/*
+ players can join and leave the game by typing `jsp cowclicker`
+*/
+command('cowclicker', function(params, sender){
+ if (!store[sender.name])
+ _addPlayer(sender);
+ else
+ _removePlayer(sender);
+});
+/*
+ stop the game when ScriptCraft is unloaded.
+*/
+addUnloadHandler(function(){
+ _stopGame(false);
+});
+
diff --git a/src/main/javascript/plugins/spawn.js b/src/main/javascript/plugins/spawn.js
new file mode 100644
index 0000000..975de56
--- /dev/null
+++ b/src/main/javascript/plugins/spawn.js
@@ -0,0 +1,35 @@
+/*************************************************************************
+## Spawn Plugin
+
+Allows in-game operators to easily spawn creatures at current location.
+
+### Usage
+
+ /jsp spawn cow
+ /jsp spawn sheep
+ /jsp spawn wolf
+
+This command supports TAB completion so to see a list of possible
+entitities, type `/jsp spawn ' at the in-game command prompt, then
+press TAB. Visit
+
+for a list of possible entities (creatures) which can be spawned.
+
+***/
+var entities = [];
+var Types = org.bukkit.entity.EntityType
+for (var t in Types){
+ if (Types[t] && Types[t].ordinal){
+ entities.push(t);
+ }
+}
+command('spawn', function(parameters, sender){
+ if (!sender.op){
+ sender.sendMessage('Only operators can perform this command');
+ return;
+ }
+ var location = sender.location;
+ var world = location.world;
+ var type = ('' + parameters[0]).toUpperCase();
+ world.spawnEntity(location, org.bukkit.entity.EntityType[type]);
+},entities);
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
index c856198..55e6fd2 100644
--- a/src/main/resources/plugin.yml
+++ b/src/main/resources/plugin.yml
@@ -1,4 +1,4 @@
-name: ScriptCraftPlugin
+name: scriptcraft
main: net.walterhiggins.scriptcraft.ScriptCraftPlugin
version: [[version]]
commands: