diff --git a/moonlight/index.html b/moonlight/index.html
index 3c3473c..cf305c6 100644
--- a/moonlight/index.html
+++ b/moonlight/index.html
@@ -1,16 +1,16 @@
-
- Moonlight Skulk (Working Title)
-
-
-
-
+
+ Moonlight Skulk (Working Title)
+
+
+
+
diff --git a/moonlight/index_debug.html b/moonlight/index_debug.html
new file mode 100644
index 0000000..196517f
--- /dev/null
+++ b/moonlight/index_debug.html
@@ -0,0 +1,29 @@
+
+
+
+
+ Moonlight Skulk (Working Title)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/moonlight/js/moonlight-skulk.js b/moonlight/js/moonlight-skulk.js
index a3e5ae0..b17ef87 100644
--- a/moonlight/js/moonlight-skulk.js
+++ b/moonlight/js/moonlight-skulk.js
@@ -42,132 +42,6 @@ SPRITE_TOWNSFOLK_FEMALE4 = 8;
SPRITE_TOWNSFOLK_GUARD1 = 9;
SPRITE_TOWNSFOLK_GUARD2 = 10;
-
-var pathfinder = null;
-var pathfinder_grid = null;
-
-var game = new Phaser.Game(640, 480, Phaser.AUTO, '');
-
-// Create torch objects
-// Light constructor
-var Light = function(game, x, y, key, frame, radius, fade, color_start, color_stop, flicker, always_render, light_meter) {
- color_start = ( typeof color_start == undefined ? color_start : 'rgba(255, 255, 255, 1.0)');
- color_stop = ( typeof color_stop == undefined ? color_stop : 'rgba(255, 255, 255, 0.0)');
- fade = ( typeof fade == undefined ? fade : 0.25);
- radius = ( typeof radius == undefined ? radius : 64);
- flicker = ( typeof flicker == undefined ? flicker : false);
- always_render = ( typeof always_render == undefined ? always_render : false);
- light_meter = ( typeof light_meter == undefined ? light_meter : 1.0 );
- Phaser.Sprite.call(this, game, x, y, null);
-
- // Set the pivot point for this sprite to the center
- this.anchor.setTo(0.5, 0.5);
-
- this.color_start = color_start;
- this.color_stop = color_stop;
- this.radius = radius;
- this.rendered_radius = radius;
- this.fade = radius * fade
- this.light_meter = light_meter;
- this.always_render = always_render
- this.rect = positiveRectangle(this.x - radius, this.y - radius, radius * 2, radius * 2)
- this.flicker = flicker;
-};
-
-// Lightes are a type of Phaser.Sprite
-Light.prototype = Object.create(Phaser.Sprite.prototype);
-Light.prototype.constructor = Light;
-
-Light.prototype.update_new_values = function() {
- this.light_meter = Number(this.light_meter);
- this.radius = parseInt(this.radius);
- this.fade = this.radius * Number(this.fade);
- this.flicker = parseBoolean(this.flicker);
- this.always_render = parseBoolean(this.always_render);
- this.rect = positiveRectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2)
-}
-
-function SoundSprite(game, x, y, key, frame,
- sound_key,
- sound_marker,
- sound_position,
- sound_volume,
- sound_loop,
- sound_forcerestart,
- sound_distance,
- sound_nofade)
-{
- Phaser.Sprite.call(this, game, x, y, null);
- this.sound_key = sound_key;
- this.sound_marker = ( typeof sound_marker == undefined ? sound_marker : '');
- this.sound_volume = ( typeof sound_volume == undefined ? sound_volume : 1.0 );
- this.sound_position = ( typeof sound_position == undefined ? sound_position : 1.0 );
- this.sound_loop = ( typeof sound_loop == undefined ? sound_loop : true );
- this.sound_forcerestart = ( typeof sound_forcerestart == undefined ? sound_forcerestart : false );
- var def_distance = Math.sqrt(
- Number((game.camera.width/2) * (game.camera.width/2)) +
- Number((game.camera.height/2) * (game.camera.height/2))
- );
- this.sound_distance = ( typeof sound_distance == undefined ? sound_distance : def_distance);
- this.sound_nofade = (typeof sound_nofade == undefined ? sound_nofade : false);
-
- this.sound = null;
-}
-
-SoundSprite.prototype = Object.create(Phaser.Sprite.prototype);
-SoundSprite.prototype.constructor = Light;
-
-SoundSprite.prototype.update_new_values = function() {
- if ( this.sound_key == null ) {
- if ( this.sound !== null ) {
- this.sound.stop();
- }
- return;
- }
- this.sound_position = parseInt(this.sound_position);
- this.sound_distance = Number(this.sound_distance);
- this.sound_volume = Number(this.sound_volume);
- this.sound_loop = parseBoolean(this.sound_loop);
- this.sound_forcerestart = parseBoolean(this.sound_forcerestart);
- this.sound_nofade = parseBoolean(this.sound_nofade);
-
- if ( this.sound !== null )
- this.sound.stop();
- this.sound = game.add.audio(this.sound_key, this.sound_volume, this.sound_loop);
- this.sound.play(
- this.sound_marker,
- this.sound_position,
- this.sound_volume,
- this.sound_loop,
- this.sound_forcerestart);
-}
-
-SoundSprite.prototype.adjust_relative_to = function(spr) {
- if ( this.sound_nofade == true ) {
- this.sound.volume = this.sound_volume;
- return;
- }
-
- // The volume of any given sound is equal to the length of the
- // hypotenuse of a triangle drawn from the point (p) to the
- // sprite in question
-
- var xd = (spr.x - this.x);
- if ( xd < 0 )
- xd = -(xd);
- var yd = (spr.y - this.y);
- if ( yd < 0 )
- yd = -(yd);
-
- var hyp = Math.sqrt(Number(xd * xd) + Number(yd * yd));
-
- this.sound.volume = (1.0 - Number(hyp / this.sound_distance));
- // Math.max doesn't work here??
- if ( this.sound.volume < 0 )
- this.sound.volume = 0;
-
-}
-
var moonlightSettings = {
'map' : {
'tilesets': [
@@ -501,7 +375,6 @@ var moonlightSettings = {
}
}
};
-
var moonlightDialog = {
"status": {
"townsfolk-male" : {
@@ -634,7 +507,6 @@ var moonlightDialog = {
}
}
};
-
// Return new array with duplicate values removed
function array_unique(arr) {
var a = [];
@@ -667,23 +539,262 @@ function stringSize(str, font)
return [width, height];
}
-var EffectSprite = function(game, x, y, key, frame, animation) {
- this.update_new_values = function() {
- this.animations.destroy();
- this.loadTexture(this.sprite_key, 0);
- addAnimation(this, this.sprite_animation);
- this.animations.play(this.sprite_animation);
- }
-
- Phaser.Sprite.call(this, game, x, y, null);
- game.physics.arcade.enable(this);
- this.collide_with_map = true;
- this.collide_with_player = false;
+function rotatePoints(arr, x, y, degrees)
+{
+ arr.forEach(function(p) {
+ p.rotate(x, y, degrees, true);
+ }, this);
}
-EffectSprite.prototype = Object.create(Phaser.Sprite.prototype);
-EffectSprite.prototype.constructor = EffectSprite;
+function positiveRectangle(x, y, w, h) {
+ if ( w < 0 ) {
+ w = -(w);
+ x = x - w;
+ }
+ if ( h < 0 ) {
+ h = -(h);
+ y = y - h;
+ }
+ return new Phaser.Rectangle(x, y, w, h);
+}
+function nearestInGroup(sprite, group, sprite_group) {
+ var nearest = null;
+ var lastdist = 0.0;
+ for ( var i = 0 ; i < group.length; i++ ) {
+ console.log("Checking distance to group[" + i + "]");
+ var spr = group.getChildAt(i);
+ console.log(spr);
+ if ( (typeof sprite_group !== undefined) &&
+ spr.sprite_group !== sprite_group )
+ continue;
+ var dist = new Phaser.Line(sprite.x, sprite.y, spr.x, spr.y);
+ if ( (lastdist == 0.0 ) || (dist.length < lastdist) ) {
+ lastdist = dist.length;
+ nearest = spr;
+ }
+ }
+ return nearest;
+}
+
+function nearestWalkableTile(spr)
+{
+ function _walkable_inner(multiplier) {
+ var startx = parseInt(Math.max((spr.x / 32) - (1 * multiplier), 0));
+ var starty = parseInt(Math.max((spr.y / 32) - (1 * multiplier), 0));
+ var endx = parseInt(Math.min((spr.x / 32) + 1 + (1 * multiplier), game.state.states.game.map.width));
+ var endy = parseInt(Math.min((spr.y / 32) + 1 + (1 * multiplier), game.state.states.game.map.width));
+
+ for ( var x = startx ; x <= endx ; x++ ) {
+ for ( var y = starty ; y <= endy ; y++ ) {
+ if ( (x == startx && y == starty) ||
+ (x == startx && y == endy) ||
+ (y == starty) ||
+ (y == endy) ) {
+ console.log(pathfinder_grid);
+ if ( pathfinder_grid.nodes[x][y].walkable == true ) {
+ console.log([x, y]);
+ return [x, y];
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ for ( var i = 1 ; i < 100 ; i++ ) {
+ var rv = _walkable_inner(i);
+ if ( rv !== null ) {
+ console.log("Found near walkable tile");
+ console.log([rv] + [spr.x / 32, spr.y / 32]);
+ return rv
+ }
+ }
+ //if ( multiplier >= 10 )
+ console.log("Couldn't find a near walkable tile");
+ console.log([spr.x / 32, spr.y / 32]);
+ return [parseInt(spr.x / 32), parseInt(spr.y / 32)];
+ //return nearestWalkableTile(spr, multiplier + 1);
+}
+
+function addAnimation(obj, anim)
+{
+ a = moonlightSettings['animations'][anim]
+ obj.animations.add(anim, a['frames'], a['speed'], a['loop'])
+}
+
+function getFaceState(spr)
+{
+ if ( hasState(spr, STATE_FACE_LEFT) )
+ return STATE_FACE_LEFT;
+ if ( hasState(spr, STATE_FACE_RIGHT) )
+ return STATE_FACE_RIGHT;
+ if ( hasState(spr, STATE_FACE_DOWN) )
+ return STATE_FACE_DOWN;
+ if ( hasState(spr, STATE_FACE_UP) )
+ return STATE_FACE_UP;
+}
+
+function getMoveState(spr)
+{
+ return ( hasState(spr, STATE_MOVING) ||
+ hasState(spr, STATE_RUNNING) );
+}
+
+function delState(spr, state)
+{
+ if ( hasState(spr, state) )
+ spr.state = spr.state ^ state;
+}
+
+function addState(spr, state)
+{
+ spr.state = spr.state | state;
+}
+
+function setMovingState(spr, state)
+{
+ delState(spr, STATE_FACE_LEFT);
+ delState(spr, STATE_FACE_RIGHT);
+ delState(spr, STATE_FACE_DOWN);
+ delState(spr, STATE_FACE_UP);
+ delState(spr, STATE_MOVING);
+ delState(spr, STATE_RUNNING);
+ addState(spr, state);
+}
+
+function setAwarenessState(spr, state)
+{
+ delState(spr, STATE_UNAWARE);
+ delState(spr, STATE_CONCERNED);
+ delState(spr, STATE_ALERTED);
+ delState(spr, STATE_LOSTHIM);
+ addState(spr, state);
+}
+
+function exchangeState(spr, state1, state2)
+{
+ delState(spr, state1);
+ addState(spr, state2);
+}
+
+function hasAnyState(spr, states)
+{
+ var hasstate = false;
+ states.forEach(function(x) {
+ if ( hasState(spr, x) )
+ hasstate = true;
+ }, this);
+ return hasstate;
+}
+
+function hasState(spr, state)
+{
+ if ( (spr.state & state) == state )
+ return true;
+ return false;
+}
+
+function spriteFacing(spr)
+{
+ if ( hasState(spr, STATE_FACE_LEFT) )
+ return "left";
+ if ( hasState(spr, STATE_FACE_RIGHT) )
+ return "right";
+ if ( hasState(spr, STATE_FACE_DOWN) )
+ return "down";
+ if ( hasState(spr, STATE_FACE_UP) )
+ return "up";
+}
+
+function parseBoolean(val)
+{
+ return ( val == 'true' || val == true );
+}
+
+function setSpriteMovement(spr, velocity)
+{
+ var x = 0;
+ var y = 0;
+ var dir = spriteFacing(spr);
+ velocity = ( typeof velocity == undefined ? velocity : [SPEED_WALKING,
+ SPEED_RUNNING] );
+
+ spr.body.setSize(16, 16, 8, 16);
+
+ if ( hasState(spr, STATE_RUNNING) ) {
+ if ( velocity !== false )
+ velocity = velocity[1];
+ spr.animations.play("bipedrun" + dir);
+ } else if ( hasState(spr, STATE_MOVING) ) {
+ if ( velocity !== false )
+ velocity = velocity[0];
+ spr.animations.play("bipedwalk" + dir);
+ } else {
+ if ( velocity !== false ) {
+ spr.body.velocity.x = 0;
+ spr.body.velocity.y = 0;
+ }
+ spr.animations.stop();
+ return;
+ }
+
+ if ( velocity !== false ) {
+ if ( dir == "left" ) {
+ spr.body.velocity.x = -(velocity * velocity);
+ spr.body.velocity.y = 0;
+ } else if ( dir == "right" ) {
+ spr.body.velocity.x = (velocity * velocity);
+ spr.body.velocity.y = 0;
+ } else if ( dir == "up" ) {
+ spr.body.velocity.x = 0;
+ spr.body.velocity.y = -(velocity * velocity);
+ } else if ( dir == "down" ) {
+ spr.body.velocity.x = 0;
+ spr.body.velocity.y = (velocity * velocity);
+ }
+ }
+}
+
+
+// Create torch objects
+// Light constructor
+var Light = function(game, x, y, key, frame, radius, fade, color_start, color_stop, flicker, always_render, light_meter) {
+ color_start = ( typeof color_start == undefined ? color_start : 'rgba(255, 255, 255, 1.0)');
+ color_stop = ( typeof color_stop == undefined ? color_stop : 'rgba(255, 255, 255, 0.0)');
+ fade = ( typeof fade == undefined ? fade : 0.25);
+ radius = ( typeof radius == undefined ? radius : 64);
+ flicker = ( typeof flicker == undefined ? flicker : false);
+ always_render = ( typeof always_render == undefined ? always_render : false);
+ light_meter = ( typeof light_meter == undefined ? light_meter : 1.0 );
+ Phaser.Sprite.call(this, game, x, y, null);
+
+ // Set the pivot point for this sprite to the center
+ this.anchor.setTo(0.5, 0.5);
+
+ this.color_start = color_start;
+ this.color_stop = color_stop;
+ this.radius = radius;
+ this.rendered_radius = radius;
+ this.fade = radius * fade
+ this.light_meter = light_meter;
+ this.always_render = always_render
+ this.rect = positiveRectangle(this.x - radius, this.y - radius, radius * 2, radius * 2)
+ this.flicker = flicker;
+};
+
+// Lightes are a type of Phaser.Sprite
+Light.prototype = Object.create(Phaser.Sprite.prototype);
+Light.prototype.constructor = Light;
+
+Light.prototype.update_new_values = function() {
+ this.light_meter = Number(this.light_meter);
+ this.radius = parseInt(this.radius);
+ this.fade = this.radius * Number(this.fade);
+ this.flicker = parseBoolean(this.flicker);
+ this.always_render = parseBoolean(this.always_render);
+ this.rect = positiveRectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2)
+}
var AISprite = function(game, x, y, key, frame) {
this.viewRectangle = function() {
var offset = [];
@@ -1219,91 +1330,102 @@ var AISprite = function(game, x, y, key, frame) {
AISprite.prototype = Object.create(Phaser.Sprite.prototype);
AISprite.prototype.constructor = AISprite;
+var EffectSprite = function(game, x, y, key, frame, animation) {
+ this.update_new_values = function() {
+ this.animations.destroy();
+ this.loadTexture(this.sprite_key, 0);
+ addAnimation(this, this.sprite_animation);
+ this.animations.play(this.sprite_animation);
+ }
-function rotatePoints(arr, x, y, degrees)
+ Phaser.Sprite.call(this, game, x, y, null);
+ game.physics.arcade.enable(this);
+ this.collide_with_map = true;
+ this.collide_with_player = false;
+}
+
+EffectSprite.prototype = Object.create(Phaser.Sprite.prototype);
+EffectSprite.prototype.constructor = EffectSprite;
+
+function SoundSprite(game, x, y, key, frame,
+ sound_key,
+ sound_marker,
+ sound_position,
+ sound_volume,
+ sound_loop,
+ sound_forcerestart,
+ sound_distance,
+ sound_nofade)
{
- arr.forEach(function(p) {
- p.rotate(x, y, degrees, true);
- }, this);
+ Phaser.Sprite.call(this, game, x, y, null);
+ this.sound_key = sound_key;
+ this.sound_marker = ( typeof sound_marker == undefined ? sound_marker : '');
+ this.sound_volume = ( typeof sound_volume == undefined ? sound_volume : 1.0 );
+ this.sound_position = ( typeof sound_position == undefined ? sound_position : 1.0 );
+ this.sound_loop = ( typeof sound_loop == undefined ? sound_loop : true );
+ this.sound_forcerestart = ( typeof sound_forcerestart == undefined ? sound_forcerestart : false );
+ var def_distance = Math.sqrt(
+ Number((game.camera.width/2) * (game.camera.width/2)) +
+ Number((game.camera.height/2) * (game.camera.height/2))
+ );
+ this.sound_distance = ( typeof sound_distance == undefined ? sound_distance : def_distance);
+ this.sound_nofade = (typeof sound_nofade == undefined ? sound_nofade : false);
+
+ this.sound = null;
}
-function positiveRectangle(x, y, w, h) {
- if ( w < 0 ) {
- w = -(w);
- x = x - w;
- }
- if ( h < 0 ) {
- h = -(h);
- y = y - h;
- }
- return new Phaser.Rectangle(x, y, w, h);
-}
+SoundSprite.prototype = Object.create(Phaser.Sprite.prototype);
+SoundSprite.prototype.constructor = Light;
-function nearestInGroup(sprite, group, sprite_group) {
- var nearest = null;
- var lastdist = 0.0;
- for ( var i = 0 ; i < group.length; i++ ) {
- console.log("Checking distance to group[" + i + "]");
- var spr = group.getChildAt(i);
- console.log(spr);
- if ( (typeof sprite_group !== undefined) &&
- spr.sprite_group !== sprite_group )
- continue;
- var dist = new Phaser.Line(sprite.x, sprite.y, spr.x, spr.y);
- if ( (lastdist == 0.0 ) || (dist.length < lastdist) ) {
- lastdist = dist.length;
- nearest = spr;
+SoundSprite.prototype.update_new_values = function() {
+ if ( this.sound_key == null ) {
+ if ( this.sound !== null ) {
+ this.sound.stop();
}
+ return;
}
- return nearest;
+ this.sound_position = parseInt(this.sound_position);
+ this.sound_distance = Number(this.sound_distance);
+ this.sound_volume = Number(this.sound_volume);
+ this.sound_loop = parseBoolean(this.sound_loop);
+ this.sound_forcerestart = parseBoolean(this.sound_forcerestart);
+ this.sound_nofade = parseBoolean(this.sound_nofade);
+
+ if ( this.sound !== null )
+ this.sound.stop();
+ this.sound = game.add.audio(this.sound_key, this.sound_volume, this.sound_loop);
+ this.sound.play(
+ this.sound_marker,
+ this.sound_position,
+ this.sound_volume,
+ this.sound_loop,
+ this.sound_forcerestart);
}
-function nearestWalkableTile(spr)
-{
- function _walkable_inner(multiplier) {
- var startx = parseInt(Math.max((spr.x / 32) - (1 * multiplier), 0));
- var starty = parseInt(Math.max((spr.y / 32) - (1 * multiplier), 0));
- var endx = parseInt(Math.min((spr.x / 32) + 1 + (1 * multiplier), game.state.states.game.map.width));
- var endy = parseInt(Math.min((spr.y / 32) + 1 + (1 * multiplier), game.state.states.game.map.width));
-
- for ( var x = startx ; x <= endx ; x++ ) {
- for ( var y = starty ; y <= endy ; y++ ) {
- if ( (x == startx && y == starty) ||
- (x == startx && y == endy) ||
- (y == starty) ||
- (y == endy) ) {
- console.log(pathfinder_grid);
- if ( pathfinder_grid.nodes[x][y].walkable == true ) {
- console.log([x, y]);
- return [x, y];
- }
- }
- }
- }
- return null;
+SoundSprite.prototype.adjust_relative_to = function(spr) {
+ if ( this.sound_nofade == true ) {
+ this.sound.volume = this.sound_volume;
+ return;
}
- for ( var i = 1 ; i < 100 ; i++ ) {
- var rv = _walkable_inner(i);
- if ( rv !== null ) {
- console.log("Found near walkable tile");
- console.log([rv] + [spr.x / 32, spr.y / 32]);
- return rv
- }
- }
- //if ( multiplier >= 10 )
- console.log("Couldn't find a near walkable tile");
- console.log([spr.x / 32, spr.y / 32]);
- return [parseInt(spr.x / 32), parseInt(spr.y / 32)];
- //return nearestWalkableTile(spr, multiplier + 1);
-}
+ // The volume of any given sound is equal to the length of the
+ // hypotenuse of a triangle drawn from the point (p) to the
+ // sprite in question
-function addAnimation(obj, anim)
-{
- a = moonlightSettings['animations'][anim]
- obj.animations.add(anim, a['frames'], a['speed'], a['loop'])
-}
+ var xd = (spr.x - this.x);
+ if ( xd < 0 )
+ xd = -(xd);
+ var yd = (spr.y - this.y);
+ if ( yd < 0 )
+ yd = -(yd);
+ var hyp = Math.sqrt(Number(xd * xd) + Number(yd * yd));
+
+ this.sound.volume = (1.0 - Number(hyp / this.sound_distance));
+ // Math.max doesn't work here??
+ if ( this.sound.volume < 0 )
+ this.sound.volume = 0;
+}
var GameState = function(game) {
}
@@ -1329,7 +1451,7 @@ GameState.prototype.create = function()
);
if ( lp['inject_sprites'] == true ) {
this.aiSprites = game.add.group();
- this.aiSprites.debug = true;
+ this.aiSprites.debug = false;
this.map.createFromObjects('AI', 3544, 'player', 0, true, false, this.aiSprites, AISprite);
this.aiSprites.forEach(function(spr) {
spr.update_new_values();
@@ -1468,139 +1590,6 @@ GameState.prototype.updateShadowTexture = function() {
this.shadowTexture.dirty = true;
};
-function getFaceState(spr)
-{
- if ( hasState(spr, STATE_FACE_LEFT) )
- return STATE_FACE_LEFT;
- if ( hasState(spr, STATE_FACE_RIGHT) )
- return STATE_FACE_RIGHT;
- if ( hasState(spr, STATE_FACE_DOWN) )
- return STATE_FACE_DOWN;
- if ( hasState(spr, STATE_FACE_UP) )
- return STATE_FACE_UP;
-}
-
-function getMoveState(spr)
-{
- return ( hasState(spr, STATE_MOVING) ||
- hasState(spr, STATE_RUNNING) );
-}
-
-function delState(spr, state)
-{
- if ( hasState(spr, state) )
- spr.state = spr.state ^ state;
-}
-
-function addState(spr, state)
-{
- spr.state = spr.state | state;
-}
-
-function setMovingState(spr, state)
-{
- delState(spr, STATE_FACE_LEFT);
- delState(spr, STATE_FACE_RIGHT);
- delState(spr, STATE_FACE_DOWN);
- delState(spr, STATE_FACE_UP);
- delState(spr, STATE_MOVING);
- delState(spr, STATE_RUNNING);
- addState(spr, state);
-}
-
-function setAwarenessState(spr, state)
-{
- delState(spr, STATE_UNAWARE);
- delState(spr, STATE_CONCERNED);
- delState(spr, STATE_ALERTED);
- delState(spr, STATE_LOSTHIM);
- addState(spr, state);
-}
-
-function exchangeState(spr, state1, state2)
-{
- delState(spr, state1);
- addState(spr, state2);
-}
-
-function hasAnyState(spr, states)
-{
- var hasstate = false;
- states.forEach(function(x) {
- if ( hasState(spr, x) )
- hasstate = true;
- }, this);
- return hasstate;
-}
-
-function hasState(spr, state)
-{
- if ( (spr.state & state) == state )
- return true;
- return false;
-}
-
-function spriteFacing(spr)
-{
- if ( hasState(spr, STATE_FACE_LEFT) )
- return "left";
- if ( hasState(spr, STATE_FACE_RIGHT) )
- return "right";
- if ( hasState(spr, STATE_FACE_DOWN) )
- return "down";
- if ( hasState(spr, STATE_FACE_UP) )
- return "up";
-}
-
-function parseBoolean(val)
-{
- return ( val == 'true' || val == true );
-}
-
-function setSpriteMovement(spr, velocity)
-{
- var x = 0;
- var y = 0;
- var dir = spriteFacing(spr);
- velocity = ( typeof velocity == undefined ? velocity : [SPEED_WALKING,
- SPEED_RUNNING] );
-
- spr.body.setSize(16, 16, 8, 16);
-
- if ( hasState(spr, STATE_RUNNING) ) {
- if ( velocity !== false )
- velocity = velocity[1];
- spr.animations.play("bipedrun" + dir);
- } else if ( hasState(spr, STATE_MOVING) ) {
- if ( velocity !== false )
- velocity = velocity[0];
- spr.animations.play("bipedwalk" + dir);
- } else {
- if ( velocity !== false ) {
- spr.body.velocity.x = 0;
- spr.body.velocity.y = 0;
- }
- spr.animations.stop();
- return;
- }
-
- if ( velocity !== false ) {
- if ( dir == "left" ) {
- spr.body.velocity.x = -(velocity * velocity);
- spr.body.velocity.y = 0;
- } else if ( dir == "right" ) {
- spr.body.velocity.x = (velocity * velocity);
- spr.body.velocity.y = 0;
- } else if ( dir == "up" ) {
- spr.body.velocity.x = 0;
- spr.body.velocity.y = -(velocity * velocity);
- } else if ( dir == "down" ) {
- spr.body.velocity.x = 0;
- spr.body.velocity.y = (velocity * velocity);
- }
- }
-}
-
GameState.prototype.check_input = function()
{
player.body.velocity.x = 0;
@@ -1661,7 +1650,10 @@ GameState.prototype.update_player_lightmeter = function() {
}
}, this)
player.lightmeter = lightValue;
- this.lightbar_crop.width = (this.lightbar_image.width * lightValue);
+ this.lightbar_crop.width = Math.min(
+ this.lightbar_image.width,
+ ((this.lightbar_image.width /2) + ((this.lightbar_image.width/2)* lightValue))
+ );
this.lightbar.crop(this.lightbar_crop);
}
@@ -1811,8 +1803,20 @@ Preloader.prototype.create = function()
tween.onComplete.add(goalready, this);
}
+
+
+var pathfinder = null;
+var pathfinder_grid = null;
+
+var game = new Phaser.Game(640, 480, Phaser.AUTO, '');
+
game.state.add('boot', Boot, false);
game.state.add('preloader', Preloader, false);
game.state.add('game', GameState, false);
game.state.start('boot');
+
+
+
+
+
diff --git a/moonlight/src/AISprite.js b/moonlight/src/AISprite.js
new file mode 100644
index 0000000..046ae2c
--- /dev/null
+++ b/moonlight/src/AISprite.js
@@ -0,0 +1,535 @@
+var AISprite = function(game, x, y, key, frame) {
+ this.viewRectangle = function() {
+ var offset = [];
+ var size = [];
+ var multiplier = 1.0;
+ if ( hasState(this, STATE_ALERTED) ) {
+ multiplier = 2.0;
+ }
+
+ if ( hasState(this, STATE_FACE_LEFT) ) {
+ offset = [0, -32 * multiplier];
+ size = [-this.view_distance, 96];
+ } else if ( hasState(this, STATE_FACE_RIGHT) ) {
+ offset = [32, -32 * multiplier];
+ size = [32 + this.view_distance, 96];
+ } else if ( hasState(this, STATE_FACE_DOWN) ) {
+ offset = [-32 * multiplier, 32];
+ size = [96, this.view_distance];
+ } else if ( hasState(this, STATE_FACE_UP) ) {
+ offset = [-32 * multiplier, 0];
+ size = [96, -this.view_distance];
+ } else {
+ return null;
+ }
+ size[0] *= multiplier;
+ size[1] *= multiplier;
+ return positiveRectangle(this.x + offset[0],
+ this.y + offset[1],
+ size[0],
+ size[1]);
+ }
+
+ this.canSeeSprite = function(spr, debug) {
+ var vd = this.view_distance;
+ if ( hasState(this, STATE_FACE_LEFT) ||
+ hasState(this, STATE_FACE_UP) ) {
+ // Without this the player can stand in our view distance
+ // but as long as their left edge is 1 px out we won't see them,
+ // with this we see their near edge
+ vd = vd + 32;
+ }
+ if ( hasState(this, STATE_ALERTED) )
+ vd = vd * 2;
+
+ var distance = (new Phaser.Line(spr.x, spr.y, this.x, this.y).length);
+ if ( distance > vd ) {
+ return false;
+ }
+
+ var viewrect = this.viewRectangle();
+ if ( viewrect == null ) {
+ return false;
+ }
+ var sprrect = positiveRectangle(spr.x, spr.y, 32, 32);
+ if ( viewrect.intersects(sprrect) || viewrect.containsRect(sprrect) ) {
+ return true;
+ }
+ return false;
+ }
+
+ this.enableAwarenessChange = function(state) {
+ this.awareness_change_enabled = true;
+ }
+
+ this.startAwarenessTimer = function() {
+ this.awareness_change_enabled = false;
+ if ( this.awareness_timer !== null )
+ this.awareness_timer.stop();
+ this.awareness_timer = game.time.create(false);
+ this.awareness_timer.add(this.sprite_awareness_duration,
+ this.enableAwarenessChange,
+ this);
+ this.awareness_timer.start()
+ }
+
+ this.setAwarenessEffect = function(state) {
+ var animkey = "";
+
+ if ( hasState(this, state) == true ) {
+ // restart the awareness timer
+ this.startAwarenessTimer();
+ return;
+ } else if ( (state == STATE_LOSTHIM) &&
+ (hasState(this, STATE_ALERTED) == false) &&
+ (hasState(this, STATE_CONCERNED) == false) ) {
+ return;
+ }
+
+ if ( this.awareness_change_enabled == false &&
+ state != STATE_ALERTED ) {
+ return;
+ }
+ this.startAwarenessTimer();
+ setAwarenessState(this, state);
+
+ if ( this.awareness_effect !== null ) {
+ this.awareness_effect.alive = false;
+ this.awareness_effect.destroy();
+ this.awareness_effect = null;
+ }
+ if ( state == STATE_ALERTED ) {
+ animkey = "alerted";
+ } else if ( state == STATE_CONCERNED ) {
+ animkey = "concerned";
+ } else if ( state == STATE_LOSTHIM ) {
+ if ( this.sprite_group == "townsfolk-guard" ) {
+ animkey = "angry";
+ } else {
+ animkey = "relieved";
+ }
+ }
+
+ if ( animkey == "" )
+ return;
+
+ this.bubble_immediate = true;
+ this.clearWordBubble();
+ this.awareness_effect = game.state.states.game.add.sprite(
+ this.x + 16,
+ this.y - 16,
+ 'balloon');
+ addAnimation(this.awareness_effect, animkey);
+ this.awareness_effect.play(animkey, null, false, true);
+ }
+
+ this.enableWordBubble = function() {
+ this.enable_word_bubble = true;
+ this.timer = game.time.create(false);
+ if ( this.bubble_immediate == true ) {
+ this.bubble_immediate = false;
+ this.setWordBubble();
+ } else {
+ var timerdelta = 10000 + (game.rnd.integerInRange(0, 20) * 1000);
+ timerev = this.timer.add(timerdelta, this.setWordBubble, this);
+ this.timer.start()
+ }
+ }
+
+ this.clearWordBubble = function() {
+ if ( this.bubble_text !== null )
+ this.clear_bubble = true;
+ this.enable_word_bubble = false;
+ this.timer = game.time.create(false);
+ timerev = this.timer.add(1000, this.enableWordBubble, this);
+ this.timer.start()
+ }
+
+ this.setWordBubble = function()
+ {
+ if ( this.bubble_text !== null ||
+ this.sprite_group == undefined ||
+ this.enable_world_bubble == false) {
+ return;
+ }
+
+ aistate = this.state & ( STATE_UNAWARE | STATE_CONCERNED | STATE_ALERTED | STATE_LOSTHIM );
+ switch ( aistate ) {
+ case STATE_UNAWARE: {
+ aistate = "unaware";
+ break;
+ }
+ case STATE_CONCERNED: {
+ aistate = "concerned";
+ break;
+ }
+ case STATE_ALERTED: {
+ aistate = "alerted";
+ break;
+ }
+ case STATE_LOSTHIM: {
+ aistate = "losthim";
+ break;
+ }
+ }
+
+ var mylines = moonlightDialog['status'][this.sprite_group][aistate];
+ bubbleimg = game.cache.getImage('wordbubble');
+ text = mylines[game.rnd.integerInRange(0, mylines.length-1)];
+ style = {font: '14px Arial Bold', fill: '#ffffff'}
+ this.text_size = stringSize(text, style['font']);
+ this.bubble_sprite = game.add.sprite(this.x, this.y, 'wordbubble');
+ this.bubble_sprite.anchor.setTo(0.5, 1.0);
+ this.bubble_sprite.scale.x = Number((this.text_size[0] + 16) / bubbleimg.width);
+ this.bubble_sprite.scale.y = Number((this.text_size[1] + 16) / bubbleimg.height);
+ this.bubble_text = game.add.text(this.x, this.y, text, style);
+ this.snap_bubble_position();
+
+ this.timer = game.time.create(false);
+ timerev = this.timer.add(5000, this.clearWordBubble, this);
+ this.timer.start()
+ }
+
+ this.snap_bubble_position = function()
+ {
+ this.bubble_sprite.x = this.x + 16;
+ this.bubble_sprite.y = this.y;
+ var tx = this.bubble_sprite.x - (this.text_size[0]/2);
+ var ty = this.bubble_sprite.y - (this.bubble_sprite.height) + 8;
+ this.bubble_text.position.x = tx;
+ this.bubble_text.position.y = ty;
+ }
+
+ this.blocked = function() {
+ function f() {
+ if ( hasState(this, STATE_FACE_LEFT) &&
+ this.body.blocked.left == true )
+ return true;
+ if ( hasState(this, STATE_FACE_RIGHT) &&
+ this.body.blocked.right == true )
+ return true;
+ if ( hasState(this, STATE_FACE_DOWN) &&
+ this.body.blocked.down == true )
+ return true;
+ if ( hasState(this, STATE_FACE_UP) &&
+ this.body.blocked.up == true )
+ return true;
+ return false;
+ }
+ return f();
+ }
+
+ this.path_purge = function() {
+ this.path = [];
+ this.path_index = 0;
+ }
+
+ this.path_set = function(target, force, maxsteps) {
+ maxsteps = (typeof maxsteps == undefined ? maxsteps : this.path_maximum_steps);
+ force = ( typeof force == undefined ? false : force );
+ if ( force == false &&
+ this.path.length > 0 &&
+ this.path_index < this.path.length ) {
+ return false;
+ }
+ this.path_purge();
+ var pos = nearestWalkableTile(target);
+ tpath = pathfinder.findPath(
+ parseInt(this.x/32),
+ parseInt(this.y/32),
+ pos[0],
+ pos[1],
+ pathfinder_grid.clone()
+ );
+ prevpoint = [this.x, this.y];
+ console.log("New path has at most " + maxsteps + " steps in it");
+ for ( var i = 0 ; i < Math.min(maxsteps, tpath.length) ; i++ ) {
+ if ( (prevpoint[0]+prevpoint[1]) == ((tpath[i][0]*32)+(tpath[i][1]*32)) )
+ continue;
+ this.path.push(new Phaser.Line(prevpoint[0], prevpoint[1],
+ tpath[i][0]*32, tpath[i][1]*32));
+ prevpoint = [tpath[i][0]*32, tpath[i][1]*32];
+ }
+ return true;
+ }
+
+ this.path_tween_start = function(movingstate)
+ {
+ movingState = (typeof movementState == undefined ? movementState : (STATE_MOVING | STATE_RUNNING));
+ this.path_tweens = [];
+ prevpos = [this.x, this.y]
+ for ( var i = 0;
+ i < this.path.length ;
+ i++ ) {
+ pl = this.path[i];
+ movingstate = STATE_MOVING | STATE_RUNNING;
+ if ( pl.end.x < prevpos[0]) {
+ movingstate = movingstate | STATE_FACE_LEFT;
+ } else if ( pl.end.x > prevpos[0] ) {
+ movingstate = movingstate | STATE_FACE_RIGHT;
+ }
+ if ( pl.end.y < prevpos[1] ) {
+ movingstate = movingstate | STATE_FACE_UP;
+ } else if ( pl.end.y > prevpos[1] ) {
+ movingstate = movingstate | STATE_FACE_DOWN;
+ }
+ prevpos = [pl.end.x, pl.end.y];
+ tween = game.add.tween(this);
+ tween.movingstate = movingstate;
+ this.path_tweens.push(tween);
+ tween.to(
+ {x: (pl.end.x), y: (pl.end.y)},
+ (TWEEN_DURATION_PERPIXEL_RUNNING * pl.length),
+ null);
+ tween.onStart.add(function() {
+ setMovingState(this._object, this.movingstate);
+ this._object.animations.play("bipedrun" + spriteFacing(this._object));
+ }, tween);
+ tween.onComplete.add(function() {
+ this._object.path_index += 1;
+ setMovingState(this._object, getFaceState(this._object));
+ this._object.animations.play("bipedrun" + spriteFacing(this._object));
+ this._object.animations.stop();
+ }, tween);
+ if ( i > 0 ) {
+ this.path_tweens[i-1].onComplete.add(tween.start,
+ tween);
+ }
+ }
+ if ( this.path_tweens.length > 0 )
+ this.path_tweens[0].start();
+ }
+
+ this.path_tween_stop = function()
+ {
+ this.path_tweens.forEach(function(x) {
+ x.stop();
+ game.tweens.remove(x);
+ }, this);
+ }
+
+ this.turnUnseenDirection = function() {
+ if ( this.seen_directions.length >= 4 )
+ this.seen_directions = [];
+ var directions = [STATE_FACE_DOWN, STATE_FACE_LEFT,
+ STATE_FACE_RIGHT, STATE_FACE_UP];
+ var newdirection = directions[game.rnd.integerInRange(0, 3)];
+ while ( this.seen_directions.indexOf(newdirection) !== -1 ) {
+ newdirection = directions[game.rnd.integerInRange(0, 3)];
+ }
+ setMovingState(this, newdirection);
+ this.animations.stop();
+ this.animations.play("bipedrun" + spriteFacing(this));
+ this.animations.stop();
+ if ( this.rotation_timer !== null ) {
+ this.rotation_timer.stop();
+ this.rotation_timer = null;
+ }
+ }
+
+ this.chasetarget = function(target, alertedState, movingstate, visual, maxsteps)
+ {
+ alertedState = (typeof alertedState == undefined ? STATE_ALERTED : alertedState);
+ visual = (typeof visual == undefined ? false : visual);
+ movingstate = (typeof alertedState == undefined ? STATE_NONE : movingstate);
+ if ( game.physics.arcade.collide(this, target) )
+ return;
+
+ if ( this.path_index >= this.path.length ) {
+ this.path_tween_stop();
+ if ( (visual == false) || (this.canSeeSprite(target, false) == true )) {
+ this.setAwarenessEffect(alertedState);
+ this.path_set(target, true, maxsteps);
+ this.path_tween_start(movingstate);
+ } else {
+ if ( this.rotation_timer == null ) {
+ this.rotation_timer = game.time.create(false);
+ timerev = this.rotation_timer.add(250, this.turnUnseenDirection, this);
+ this.rotation_timer.start()
+ }
+ }
+ } else {
+ if ( this.path_set(target, this.blocked(true), maxsteps) == true ) {
+ if ( (visual == false) || (this.canSeeSprite(target, false) == false )) {
+ this.path_purge();
+ this.path_tween_stop();
+ } else {
+ this.setAwarenessEffect(alertedState);
+ this.path_tween_start(movingstate);
+ }
+ }
+ }
+ }
+
+ this.action_chaseplayer = function()
+ {
+ this.chasetarget(player,
+ STATE_ALERTED,
+ STATE_MOVING | STATE_RUNNING,
+ true);
+ return;
+ }
+
+ this.action_reportplayer = function()
+ {
+ if ( (this.path.length < 1) || this.path_index >= this.path.length) {
+ if ( hasState(this, STATE_RUNNINGTOLIGHT) == false ) {
+ var aiSprites = game.state.states.game.aiSprites;
+ this.target = nearestInGroup(this, aiSprites, "townsfolk-guard");
+ }
+ }
+ if ( this.target !== null &&
+ hasState(this, STATE_RUNNINGTOLIGHT) == false ) {
+ if ( (game.physics.arcade.collide(this, this.target) == true) ) {
+ this.path_tween_stop();
+ this.path_purge();
+ var staticLights = game.state.states.game.staticLights;
+ this.target = nearestInGroup(this, staticLights);
+ console.log("Running to the nearest light");
+ console.log(this.target);
+ addState(this, STATE_RUNNINGTOLIGHT);
+ }
+ this.chasetarget(this.target,
+ STATE_ALERTED,
+ STATE_MOVING | STATE_RUNNING,
+ false,
+ 1000);
+ }
+ }
+
+ this.action_huntplayer = function()
+ {
+ console.log("I AM HUNTING FOR THE PLAYER");
+ setSpriteMovement(this);
+ }
+
+ this.action_wander = function()
+ {
+ var newstate = STATE_NONE;
+ if ( this.sprite_canmove == false) {
+ return;
+ }
+ if ( game.rnd.integerInRange(0, 100) < 95 )
+ return;
+ this.turnUnseenDirection();
+ addState(this, STATE_MOVING);
+ setSpriteMovement(this);
+ }
+
+ this.update = function()
+ {
+ if ( this.ready_to_update == false )
+ return;
+ if ( this.awareness_effect !== null ) {
+ if ( this.awareness_effect.alive == false ) {
+ this.awareness_effect.destroy();
+ this.awareness_effect = null;
+ } else {
+ this.awareness_effect.x = this.x + 16;
+ this.awareness_effect.y = this.y - 16;
+ }
+ }
+
+ if ( this.bubble_text !== null ) {
+ if ( this.clear_bubble == true ) {
+ this.bubble_text.destroy();
+ this.bubble_sprite.destroy();
+ this.bubble_text = null;
+ this.bubble_sprite = null;
+ this.clear_bubble = false;
+ } else {
+ this.snap_bubble_position();
+ }
+ }
+
+ if ( hasState(this, STATE_ALERTED) ) {
+ if ( this.sprite_group == "townsfolk-guard" ) {
+ this.action_chaseplayer();
+ } else {
+ this.action_reportplayer();
+ }
+ } else if ( hasAnyState(this, [STATE_CONCERNED, STATE_LOSTHIM]) ) {
+ this.action_huntplayer();
+ } else {
+ this.action_wander();
+ }
+ }
+
+ this.update_new_values = function() {
+ if ( this.timer !== null )
+ this.timer.stop();
+ this.animations.destroy();
+ this.clearWordBubble();
+ this.state = STATE_UNAWARE;
+ this.sprite_can_see_lightmeter = Number(this.sprite_can_see_lightmeter);
+ this.sprite_canmove = parseBoolean(this.sprite_canmove);
+ this.sprite_awareness_duration = parseInt(this.sprite_awareness_duration);
+ this.collide_with_player = parseBoolean(this.collide_with_player);
+ this.collide_with_map = parseBoolean(this.collide_with_map);
+ this.carries_light = parseBoolean(this.carries_light);
+
+ this.path_maximum_steps = parseInt(this.path_maximum_steps);
+ this.loadTexture(this.sprite_name, 0);
+ addAnimation(this, 'bipedwalkleft');
+ addAnimation(this, 'bipedwalkright');
+ addAnimation(this, 'bipedwalkup');
+ addAnimation(this, 'bipedwalkdown');
+ addAnimation(this, 'bipedrunleft');
+ addAnimation(this, 'bipedrunright');
+ addAnimation(this, 'bipedrunup');
+ addAnimation(this, 'bipedrundown');
+ setMovingState(this, STATE_FACE_DOWN);
+ setSpriteMovement(this);
+ this.ready_to_update = true;
+ }
+
+ var spritenames_by_type = [
+ 'townsfolk-male-1',
+ 'townsfolk-male-2',
+ 'townsfolk-male-3',
+ 'townsfolk-male-4',
+ 'townsfolk-female-1',
+ 'townsfolk-female-2',
+ 'townsfolk-female-3',
+ 'townsfolk-female-4',
+ 'townsfolk-guard-1',
+ 'townsfolk-guard-2'
+ ];
+
+ this.ready_to_update = false;
+ Phaser.Sprite.call(this, game, x, y, null);
+ game.physics.arcade.enable(this);
+ this.body.immovable = true;
+ pathfinder_grid = [];
+ this.walkables = [];
+ this.path = [];
+ this.target = null;
+ this.path_tweens = [];
+ this.path_maximum_steps = 4;
+ this.awareness_change_enabled = true;
+ this.lightmeter = 1.0;
+ this.sprite_can_see_lightmeter = 0.3;
+ this.awareness_effect = null;
+ this.awareness_timer = null;
+ this.lastSawPlayerAt = null;
+ this.seen_directions = [];
+ this.sprite_awareness_duration = 60000;
+ this.sprite_canmove = 'true';
+ this.collide_with_player = 'true';
+ this.collide_with_map = 'true';
+ this.carries_light = 'false';
+ this.view_distance = 32 * 5;
+ this.timer = null;
+ this.rotation_timer = null;
+ this.origin = new Phaser.Point(x, y);
+ this.bubble_immediate = false;
+ this.bubble_text = null;
+ this.enable_word_bubble = false;
+ this.body.collideWorldBounds = true;
+ this.sprite_name = "townsfolk-male-1";
+ this.sprite_group = "townsfolk-male";
+ this.update_new_values();
+}
+
+AISprite.prototype = Object.create(Phaser.Sprite.prototype);
+AISprite.prototype.constructor = AISprite;
diff --git a/moonlight/src/Constants.js b/moonlight/src/Constants.js
new file mode 100644
index 0000000..5a1fd31
--- /dev/null
+++ b/moonlight/src/Constants.js
@@ -0,0 +1,44 @@
+SPEED_WALKING = 8;
+SPEED_RUNNING = 14;
+
+// Millisecond durations per tweens, per tile
+TWEEN_DURATION_PERPIXEL_RUNNING = 5;
+TWEEN_DURATION_PERPIXEL_WALKING = 9;
+TWEEN_DURATION_PERTILE_RUNNING = TWEEN_DURATION_PERPIXEL_RUNNING * 32;
+TWEEN_DURATION_PERTILE_WALKING = TWEEN_DURATION_PERPIXEL_WALKING * 32;
+
+STATE_NONE = 0;
+STATE_UNAWARE = 1 << 1;
+STATE_CONCERNED = 1 << 2;
+STATE_ALERTED = 1 << 3;
+STATE_LOSTHIM = 1 << 4;
+
+STATE_RUNNING = 1 << 5;
+STATE_FACE_LEFT = 1 << 6;
+STATE_FACE_RIGHT = 1 << 7;
+STATE_FACE_UP = 1 << 8;
+STATE_FACE_DOWN = 1 << 9;
+STATE_MOVING = 1 << 10;
+
+STATE_RUNNINGTOLIGHT = 1 << 11;
+
+STATES_AWARENESS = (STATE_UNAWARE | STATE_CONCERNED | STATE_ALERTED | STATE_LOSTHIM);
+STATES_MOVEMENT = (STATE_MOVING | STATE_RUNNING);
+STATES_FACE = (STATE_FACE_LEFT | STATE_FACE_RIGHT | STATE_FACE_DOWN | STATE_FACE_UP);
+
+SPRITE_TOWNSFOLK_MALE = 1;
+SPRITE_TOWNSFOLK_FEMALE = 2;
+SPRITE_TOWNSFOLK_GUARD = 3;
+
+SPRITE_TOWNSFOLK_MALE1 = 1;
+SPRITE_TOWNSFOLK_MALE2 = 2;
+SPRITE_TOWNSFOLK_MALE3 = 3;
+SPRITE_TOWNSFOLK_MALE4 = 4;
+
+SPRITE_TOWNSFOLK_FEMALE1 = 5;
+SPRITE_TOWNSFOLK_FEMALE2 = 6;
+SPRITE_TOWNSFOLK_FEMALE3 = 7;
+SPRITE_TOWNSFOLK_FEMALE4 = 8;
+
+SPRITE_TOWNSFOLK_GUARD1 = 9;
+SPRITE_TOWNSFOLK_GUARD2 = 10;
diff --git a/moonlight/src/Dialogue.js b/moonlight/src/Dialogue.js
new file mode 100644
index 0000000..e37a9dc
--- /dev/null
+++ b/moonlight/src/Dialogue.js
@@ -0,0 +1,132 @@
+var moonlightDialog = {
+ "status": {
+ "townsfolk-male" : {
+ "unaware" : [
+ "I'd rather be fishing.",
+ "Different day, same old stuff.",
+ "Oi! Where'd that trouble run\noff to now then?",
+ "The missus is off shoppin', and\nhere I am sittin' on\nme Jack Jones.",
+ "Oy I'm gonna have a butcher’s at\nthat new tailor's knickers\nhe has for sale.",
+ "I'm off to the pub to see the\nlads and chew the fat.",
+ "♪ ♫ Whistling ♪ ♫"
+ ],
+ "concerned" : [
+ "Wha… what’s that? Who’s there?",
+ "Did you hear that?",
+ "Either I’m hearin’ things, or I\nneed to stop drinkin’ midday.",
+ "Oi? I don’t want no tomfoolery;\ncome out if you’re there!",
+ "Must be them darned kids again.",
+ "What’s that?",
+ "Did you see that?"
+ ],
+ "alerted" : [
+ "Don't you come no closer, you hear?",
+ "Egads!",
+ "I'm getting’ outta here!",
+ "What's going on?!",
+ "Holy bejeezus!",
+ "Did you see that?",
+ "What're you doing?!",
+ "Get away!",
+ "Get away from me!",
+ "Stay away! I know Kung-fu! ... but\nthat would require bravery \nI don't have",
+ "Guards! GUARDS!"
+ ],
+ "losthim" : [
+ "Whew. Glad that’s over.",
+ "I wasn’t scared!",
+ "Must’ve been intimidated by\nmy manly physique.",
+ "That’s right! Run away!",
+ "Aye, and don’t-cha come back!",
+ "Spoony Bard...",
+ "Bloody wanker!"
+ ]
+ },
+ "townsfolk-female" : {
+ "unaware" : [
+ "My retro shake brings all the\nboys to the yard.",
+ "I'm off to get my Barnet sorted\nout. I’ll be the best looking\nlady at the gala.",
+ "It's always all itsy bitsy with\nthem boys at the Rub-a-Dub.",
+ "I need to get this shopping\nsorted out.",
+ "What a lovely evening. Perfect\nfor skulking, I would imagine."
+ ],
+ "concerned" : [
+ "Wha… what’s that? Who’s there?",
+ "Did you hear that?",
+ "Martha? Is that you?",
+ "I don't want no tomfoolery.\nGo away!",
+ "What was that? This is how horror\ntheatre bits start…",
+ "What's that?",
+ "Did you see that?"
+ ],
+ "alerted" : [
+ "Eeeek!",
+ "Stay away from me!",
+ "Guards! Guards!",
+ "What in the nine hells?",
+ "Get back or I'll swoon!",
+ "Help! He's after me virtue!"
+ ],
+ "losthim" : [
+ "Good riddance! There’s too many\nmale protagonists in\ngames anyhow!",
+ "I sure am glad that’s over.",
+ "This town is going straight to hell.",
+ "I hope he doesn’t come back.",
+ "I hope he’s caught and hanged!"
+ ]
+ },
+ "townsfolk-guard" : {
+ "unaware" : [
+ "Just doing my civic duty.",
+ "Good day, citizens.",
+ "Honor. Liberty. Justice.\nOh, and pancakes…\nI love pancakes.",
+ "No loitering.",
+ "I am the law.",
+ "May Evil beware and may\nGood dress warmly and\neat plenty of fresh vegetables.",
+ "We're sworn to protect The City."
+ ],
+ "concerned" : [
+ "I sense law-breaking abound.",
+ "Did you hear something?",
+ "Did you see that?",
+ "I know you're around here\nsomewhere, rat…",
+ "Don't make me look for\nyou in hard-to-reach places!",
+ "The eyes play tricks\nlike tiny, round devils."
+ ],
+ "alerted" : [
+ "Surrender lawbreaker!",
+ "Halt!",
+ "Halt! In the name of the… umm, er… me!",
+ "Prepare for justice, criminal!",
+ "I am justice!",
+ "There’s no escaping the law!",
+ "Surrender thief!",
+ "Prepare to taste steel!",
+ "Clear the area! Nobody\npanic! I'll catch him!"
+ ],
+ "losthim" : [
+ "I’ll get you next time,\ncriminal scum.",
+ "Defeat is a harsh mistress.",
+ "Evil men may get away, but\njustice fights another day.",
+ "Wickedness flees, evading the\ncold steel of righteousness."
+ ]
+ }
+ },
+ "conversations": {
+ "townsfolk-male": {
+ "townsfolk-female": [],
+ "townsfolk-male": [],
+ "townsfolk-guard": []
+ },
+ "townsfolk-female": {
+ "townsfolk-male": [],
+ "townsfolk-female": [],
+ "townsfolk-guard": [],
+ },
+ "townsfolk-guard": {
+ "townsfolk-male": [],
+ "townsfolk-female": [],
+ "townsfolk-guard": []
+ }
+ }
+};
diff --git a/moonlight/src/EffectSprite.js b/moonlight/src/EffectSprite.js
new file mode 100644
index 0000000..8646617
--- /dev/null
+++ b/moonlight/src/EffectSprite.js
@@ -0,0 +1,17 @@
+var EffectSprite = function(game, x, y, key, frame, animation) {
+ this.update_new_values = function() {
+ this.animations.destroy();
+ this.loadTexture(this.sprite_key, 0);
+ addAnimation(this, this.sprite_animation);
+ this.animations.play(this.sprite_animation);
+ }
+
+ Phaser.Sprite.call(this, game, x, y, null);
+ game.physics.arcade.enable(this);
+ this.collide_with_map = true;
+ this.collide_with_player = false;
+}
+
+EffectSprite.prototype = Object.create(Phaser.Sprite.prototype);
+EffectSprite.prototype.constructor = EffectSprite;
+
diff --git a/moonlight/src/GameStates.js b/moonlight/src/GameStates.js
new file mode 100644
index 0000000..ee10f75
--- /dev/null
+++ b/moonlight/src/GameStates.js
@@ -0,0 +1,378 @@
+var GameState = function(game) {
+}
+
+GameState.prototype.create = function()
+{
+ this.map = this.add.tilemap('map');
+ for (var k in moonlightSettings['map']['tilesets']) {
+ var ts = moonlightSettings['map']['tilesets'][k];
+ this.map.addTilesetImage(ts['name']);
+ }
+ this.map_collision_layers = [];
+ pfgrid = [];
+
+ for (var ln in moonlightSettings['map']['layers']) {
+ lp = moonlightSettings['map']['layers'][ln];
+ if ( lp['type'] == "tiles" ) {
+ layer = this.map.createLayer(ln);
+ this.map.setCollisionBetween(
+ lp['collisionBetween'][0],
+ lp['collisionBetween'][1],
+ lp['collides'],
+ ln
+ );
+ if ( lp['inject_sprites'] == true ) {
+ this.aiSprites = game.add.group();
+ this.aiSprites.debug = false;
+ this.map.createFromObjects('AI', 3544, 'player', 0, true, false, this.aiSprites, AISprite);
+ this.aiSprites.forEach(function(spr) {
+ spr.update_new_values();
+ }, this)
+ player = this.add.sprite((19 * 32), (21 * 32), 'player');
+ player.lightmeter = 0;
+
+ };
+ if ( lp['collides'] == true ) {
+ this.map_collision_layers.push(layer);
+ for (var i = 0; i < layer.layer.data.length; i++)
+ {
+ if ( i >= pfgrid.length )
+ pfgrid[i] = [];
+ for (var j = 0; j < layer.layer.data[i].length; j++)
+ {
+ if (layer.layer.data[i][j].index > 0) {
+ pfgrid[i][j] = 1;
+ } else if ( pfgrid[i][j] != 1 ) {
+ pfgrid[i][j] = 0;
+ }
+ }
+ }
+ }
+ layer.resizeWorld();
+ }
+ }
+
+ pathfinder_grid = new PF.Grid(this.map.width,
+ this.map.height,
+ pfgrid);
+ pathfinder = new PF.AStarFinder({allowDiagonal: false});
+
+ this.physics.arcade.enable(player);
+ player.body.center = new Phaser.Point(player.body.width / 2, player.body.height + player.body.halfHeight);
+ player.body.collideWorldBounds = true;
+ //player.body.immovable = true;
+
+ addAnimation(player, 'bipedwalkleft');
+ addAnimation(player, 'bipedwalkright');
+ addAnimation(player, 'bipedwalkup');
+ addAnimation(player, 'bipedwalkdown');
+ addAnimation(player, 'bipedrunleft');
+ addAnimation(player, 'bipedrunright');
+ addAnimation(player, 'bipedrunup');
+ addAnimation(player, 'bipedrundown');
+
+ this.camera.follow(player, Phaser.Camera.FOLLOW_TOPDOWN);
+ controls = game.input.keyboard.createCursorKeys();
+
+ this.effectSprites = game.add.group();
+ this.map.createFromObjects('EffectSprites', 5, 'player', 0, true, false, this.effectSprites, EffectSprite);
+ this.effectSprites.forEach(function(spr) {
+ spr.update_new_values();
+ }, this)
+
+ this.shadowTexture = game.add.bitmapData(game.world.width, game.world.height);
+ // drop this lower to make the map darker
+ this.shadowTextureColor = 'rgb(60, 60, 60)';
+ this.shadowSprite = game.add.image(0, 0, this.shadowTexture);
+
+ this.shadowSprite.blendMode = Phaser.blendModes.MULTIPLY;
+
+ this.staticLights = game.add.group();
+ this.map.createFromObjects('Lights', 97, 'player', 0, true, false, this.staticLights, Light);
+ this.staticLights.forEach(function(light) {
+ light.update_new_values();
+ }, this)
+
+ this.staticSounds = game.add.group();
+ this.map.createFromObjects('Sounds', 11, 'player', 0, true, false, this.staticSounds, SoundSprite);
+ this.staticSounds.forEach(function(snd) {
+ snd.update_new_values();
+ }, this)
+
+ this.bubble_group = game.add.group();
+
+ this.uigroup = game.add.group();
+ this.game.time.advancedTiming = true;
+ this.fpsText = this.game.add.text(
+ 20, 20, '', { font: '16px Arial', fill: '#ffffff' }, this.uigroup
+ );
+ this.lightbox = this.game.add.image(game.camera.width / 2 - 50,
+ game.camera.height - 40,
+ 'lightbox',
+ 0,
+ this.uigroup);
+ this.lightbar = this.game.add.image(this.lightbox.x + 3,
+ this.lightbox.y + 3,
+ 'lightbar',
+ 0,
+ this.uigroup);
+ this.lightbar_image = game.cache.getImage('lightbar');
+ this.lightbar_crop = positiveRectangle(0,
+ 0,
+ this.lightbar_image.width,
+ this.lightbar_image.height);
+ this.uigroup.setAll('fixedToCamera', true);
+}
+
+GameState.prototype.updateShadowTexture = function() {
+ this.shadowTexture.context.fillStyle = this.shadowTextureColor;
+ this.shadowTexture.context.fillRect(0, 0, game.world.width, game.world.height);
+
+ this.staticLights.forEach(function(light) {
+ if ( light.always_render !== true ) {
+ var r1 = positiveRectangle(this.game.camera.x,
+ this.game.camera.y,
+ this.game.camera.width,
+ this.game.camera.height);
+ if ( ! light.rect.intersects(r1) ) {
+ return;
+ }
+ }
+
+ if ( light.flicker ) {
+ var radius = light.radius + game.rnd.integerInRange(1,10);
+ } else {
+ var radius = light.radius;
+ }
+ light.rendered_radius = radius;
+
+ var gradient =
+ this.shadowTexture.context.createRadialGradient(
+ light.x + 16, light.y + 16, light.fade,
+ light.x + 16, light.y + 16, radius);
+ gradient.addColorStop(0, light.color_start);
+ gradient.addColorStop(1, light.color_stop);
+
+ this.shadowTexture.context.beginPath();
+ this.shadowTexture.context.fillStyle = gradient;
+ this.shadowTexture.context.arc(light.x + 16, light.y + 16, radius, 0, Math.PI*2);
+ this.shadowTexture.context.fill();
+ }, this);
+
+ this.shadowTexture.dirty = true;
+};
+
+GameState.prototype.check_input = function()
+{
+ player.body.velocity.x = 0;
+ player.body.velocity.y = 0;
+ velocityMod = 0;
+ var newstate = 0;
+
+ if ( controls.up.isDown) {
+ if ( controls.up.shiftKey ) {
+ newstate = (STATE_FACE_UP | STATE_MOVING | STATE_RUNNING);
+ } else {
+ newstate = (STATE_FACE_UP | STATE_MOVING );
+ }
+ } else if ( controls.down.isDown ) {
+ if ( controls.down.shiftKey ) {
+ newstate = (STATE_FACE_DOWN | STATE_MOVING | STATE_RUNNING);
+ } else {
+ newstate = (STATE_FACE_DOWN | STATE_MOVING );
+ }
+ } else if ( controls.left.isDown ) {
+ if ( controls.left.shiftKey ) {
+ newstate = (STATE_FACE_LEFT | STATE_MOVING | STATE_RUNNING);
+ } else {
+ newstate = (STATE_FACE_LEFT | STATE_MOVING );
+ }
+ } else if ( controls.right.isDown ) {
+ if ( controls.right.shiftKey ) {
+ newstate = (STATE_FACE_RIGHT | STATE_MOVING | STATE_RUNNING);
+ } else {
+ newstate = (STATE_FACE_RIGHT | STATE_MOVING );
+ }
+ } else {
+ newstate = STATE_NONE;
+ }
+
+ setMovingState(player, newstate);
+ setSpriteMovement(player);
+}
+
+GameState.prototype.update_player_lightmeter = function() {
+ lightValue = 0;
+ this.staticLights.forEach(function(light) {
+ var left = player.x;
+ var top = player.y + 32;
+
+ if ( player.y < this.y )
+ top = player.y;
+ if ( player.x + this.x )
+ left = player.x + 32;
+
+ line = new Phaser.Line(left, top, light.x + 16, light.y + 16);
+ if ( line.length > light.rendered_radius)
+ return;
+ var length = line.length;
+ var lv = light.light_meter - (Number(length) / Number(light.rendered_radius));
+ if ( lv > lightValue ) {
+ lightValue = lv;
+ }
+ }, this)
+ player.lightmeter = lightValue;
+ this.lightbar_crop.width = Math.min(
+ this.lightbar_image.width,
+ ((this.lightbar_image.width /2) + ((this.lightbar_image.width/2)* lightValue))
+ );
+ this.lightbar.crop(this.lightbar_crop);
+}
+
+GameState.prototype.update = function()
+{
+ this.check_input();
+ this.update_player_lightmeter();
+
+ for (var ln in this.map_collision_layers ) {
+ layer = this.map_collision_layers[ln];
+ this.physics.arcade.collide(player, layer);
+ }
+
+ function _fix_audio_relative(x) {
+ x.adjust_relative_to(player);
+ }
+ this.staticSounds.forEach(_fix_audio_relative, this);
+
+ function _inner_collide(x) {
+ if ( x.collide_with_map == true ) {
+ for ( var ln in this.map_collision_layers ) {
+ layer = this.map_collision_layers[ln];
+ this.physics.arcade.collide(x, layer);
+ }
+ }
+ if ( x.collide_with_player == false )
+ return;
+ if ( x.canSeeSprite(player, false) == true ) {
+ x.lastSawPlayerAt = new Phaser.Point(player.x, player.y);
+ if ( this.physics.arcade.collide(x, player) ) {
+ x.setAwarenessEffect(STATE_ALERTED);
+ } else if ( player.lightmeter >= x.sprite_can_see_lightmeter ) {
+ x.setAwarenessEffect(STATE_ALERTED);
+ } else {
+ x.setAwarenessEffect(STATE_CONCERNED);
+ }
+ return;
+ } else {
+ if ( hasState(x, STATE_LOSTHIM) == false ) {
+ x.setAwarenessEffect(STATE_LOSTHIM);
+ } else {
+ x.setAwarenessEffect(STATE_UNAWARE);
+ }
+ }
+ this.physics.arcade.collide(x, player);
+ }
+
+ this.effectSprites.forEach(_inner_collide, this);
+
+ this.aiSprites.forEach(_inner_collide, this);
+ this.updateShadowTexture();
+
+ if ( this.aiSprites.debug == true ) {
+ function _draw_viewrect(x) {
+ var r = x.viewRectangle();
+ if ( r == null )
+ return;
+ this.shadowTexture.context.fillStyle = 'rgb(128, 128, 128)';
+ this.shadowTexture.context.fillRect(r.left,
+ r.top,
+ r.width,
+ r.height);
+ }
+ this.aiSprites.forEach(_draw_viewrect, this);
+ function _draw_aipath(x) {
+ var p = x.path;
+ if ( p == null )
+ return;
+ this.shadowTexture.context.fillStyle = 'rgb(255, 128, 128)';
+ p.forEach(function(r) {
+ this.shadowTexture.context.fillRect(r.start.x,
+ r.start.y,
+ r.end.x - r.start.x,
+ r.end.y - r.start.y);
+ }, this);
+ }
+ this.aiSprites.forEach(_draw_aipath, this);
+ }
+ if (game.time.fps !== 0) {
+ this.fpsText.setText(game.time.fps + ' FPS');
+ }
+}
+
+function Boot()
+{
+ Phaser.State.call(game, this);
+}
+
+var Boot = function(game) {
+}
+
+Boot.prototype.preload = function()
+{
+ game.load.image('preloader', 'gfx/ui/preloader.png');
+};
+
+Boot.prototype.create = function()
+{
+ this.input.maxPointers = 1;
+ this.stage.disableVisibilityChange = false;
+ this.stage.scale.pageAlignHoritzontally = true;
+ game.state.start('preloader', true, false);
+}
+
+var Preloader = function(game) {
+}
+
+Preloader.prototype.preload = function()
+{
+ this.preloadBar = game.add.sprite(0, 0, 'preloader');
+ this.preloadBar.anchor.setTo(0.5, 0.5);
+ this.preloadBar.x = game.camera.x + (game.camera.width / 2);
+ this.preloadBar.y = game.camera.y + (game.camera.width / 2);
+ game.load.setPreloadSprite(this.preloadBar, 0);
+
+ for (var k in moonlightSettings['map']['tilesets']) {
+ var ts = moonlightSettings['map']['tilesets'][k];
+ this.load.image(ts['name'], ts['path']);
+ }
+ for (var k in moonlightSettings['images']) {
+ var i = moonlightSettings['images'][k];
+ this.load.image(i['name'], i['path']);
+ }
+ for (var k in moonlightSettings['sounds']) {
+ var s = moonlightSettings['sounds'][k];
+ this.load.audio(s['name'], s['path']);
+ }
+ for (var k in moonlightSettings['spritesheets']) {
+ var s = moonlightSettings['spritesheets'][k]
+ game.load.spritesheet(s['name'], s['path'], s['width'], s['height'], s['frames'])
+ }
+
+ this.load.tilemap('map',
+ moonlightSettings['map']['path'],
+ null,
+ Phaser.Tilemap.TILED_JSON);
+}
+
+Preloader.prototype.create = function()
+{
+ function goalready() {
+ this.preloadBar.destroy();
+ game.state.start('game', true, false);
+ }
+
+ var tween = this.add.tween(this.preloadBar).to({ alpha: 0 }, 1000, Phaser.Easing.Linear.None, true);
+ tween.onComplete.add(goalready, this);
+}
+
+
diff --git a/moonlight/src/Light.js b/moonlight/src/Light.js
new file mode 100644
index 0000000..91462fb
--- /dev/null
+++ b/moonlight/src/Light.js
@@ -0,0 +1,39 @@
+
+// Create torch objects
+// Light constructor
+var Light = function(game, x, y, key, frame, radius, fade, color_start, color_stop, flicker, always_render, light_meter) {
+ color_start = ( typeof color_start == undefined ? color_start : 'rgba(255, 255, 255, 1.0)');
+ color_stop = ( typeof color_stop == undefined ? color_stop : 'rgba(255, 255, 255, 0.0)');
+ fade = ( typeof fade == undefined ? fade : 0.25);
+ radius = ( typeof radius == undefined ? radius : 64);
+ flicker = ( typeof flicker == undefined ? flicker : false);
+ always_render = ( typeof always_render == undefined ? always_render : false);
+ light_meter = ( typeof light_meter == undefined ? light_meter : 1.0 );
+ Phaser.Sprite.call(this, game, x, y, null);
+
+ // Set the pivot point for this sprite to the center
+ this.anchor.setTo(0.5, 0.5);
+
+ this.color_start = color_start;
+ this.color_stop = color_stop;
+ this.radius = radius;
+ this.rendered_radius = radius;
+ this.fade = radius * fade
+ this.light_meter = light_meter;
+ this.always_render = always_render
+ this.rect = positiveRectangle(this.x - radius, this.y - radius, radius * 2, radius * 2)
+ this.flicker = flicker;
+};
+
+// Lightes are a type of Phaser.Sprite
+Light.prototype = Object.create(Phaser.Sprite.prototype);
+Light.prototype.constructor = Light;
+
+Light.prototype.update_new_values = function() {
+ this.light_meter = Number(this.light_meter);
+ this.radius = parseInt(this.radius);
+ this.fade = this.radius * Number(this.fade);
+ this.flicker = parseBoolean(this.flicker);
+ this.always_render = parseBoolean(this.always_render);
+ this.rect = positiveRectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2)
+}
diff --git a/moonlight/src/Settings.js b/moonlight/src/Settings.js
new file mode 100644
index 0000000..b93c83b
--- /dev/null
+++ b/moonlight/src/Settings.js
@@ -0,0 +1,333 @@
+var moonlightSettings = {
+ 'map' : {
+ 'tilesets': [
+ {
+ 'name': 'bigtop',
+ 'path': 'gfx/tiles/bigtop.png'
+ },
+ {
+ 'name': '002-Woods01',
+ 'path': 'gfx/tiles/002-Woods01.png'
+ },
+ {
+ 'name': '009-CastleTown01',
+ 'path': 'gfx/tiles/009-CastleTown01.png'
+ },
+ {
+ 'name': '010-CastleTown02',
+ 'path': 'gfx/tiles/010-CastleTown02.png'
+ },
+ {
+ 'name': '025-Castle01',
+ 'path': 'gfx/tiles/025-Castle01.png'
+ },
+ {
+ 'name': '026-Castle02',
+ 'path': 'gfx/tiles/026-Castle02.png'
+ },
+ {
+ 'name': '027-Castle03',
+ 'path': 'gfx/tiles/027-Castle03.png'
+ },
+ {
+ 'name': '027-Castle03',
+ 'path': 'gfx/tiles/027-Castle03.png'
+ },
+ {
+ 'name': '028-Church01',
+ 'path': 'gfx/tiles/028-Church01.png'
+ },
+ {
+ 'name': '029-Church02',
+ 'path': 'gfx/tiles/029-Church02.png'
+ },
+ {
+ 'name': '034-Bridge01',
+ 'path': 'gfx/tiles/034-Bridge01.png'
+ },
+ {
+ 'name': '035-Ruins01',
+ 'path': 'gfx/tiles/035-Ruins01.png'
+ },
+ {
+ 'name': '037-Fort01',
+ 'path': 'gfx/tiles/037-Fort01.png'
+ },
+ {
+ 'name': '038-Fort02',
+ 'path': 'gfx/tiles/038-Fort02.png'
+ },
+ {
+ 'name': '039-Tower01',
+ 'path': 'gfx/tiles/039-Tower01.png'
+ },
+ {
+ 'name': '040-Tower02',
+ 'path': 'gfx/tiles/040-Tower02.png'
+ },
+ {
+ 'name': '041-EvilCastle01',
+ 'path': 'gfx/tiles/041-EvilCastle01.png'
+ },
+ {
+ 'name': '042-EvilCastle02',
+ 'path': 'gfx/tiles/042-EvilCastle02.png'
+ },
+ {
+ 'name': '048-Sewer01',
+ 'path': 'gfx/tiles/048-Sewer01.png'
+ },
+ {
+ 'name': '004-Mountain01',
+ 'path': 'gfx/tiles/004-Mountain01.png'
+ },
+ {
+ 'name': '!Door1',
+ 'path': 'gfx/tiles/Doors.png'
+ }
+ ],
+ 'layers': {
+ '0 - NonCollide Base': {
+ 'collides': false,
+ 'collisionBetween': [0, 0],
+ 'type': 'tiles',
+ 'inject_sprites': false
+ },
+ '0 - Collide Base': {
+ 'collides': true,
+ 'collisionBetween': [0, 9999],
+ 'type': 'tiles',
+ 'inject_sprites': false
+ },
+ '0 - NonCollide Overlay - Pathways': {
+ 'collides': false,
+ 'collisionBetween': [0, 9999],
+ 'type': 'tiles',
+ 'inject_sprites': false
+ },
+ '0 - NonCollide Overlay - Below Player': {
+ 'collides': false,
+ 'collisionBetween': [0, 9999],
+ 'type': 'tiles',
+ 'inject_sprites': false
+ },
+ '0 - Collide Overlay - Ground Objects': {
+ 'collides': true,
+ 'collisionBetween': [0, 9999],
+ 'type': 'tiles',
+ 'inject_sprites': true
+ },
+ '0 - NonCollide Overlay - Above Player (Short)': {
+ 'collides': false,
+ 'collisionBetween': [0, 9999],
+ 'type': 'tiles',
+ 'inject_sprites': false
+ },
+ '0 - NonCollide Overlay - Above Player (Tall)': {
+ 'collides': false,
+ 'collisionBetween': [0, 9999],
+ 'type': 'tiles',
+ 'inject_sprites': false
+ }
+ },
+ 'path': 'gfx/map.json'
+ },
+ 'sounds': [
+ {
+ 'name': 'fountain',
+ 'path': 'sfx/fountain.wav'
+ },
+ {
+ 'name': 'fire',
+ 'path': 'sfx/fire.ogg'
+ },
+ {
+ 'name': 'calliope',
+ 'path': 'sfx/calliope.mp3'
+ }
+ ],
+ 'images': [
+ {
+ 'name': 'lightbox',
+ 'path': 'gfx/ui/lightbox.png'
+ },
+ {
+ 'name': 'lightbar',
+ 'path': 'gfx/ui/lightbar.png'
+ },
+ {
+ 'name': 'wordbubble',
+ 'path': 'gfx/effects/wordbubble.png'
+ }
+ ],
+ 'spritesheets': [
+ {
+ 'name': 'flame',
+ 'path': 'gfx/effects/flame.png',
+ 'width': 32,
+ 'height': 32,
+ 'frames': 96
+ },
+ {
+ 'name': 'balloon',
+ 'path': 'gfx/effects/Balloon.png',
+ 'width': 32,
+ 'height': 32,
+ 'frames': 80
+ },
+ {
+ 'name': 'player',
+ 'path': 'gfx/sprites/sprite-player.png',
+ 'width': 32,
+ 'height': 32,
+ 'frames': 12
+ },
+ {
+ 'name': 'townsfolk-male-1',
+ 'path': 'gfx/sprites/sprite-townsfolk-male-1.png',
+ 'width': 32,
+ 'height': 32,
+ 'frames': 12
+ },
+ {
+ 'name': 'townsfolk-male-2',
+ 'path': 'gfx/sprites/sprite-townsfolk-male-2.png',
+ 'width': 32,
+ 'height': 32,
+ 'frames': 12
+ },
+ {
+ 'name': 'townsfolk-male-3',
+ 'path': 'gfx/sprites/sprite-townsfolk-male-3.png',
+ 'width': 32,
+ 'height': 32,
+ 'frames': 12
+ },
+ {
+ 'name': 'townsfolk-male-4',
+ 'path': 'gfx/sprites/sprite-townsfolk-male-4.png',
+ 'width': 32,
+ 'height': 32,
+ 'frames': 12
+ },
+ {
+ 'name': 'townsfolk-female-1',
+ 'path': 'gfx/sprites/sprite-townsfolk-female-1.png',
+ 'width': 32,
+ 'height': 32,
+ 'frames': 12
+ },
+ {
+ 'name': 'townsfolk-female-2',
+ 'path': 'gfx/sprites/sprite-townsfolk-female-2.png',
+ 'width': 32,
+ 'height': 32,
+ 'frames': 12
+ },
+ {
+ 'name': 'townsfolk-female-3',
+ 'path': 'gfx/sprites/sprite-townsfolk-female-3.png',
+ 'width': 32,
+ 'height': 32,
+ 'frames': 12
+ },
+ {
+ 'name': 'townsfolk-female-4',
+ 'path': 'gfx/sprites/sprite-townsfolk-female-4.png',
+ 'width': 32,
+ 'height': 32,
+ 'frames': 12
+ },
+ {
+ 'name': 'townsfolk-guard-1',
+ 'path': 'gfx/sprites/sprite-townsfolk-guard-1.png',
+ 'width': 32,
+ 'height': 32,
+ 'frames': 12
+ },
+ {
+ 'name': 'townsfolk-guard-2',
+ 'path': 'gfx/sprites/sprite-townsfolk-guard-2.png',
+ 'width': 32,
+ 'height': 32,
+ 'frames': 12
+ }
+ ],
+ 'animations': {
+ 'alerted': {
+ 'frames': [0, 1, 2, 3, 4, 5, 6, 7],
+ 'speed': 4,
+ 'loop': false
+ },
+ 'concerned': {
+ 'frames': [8, 9, 10, 11, 12, 13, 14, 15],
+ 'speed': 4,
+ 'loop': false
+ },
+ 'relieved': {
+ 'frames': [40, 41, 42, 43, 44, 45, 46, 47],
+ 'speed': 4,
+ 'loop': false
+ },
+ 'angry': {
+ 'frames': [48, 49, 50, 51, 52, 53, 54, 55],
+ 'speed': 4,
+ 'loop': false
+ },
+ 'bipedwalkdown': {
+ 'frames': [1, 2, 0],
+ 'speed': 4,
+ 'loop': true
+ },
+ 'bipedwalkleft': {
+ 'frames': [4, 5, 3],
+ 'speed': 4,
+ 'loop': true
+ },
+ 'bipedwalkright': {
+ 'frames': [7, 8, 6],
+ 'speed': 4,
+ 'loop': true
+ },
+ 'bipedwalkup': {
+ 'frames': [10, 11, 9],
+ 'speed': 4,
+ 'loop': true
+ },
+ 'bipedrundown': {
+ 'frames': [1, 2, 0],
+ 'speed': 12,
+ 'loop': true
+ },
+ 'bipedrunleft': {
+ 'frames': [4, 5, 3],
+ 'speed': 12,
+ 'loop': true
+ },
+ 'bipedrunright': {
+ 'frames': [7, 8, 6],
+ 'speed': 12,
+ 'loop': true
+ },
+ 'bipedrunup': {
+ 'frames': [10, 11, 9],
+ 'speed': 12,
+ 'loop': true
+ },
+ 'lantern_small': {
+ 'frames': [24, 25, 26],
+ 'speed': 6,
+ 'loop': true
+ },
+ 'campfire_small': {
+ 'frames': [6, 7, 8],
+ 'speed': 6,
+ 'loop': true
+ },
+ 'fire_small': {
+ 'frames': [9, 10, 11],
+ 'speed': 6,
+ 'loop': true
+ }
+ }
+};
diff --git a/moonlight/src/SoundSprite.js b/moonlight/src/SoundSprite.js
new file mode 100644
index 0000000..c15208d
--- /dev/null
+++ b/moonlight/src/SoundSprite.js
@@ -0,0 +1,79 @@
+function SoundSprite(game, x, y, key, frame,
+ sound_key,
+ sound_marker,
+ sound_position,
+ sound_volume,
+ sound_loop,
+ sound_forcerestart,
+ sound_distance,
+ sound_nofade)
+{
+ Phaser.Sprite.call(this, game, x, y, null);
+ this.sound_key = sound_key;
+ this.sound_marker = ( typeof sound_marker == undefined ? sound_marker : '');
+ this.sound_volume = ( typeof sound_volume == undefined ? sound_volume : 1.0 );
+ this.sound_position = ( typeof sound_position == undefined ? sound_position : 1.0 );
+ this.sound_loop = ( typeof sound_loop == undefined ? sound_loop : true );
+ this.sound_forcerestart = ( typeof sound_forcerestart == undefined ? sound_forcerestart : false );
+ var def_distance = Math.sqrt(
+ Number((game.camera.width/2) * (game.camera.width/2)) +
+ Number((game.camera.height/2) * (game.camera.height/2))
+ );
+ this.sound_distance = ( typeof sound_distance == undefined ? sound_distance : def_distance);
+ this.sound_nofade = (typeof sound_nofade == undefined ? sound_nofade : false);
+
+ this.sound = null;
+}
+
+SoundSprite.prototype = Object.create(Phaser.Sprite.prototype);
+SoundSprite.prototype.constructor = Light;
+
+SoundSprite.prototype.update_new_values = function() {
+ if ( this.sound_key == null ) {
+ if ( this.sound !== null ) {
+ this.sound.stop();
+ }
+ return;
+ }
+ this.sound_position = parseInt(this.sound_position);
+ this.sound_distance = Number(this.sound_distance);
+ this.sound_volume = Number(this.sound_volume);
+ this.sound_loop = parseBoolean(this.sound_loop);
+ this.sound_forcerestart = parseBoolean(this.sound_forcerestart);
+ this.sound_nofade = parseBoolean(this.sound_nofade);
+
+ if ( this.sound !== null )
+ this.sound.stop();
+ this.sound = game.add.audio(this.sound_key, this.sound_volume, this.sound_loop);
+ this.sound.play(
+ this.sound_marker,
+ this.sound_position,
+ this.sound_volume,
+ this.sound_loop,
+ this.sound_forcerestart);
+}
+
+SoundSprite.prototype.adjust_relative_to = function(spr) {
+ if ( this.sound_nofade == true ) {
+ this.sound.volume = this.sound_volume;
+ return;
+ }
+
+ // The volume of any given sound is equal to the length of the
+ // hypotenuse of a triangle drawn from the point (p) to the
+ // sprite in question
+
+ var xd = (spr.x - this.x);
+ if ( xd < 0 )
+ xd = -(xd);
+ var yd = (spr.y - this.y);
+ if ( yd < 0 )
+ yd = -(yd);
+
+ var hyp = Math.sqrt(Number(xd * xd) + Number(yd * yd));
+
+ this.sound.volume = (1.0 - Number(hyp / this.sound_distance));
+ // Math.max doesn't work here??
+ if ( this.sound.volume < 0 )
+ this.sound.volume = 0;
+}
diff --git a/moonlight/src/Util.js b/moonlight/src/Util.js
new file mode 100644
index 0000000..40efb63
--- /dev/null
+++ b/moonlight/src/Util.js
@@ -0,0 +1,249 @@
+// Return new array with duplicate values removed
+function array_unique(arr) {
+ var a = [];
+ var l = arr.length;
+ for(var i=0; i' + x + '')
+ .css({'position': 'absolute', 'float': 'left', 'visibility': 'hidden', 'font': f})
+ .appendTo($('body'));
+ if ( o.width() > width )
+ width = o.width();
+ height += 5 + o.height();
+ o.remove();
+ }, this);
+ return [width, height];
+}
+
+function rotatePoints(arr, x, y, degrees)
+{
+ arr.forEach(function(p) {
+ p.rotate(x, y, degrees, true);
+ }, this);
+}
+
+function positiveRectangle(x, y, w, h) {
+ if ( w < 0 ) {
+ w = -(w);
+ x = x - w;
+ }
+ if ( h < 0 ) {
+ h = -(h);
+ y = y - h;
+ }
+ return new Phaser.Rectangle(x, y, w, h);
+}
+
+function nearestInGroup(sprite, group, sprite_group) {
+ var nearest = null;
+ var lastdist = 0.0;
+ for ( var i = 0 ; i < group.length; i++ ) {
+ console.log("Checking distance to group[" + i + "]");
+ var spr = group.getChildAt(i);
+ console.log(spr);
+ if ( (typeof sprite_group !== undefined) &&
+ spr.sprite_group !== sprite_group )
+ continue;
+ var dist = new Phaser.Line(sprite.x, sprite.y, spr.x, spr.y);
+ if ( (lastdist == 0.0 ) || (dist.length < lastdist) ) {
+ lastdist = dist.length;
+ nearest = spr;
+ }
+ }
+ return nearest;
+}
+
+function nearestWalkableTile(spr)
+{
+ function _walkable_inner(multiplier) {
+ var startx = parseInt(Math.max((spr.x / 32) - (1 * multiplier), 0));
+ var starty = parseInt(Math.max((spr.y / 32) - (1 * multiplier), 0));
+ var endx = parseInt(Math.min((spr.x / 32) + 1 + (1 * multiplier), game.state.states.game.map.width));
+ var endy = parseInt(Math.min((spr.y / 32) + 1 + (1 * multiplier), game.state.states.game.map.width));
+
+ for ( var x = startx ; x <= endx ; x++ ) {
+ for ( var y = starty ; y <= endy ; y++ ) {
+ if ( (x == startx && y == starty) ||
+ (x == startx && y == endy) ||
+ (y == starty) ||
+ (y == endy) ) {
+ console.log(pathfinder_grid);
+ if ( pathfinder_grid.nodes[x][y].walkable == true ) {
+ console.log([x, y]);
+ return [x, y];
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ for ( var i = 1 ; i < 100 ; i++ ) {
+ var rv = _walkable_inner(i);
+ if ( rv !== null ) {
+ console.log("Found near walkable tile");
+ console.log([rv] + [spr.x / 32, spr.y / 32]);
+ return rv
+ }
+ }
+ //if ( multiplier >= 10 )
+ console.log("Couldn't find a near walkable tile");
+ console.log([spr.x / 32, spr.y / 32]);
+ return [parseInt(spr.x / 32), parseInt(spr.y / 32)];
+ //return nearestWalkableTile(spr, multiplier + 1);
+}
+
+function addAnimation(obj, anim)
+{
+ a = moonlightSettings['animations'][anim]
+ obj.animations.add(anim, a['frames'], a['speed'], a['loop'])
+}
+
+function getFaceState(spr)
+{
+ if ( hasState(spr, STATE_FACE_LEFT) )
+ return STATE_FACE_LEFT;
+ if ( hasState(spr, STATE_FACE_RIGHT) )
+ return STATE_FACE_RIGHT;
+ if ( hasState(spr, STATE_FACE_DOWN) )
+ return STATE_FACE_DOWN;
+ if ( hasState(spr, STATE_FACE_UP) )
+ return STATE_FACE_UP;
+}
+
+function getMoveState(spr)
+{
+ return ( hasState(spr, STATE_MOVING) ||
+ hasState(spr, STATE_RUNNING) );
+}
+
+function delState(spr, state)
+{
+ if ( hasState(spr, state) )
+ spr.state = spr.state ^ state;
+}
+
+function addState(spr, state)
+{
+ spr.state = spr.state | state;
+}
+
+function setMovingState(spr, state)
+{
+ delState(spr, STATE_FACE_LEFT);
+ delState(spr, STATE_FACE_RIGHT);
+ delState(spr, STATE_FACE_DOWN);
+ delState(spr, STATE_FACE_UP);
+ delState(spr, STATE_MOVING);
+ delState(spr, STATE_RUNNING);
+ addState(spr, state);
+}
+
+function setAwarenessState(spr, state)
+{
+ delState(spr, STATE_UNAWARE);
+ delState(spr, STATE_CONCERNED);
+ delState(spr, STATE_ALERTED);
+ delState(spr, STATE_LOSTHIM);
+ addState(spr, state);
+}
+
+function exchangeState(spr, state1, state2)
+{
+ delState(spr, state1);
+ addState(spr, state2);
+}
+
+function hasAnyState(spr, states)
+{
+ var hasstate = false;
+ states.forEach(function(x) {
+ if ( hasState(spr, x) )
+ hasstate = true;
+ }, this);
+ return hasstate;
+}
+
+function hasState(spr, state)
+{
+ if ( (spr.state & state) == state )
+ return true;
+ return false;
+}
+
+function spriteFacing(spr)
+{
+ if ( hasState(spr, STATE_FACE_LEFT) )
+ return "left";
+ if ( hasState(spr, STATE_FACE_RIGHT) )
+ return "right";
+ if ( hasState(spr, STATE_FACE_DOWN) )
+ return "down";
+ if ( hasState(spr, STATE_FACE_UP) )
+ return "up";
+}
+
+function parseBoolean(val)
+{
+ return ( val == 'true' || val == true );
+}
+
+function setSpriteMovement(spr, velocity)
+{
+ var x = 0;
+ var y = 0;
+ var dir = spriteFacing(spr);
+ velocity = ( typeof velocity == undefined ? velocity : [SPEED_WALKING,
+ SPEED_RUNNING] );
+
+ spr.body.setSize(16, 16, 8, 16);
+
+ if ( hasState(spr, STATE_RUNNING) ) {
+ if ( velocity !== false )
+ velocity = velocity[1];
+ spr.animations.play("bipedrun" + dir);
+ } else if ( hasState(spr, STATE_MOVING) ) {
+ if ( velocity !== false )
+ velocity = velocity[0];
+ spr.animations.play("bipedwalk" + dir);
+ } else {
+ if ( velocity !== false ) {
+ spr.body.velocity.x = 0;
+ spr.body.velocity.y = 0;
+ }
+ spr.animations.stop();
+ return;
+ }
+
+ if ( velocity !== false ) {
+ if ( dir == "left" ) {
+ spr.body.velocity.x = -(velocity * velocity);
+ spr.body.velocity.y = 0;
+ } else if ( dir == "right" ) {
+ spr.body.velocity.x = (velocity * velocity);
+ spr.body.velocity.y = 0;
+ } else if ( dir == "up" ) {
+ spr.body.velocity.x = 0;
+ spr.body.velocity.y = -(velocity * velocity);
+ } else if ( dir == "down" ) {
+ spr.body.velocity.x = 0;
+ spr.body.velocity.y = (velocity * velocity);
+ }
+ }
+}
+
diff --git a/moonlight/src/main.js b/moonlight/src/main.js
new file mode 100644
index 0000000..4c952cc
--- /dev/null
+++ b/moonlight/src/main.js
@@ -0,0 +1,16 @@
+
+var pathfinder = null;
+var pathfinder_grid = null;
+
+var game = new Phaser.Game(640, 480, Phaser.AUTO, '');
+
+game.state.add('boot', Boot, false);
+game.state.add('preloader', Preloader, false);
+game.state.add('game', GameState, false);
+
+game.state.start('boot');
+
+
+
+
+