From adab130d17c9ae040b5ac7d2f672a75556db530a Mon Sep 17 00:00:00 2001 From: Andrew Kesterson Date: Sun, 22 Jun 2014 09:58:25 -0700 Subject: [PATCH] Breaking out source into separate files Get rid of backup files Refactored source out into multiple files --- moonlight/index.html | 20 +- moonlight/index_debug.html | 29 ++ moonlight/js/moonlight-skulk.js | 702 ++++++++++++++++---------------- moonlight/src/AISprite.js | 535 ++++++++++++++++++++++++ moonlight/src/Constants.js | 44 ++ moonlight/src/Dialogue.js | 132 ++++++ moonlight/src/EffectSprite.js | 17 + moonlight/src/GameStates.js | 378 +++++++++++++++++ moonlight/src/Light.js | 39 ++ moonlight/src/Settings.js | 333 +++++++++++++++ moonlight/src/SoundSprite.js | 79 ++++ moonlight/src/Util.js | 249 +++++++++++ moonlight/src/main.js | 16 + 13 files changed, 2214 insertions(+), 359 deletions(-) create mode 100644 moonlight/index_debug.html create mode 100644 moonlight/src/AISprite.js create mode 100644 moonlight/src/Constants.js create mode 100644 moonlight/src/Dialogue.js create mode 100644 moonlight/src/EffectSprite.js create mode 100644 moonlight/src/GameStates.js create mode 100644 moonlight/src/Light.js create mode 100644 moonlight/src/Settings.js create mode 100644 moonlight/src/SoundSprite.js create mode 100644 moonlight/src/Util.js create mode 100644 moonlight/src/main.js 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'); + + + + +