Oh the complexity of it all!

In Part 8, there’s a bit more new JavaScript introduced, but there’s also a bunch more ScriptCraft/CanaryMod introduced. These things get complicated fast, but I wanted to show what’s possible and some of how I got there.

I think the end result is pretty cool: it’s an egg hunt! But you don’t have to go looking for the chickens. This egg hunt comes complete with a bunch of chickens that are ready to lay eggs within seconds.

The Video

egghunt.js

/*global require, command, server, Packages, echo, setTimeout, plugin*/

var utils = require("utils"),
    items = require("items"),
    events = require("events"),
    Canary = Packages.net.canarymod.Canary,
    CHICKEN = Packages.net.canarymod.api.entity.EntityType.CHICKEN,
    Location = Packages.net.canarymod.api.world.position.Location;

var gameData,
    chickens,
    itemPickupListener,
    GAME_LENGTH = 10, // Number of seconds
    CHICKEN_COUNT = 20,
    CHICKEN_LOCATION_VARIATION = 10, // Number of blocks
    EGG_TIMER = 60; // Time in ticks (20 per second)

function execCommand( command ){
    server.executeVanillaCommand(server, command);
}

function setupScoreboard() {
    execCommand("scoreboard objectives add egghunt dummy Egg Hunt");
    execCommand("scoreboard objectives setdisplay sidebar egghunt");
    execCommand("scoreboard teams add red");
    execCommand("scoreboard teams add yellow");
    gameData = {
        scores: {},
        playerTeams: {},
        teamScores: {
            red: 0,
            yellow: 0
        },
        mvpScore: 0,
        mvp: "no one!"
    };
}

function setupTeams() {
    utils.players(function (player) {
        var loc = player.location;
        loc.y -= 1;
        var block = utils.blockAt(loc);
        
        if (block.type.machineName !== "minecraft:wool")  {
            echo(player, "You are not playing egghunt because you are not on wool");
            return;
        }
        
        var color = block.getPropertyForName("color"),
            woolColor = block.getValue(color).toString().toLowerCase();
        
        gameData.scores[player.name] = 0;
        gameData.playerTeams[player.name] = woolColor;
        echo(player, "You are on the " + woolColor + " team");
    });
}

function spawnChickens(location) {
    var entityFactory = Canary.factory().entityFactory;
    chickens = [];
    for (var i = 0; i < CHICKEN_COUNT; i++) {
        var newLoc = location.clone();
        newLoc.x += Math.floor(Math.random() * CHICKEN_LOCATION_VARIATION - CHICKEN_LOCATION_VARIATION / 2);
        newLoc.z += Math.floor(Math.random() * CHICKEN_LOCATION_VARIATION - CHICKEN_LOCATION_VARIATION / 2);
        var chicken = entityFactory.newEntity(CHICKEN, newLoc);
        chicken.setTimeUntilNextEgg(Math.floor(Math.random() * EGG_TIMER));
        chickens.push(chicken);
        chicken.spawn();
    }
}

function cleanupEggs() {
    utils.players(function (player) {
        if (gameData.scores[player.name] !== undefined) {
            while (player.inventory.hasItem(items.egg())) {
                player.inventory.removeItem(items.egg());
            }
        }
    });
}

function itemPickupHook(event) {
    var entityItem = event.getItem(),
        item = entityItem.getItem();
    if (item.displayName === "Egg") {
        var playerName = event.getPlayer().name,
            scores = gameData.scores;
        
        if (scores[playerName] !== undefined) {
            scores[playerName] += 1;
            var score = scores[playerName];
            if (score > gameData.mvpScore) {
                gameData.mvp = playerName;
                gameData.mvpScore = score;
            }
            gameData.teamScores[gameData.playerTeams[playerName]] += 1;
            execCommand("scoreboard players set " + playerName + " egghunt " + score);
        }
    }
}

function finishGame() {
    if (chickens) {
        utils.foreach(chickens, function (chicken) {
            chicken.destroy();
        });
        chickens = null;
    }
    if (itemPickupListener) {
        itemPickupListener.unregister();
        itemPickupListener = null;
    }
    
    execCommand("scoreboard objectives remove egghunt");
    execCommand("scoreboard teams remove red");
    execCommand("scoreboard teams remove yellow");
    
    var redScore = gameData.teamScores.red,
        yellowScore = gameData.teamScores.yellow;
    
    if (redScore > yellowScore) {
        server.broadcastMessage("Red has triumphed over yellow!");
        server.broadcastMessage(redScore + " to " + yellowScore);
    } else if (redScore === yellowScore) {
        server.broadcastMessage("It's a tie! " + redScore + " all!");
    } else {
        server.broadcastMessage("Yellow has vanquished red!");
        server.broadcastMessage(yellowScore + " to " + redScore);
    }
    
    server.broadcastMessage("The MVP was " + gameData.mvp + " with " + gameData.mvpScore + " eggs!");
    
    var scores = gameData.scores;
    utils.players(function (player) {
        if (scores[player.name] !== undefined) {
            echo(player, "You found " + scores[player.name] + " eggs");
        }
    });
    
    cleanupEggs();
    gameData = null;
}

var egghunt = plugin("egghunt", {
    store: {}
}, true);

command("egghunt", function (parameters, player) {
    if (parameters[0] === "save") {
        egghunt.store.chickenspot = player.location.toString();
        echo(player, "Location saved!");
        return;
    }
    if (gameData) {
        echo(player, "Egghunt already in progress!");
        return;
    }
    server.broadcastMessage("Starting an egghunt");
    setTimeout(finishGame, GAME_LENGTH * 1000);
    setupScoreboard();
    setupTeams();
    cleanupEggs();
    
    var location = player.location;
    if (egghunt.store.chickenspot) {
        location = Location.fromString(egghunt.store.chickenspot);
    }
    spawnChickens(location);
    itemPickupListener = events.itemPickup(itemPickupHook);
});

Where To Go From Here

See if there are some changes you might want to make to the egg hunt minigame.