diff --git a/public_html/static/404.js b/public_html/static/404.js new file mode 100644 index 0000000..d572df2 --- /dev/null +++ b/public_html/static/404.js @@ -0,0 +1,156 @@ +var engine; + +$(function(){ + engine = new Engine({ + "enable_sound": false + }); + + loader = new engine.Preloader(); + loader.Run({ + onfinish: InitializeEffect + }); +}); + +function InitializeEffect() +{ + engine.AddItems({ + objects: { + controller: { + grid_w: 60, + grid_h: 18, + tile_w: 16, + tile_h: 16, + numbers: [], + colored: [], + OnCreate: function(event){ + for(var x = 0; x < this.grid_w; x++) + { + this.numbers[x] = []; + this.colored[x] = []; + } + + this.RegenerateNumbers(); + }, + OnMouseMove: function(event){ + this.SetMouse(event.x, event.y); + }, + OnStep: function(event){ + if(this.scene.step_counter % 15 == 0) + { + this.RegenerateNumbers(); + return true; + } + }, + OnDraw: function(event){ + for(var x = 0; x < this.grid_w; x++) + { + for(var y = 0; y < this.grid_h; y++) + { + if(this.colored[x][y]) + { + //var text = (this.colored[x][y]) ? "0" : this.numbers[x][y]; + var text = this.numbers[x][y]; + + this.scene.DrawText(text, { + x: x * this.tile_w, + y: y * this.tile_h, + color: (this.colored[x][y]) ? "blue" : "silver" + }); + } + } + } + }, + RegenerateNumbers: function(){ + for(var x = 0; x < this.grid_w; x++) + { + for(var y = 0; y < this.grid_h; y++) + { + this.numbers[x][y] = engine.Random.Choose(0, 1); + this.colored[x][y] = false; + } + } + + this.ApplyMouse(); + }, + SetMouse: function(x, y){ + this.mouse_x = x; + this.mouse_y = y; + this.ApplyMouse(); + }, + ApplyMouse: function(){ + this.ClearColored(); + + var matrix_w = 9; + var matrix_h = 14; + var matrix = [ + [0, 1, 1, 1, 1, 1, 1, 1, 1], + [0, 0, 1, 1, 1, 1, 1, 1, 1], + [0, 0, 0, 1, 1, 1, 1, 1, 1], + [0, 0, 0, 0, 1, 1, 1, 1, 1], + [0, 0, 0, 0, 0, 1, 1, 1, 1], + [0, 0, 0, 0, 0, 0, 1, 1, 1], + [0, 0, 0, 0, 0, 0, 0, 1, 1], + [0, 0, 0, 0, 0, 0, 0, 0, 1], + [0, 0, 0, 0, 0, 1, 1, 1, 1], + [0, 0, 1, 0, 0, 1, 1, 1, 1], + [0, 1, 1, 1, 0, 0, 1, 1, 1], + [1, 1, 1, 1, 0, 0, 1, 1, 1], + [1, 1, 1, 1, 1, 0, 0, 1, 1], + [1, 1, 1, 1, 1, 0, 0, 1, 1] + ]; + + for(var my = 0; my < matrix_h; my++) + { + for(var mx = 0; mx < matrix_w; mx++) + { + if(matrix[my][mx] == 0) + { + var target_x = Math.round(this.mouse_x / this.tile_w + mx); + var target_y = Math.round(this.mouse_y / this.tile_h + my) + 1; + + //console.log(target_x, target_y); + + if(target_x >= 0 && target_x < this.grid_w && target_y >= 0 && target_y < this.grid_h) + { + this.colored[target_x][target_y] = true; + } + } + } + } + + if(this.scene) + { + this.scene.Redraw(); + } + }, + ClearColored: function(){ + for(var x = 0; x < this.grid_w; x++) + { + for(var y = 0; y < this.grid_h; y++) + { + this.colored[x][y] = false; + } + } + } + } + }, + scenes: { + main: { + width: 960, + height: 288, + fps: 30, + OnLoad: function(event){ + this.Add("controller"); + }, + OnMouseMove: function(event){ + + } + } + } + }); + + var canvas = $("#404canvas")[0]; + engine.GetScene("main").Attach(canvas); + + $("#404canvas").show(); +} diff --git a/public_html/static/engine.js b/public_html/static/engine.js new file mode 100644 index 0000000..76e9745 --- /dev/null +++ b/public_html/static/engine.js @@ -0,0 +1,1456 @@ +/* Prototype modifications of standard types go here. */ + +HTMLCanvasElement.prototype.relativeCoordinates = function(event) +{ + var totalOffsetX = 0; + var totalOffsetY = 0; + var canvasX = 0; + var canvasY = 0; + var currentElement = this; + + do { + if(!$(currentElement).is('body')) + { + totalOffsetX += currentElement.offsetLeft - currentElement.scrollLeft; + totalOffsetY += currentElement.offsetTop - currentElement.scrollTop; + } + } while(currentElement = currentElement.offsetParent) + + canvasX = event.pageX - totalOffsetX; + canvasY = event.pageY - totalOffsetY; + + return {x:canvasX, y:canvasY} +} + +/* Core engine constructor. */ +function Engine(settings) +{ + this.resources = {}; + this.sprites = {}; + this.sounds = {}; + this.objects = {}; + this.scenes = {}; + this.canvas = null; + this.settings = settings; + this.loader_created = false; + this.instance_increment = 10000; + + _engine = this; + + /**--------------------------------------**/ + /** PRELOADER **/ + /**--------------------------------------**/ + + this.Preloader = function() + { + this._engine = _engine; + this.queue = []; + this.resources_left = 0; + this.resources_done = 0; + this.resources_total = 0; + this.resources_failed = 0; + this.images_total = 0; + this.scripts_total = 0; + this.sounds_total = 0; + this.sound_enabled = false; + this.sound_ignore_failure = false; + + if(this._engine.loader_created == false) + { + /* This is the first Preloader that is being created. Load scripts that are needed by the engine. */ + this._engine.loader_created = true; + + if(typeof this._engine.settings !== "undefined") + { + if(this._engine.settings["enable_sound"]) + { + this.AddScript("static/soundmanager2.js", "SoundManager2"); + + this.AddFunction(function(){ + soundManager.setup({ + url: 'static/', + onready: this._HandleSM2Ready.bind(this), + ontimeout: this._HandleSM2Failed.bind(this), + useHighPerformance: true, + preferFlash: false + }); + + return false; + }, "Initializing SoundManager2"); + } + else + { + this._engine.sound_enabled = false; + } + } + } + } + + /* Add function */ + this.Preloader.prototype.AddFunction = function(func, description) + { + this.queue.push({ + type: "function", + func: func.bind(this), + desc: description + }); + + this.resources_left++; + this.resources_total++; + } + + /* Add image */ + this.Preloader.prototype.AddImage = function(name, path) + { + this.queue.push({ + type: "image", + name: name, + path: path + }); + + this.resources_left++; + this.resources_total++; + } + + /* Add a dictionary of items */ + this.Preloader.prototype.AddItems = function(items) + { + if(typeof items.images != "undefined") + { + for(name in items.images) + { + this.AddImage(name, items.images[name]); + } + } + + if(typeof items.sounds != "undefined") + { + for(name in items.sounds) + { + this.AddSound(name, items.sounds[name]); + } + } + + if(typeof items.scripts != "undefined") + { + for(name in items.scripts) + { + this.AddScript(name, items.scripts[name]); + } + } + + if(typeof items.functions != "undefined") + { + for(name in items.functions) + { + this.AddFunction(name, items.functions[name]); + } + } + + } + + /* Add script file */ + this.Preloader.prototype.AddScript = function(path, description) + { + this.queue.push({ + type: "script", + path: path, + desc: description + }); + + this.resources_left++; + this.resources_total++; + } + + /* Add sound file */ + this.Preloader.prototype.AddSound = function(name, path) + { + this.queue.push({ + type: "sound", + name: name, + path: path + }); + + this.resources_left++; + this.resources_total++; + } + + /* Start the preloading sequence. */ + this.Preloader.prototype.Run = function(callbacks) + { + if(typeof callbacks == "undefined") + { + this.callbacks = {}; + } + else + { + this.callbacks = callbacks; + } + + this.RunCycle(); + } + + /* Process one item in the preloading sequence. */ + this.Preloader.prototype.RunCycle = function() + { + if(this.queue.length > 0) + { + current_object = this.queue.shift(); + + if(current_object.type == "image") + { + this._DoCallback(this.callbacks.onstagechange, { + type: "image", + description: current_object.path + }); + + current_image = new Image(); + current_image.onload = this._ReportResourceFinished.bind(this); + current_image.src = current_object.path; + + this.images_total++; + this._engine.resources[current_object.name] = current_image; + } + else if(current_object.type == "sound") + { + this._DoCallback(this.callbacks.onstagechange, { + type: "sound", + description: current_object.path + }); + + if(this._engine.sound_enabled == true) + { + if(soundManager.canPlayURL(current_object.path)) + { + var sound = soundManager.createSound({ + id: current_object.name, + url: current_object.path, + autoLoad: true, + autoPlay: false, + onload: this._ReportResourceFinished.bind(this) + }); + + this.sounds_total++; + this._engine.resources[current_object.name] = sound; + } + else + { + throw { + "name": "SoundError", + "message": "The sound format is not supported." + } + } + } + else if(this._engine.sound_ignore_failure == true) + { + /* TODO: Log error */ + } + else + { + throw { + "name": "SoundError", + "message": "Cannot add audio file because sound support is not enabled in the engine." + } + } + } + else if(current_object.type == "script") + { + this._DoCallback(this.callbacks.onstagechange, { + type: "script", + description: current_object.desc + }); + + $.getScript(current_object.path, this._ReportResourceFinished.bind(this)); + + this.scripts_total++; + } + else if(current_object.type == "function") + { + this._DoCallback(this.callbacks.onstagechange, { + type: "function", + description: current_object.desc + }); + + var result = current_object.func(this.callbacks); + + if(result == true) + { + this._ReportResourceFinished(); + } + } + } + else + { + this._DoCallback(this.callbacks.onfinish) + } + } + + /* Check if the preloading sequence is finished and take appropriate action. */ + this.Preloader.prototype._CheckIfDone = function() + { + if(this.resources_left <= 0) + { + this._DoCallback(this.callbacks.onfinish); + } + else + { + this.RunCycle(); + } + } + + /* Do a pre-specified callback if it exists. */ + this.Preloader.prototype._DoCallback = function(callback, data) + { + if(typeof callback != "undefined") + { + callback(data); + } + } + + /* Handle successful finishing of the SoundManager2 loading process. */ + this.Preloader.prototype._HandleSM2Ready = function() + { + this._engine.sound_enabled = true; + this._ReportResourceFinished(); + } + + /* Handle failure of the SoundManager2 loading process. */ + this.Preloader.prototype._HandleSM2Failed = function() + { + this._engine.sound_enabled = false; + this._ReportResourceFinished(); + } + + /* Mark the currently preloading resource as finished. */ + this.Preloader.prototype._ReportResourceFinished = function() + { + this.resources_left--; + this.resources_done++; + + this._DoCallback(this.callbacks.onprogress, { + done: this.resources_done, + total: this.resources_total, + left: this.resources_left, + failures: this.resources_failed + }); + + this._CheckIfDone(); + } + + /* Mark the currently preloading resource as failed. */ + this.Preloader.prototype._ReportResourceFailed = function() + { + /* TODO: Implement. */ + this.resources_left--; + this.resources_failed++; + } + + + /**--------------------------------------**/ + /** BASE PROPERTIES AND METHODS **/ + /**--------------------------------------**/ + + this.Base = { + timers: {}, + SetTimer: function(duration, func) + { + setTimeout((function(self, f){ return f.call.bind(f, self); })(this, func), duration); + }, + SetInterval: function(name, interval, func) + { + this.timers[name] = setInterval((function(self, f){ return f.call.bind(f, self); })(this, func), interval); + }, + CancelInterval: function(name) + { + clearInterval(this.timers[name]); + }, + CallEvent: function(func, data) + { + if(typeof func !== "undefined") + { + return func.call(this, data); + } + }, + _BubbleEvent: function(func, eventdata, instances) + { + list = instances.slice().reverse(); + + var hit_event = false; + + for(item in list) + { + var object = list[item]; + var result = object.CallEvent(object[func], eventdata); + + if(typeof result != "undefined") + { + if(result == false) + { + break; + } + else if(result == true) + { + hit_event = true; + } + } + } + + return hit_event; + } + } + + + /**--------------------------------------**/ + /** SCENES **/ + /**--------------------------------------**/ + + this.Scene = function(name, options) + { + if(typeof _engine.scenes[name] !== "undefined") + { + throw { + name: "NameError", + message: "A scene with the given name already exists." + } + } + + this._engine = _engine; + this.canvas = null; + this.instances = []; + this.dirty = true; + this.width = 640; + this.height = 480; + this.fps = 45; + this.name = name; + this.cached_selectors = {}; + this.mouse_coordinates = {x: 0, y: 0}; + this.step_counter = 0; + this.draw_counter = 0; + this.current_fps = 0; + this.date = new Date; + + $.extend(true, this, options, this._engine.Base); + + this._engine.scenes[name] = this; + } + + this.Scene.prototype.Add = function(object) + { + if(typeof object == "string") + { + if(typeof this._engine.objects[object] !== "undefined") + { + var instance = this._engine.CreateInstance(object); + } + else + { + throw { + "name": "ObjectError", + "message": "The specified object does not exist." + } + } + } + else + { + var instance = object; + } + + instance.scene = this; + this.instances.push(instance); + this.dirty = true; + } + + this.Scene.prototype.Attach = function(canvas) + { + if(typeof $(canvas).data("current-scene") !== "undefined") + { + /* A different scene was previously attached to this canvas. + * Let's detach it first. */ + var previous_scene = $(canvas).data("current-scene"); + this._engine.scenes[previous_scene].Detach(); + } + + this.canvas = canvas; + this._engine.canvas = canvas; + canvas.width = this.width; + canvas.height = this.height; + $(canvas).data("current-scene", this.name); + + $(canvas).click(this._ProcessClickEvent.bind(this)); + $(canvas).mousemove(this._ProcessMouseMoveEvent.bind(this)); + + this.CallEvent(this.OnLoad); + this._Initialize(); + } + + this.Scene.prototype.Detach = function() + { + $(this.canvas).unbind('click'); + $(this.canvas).unbind('mousemove'); + $(this.canvas).removeData("current-scene"); + this.canvas = null; + } + + this.Scene.prototype.DrawText = function(text, options) + { + var type = "fill", color = "#000000", x = 0, y = 0; + + if(typeof options.outline != "undefined" && options.outline) + { + type = "outline"; + } + + if(typeof options.color != "undefined") + { + color = options.color; + } + + if(typeof options.x != "undefined") + { + x = options.x; + } + + if(typeof options.y != "undefined") + { + y = options.y; + } + + ctx = this._GetTextContext(options); + + if(type == "fill") + { + ctx.fillStyle = color; + ctx.fillText(text, x, y); + } + else if(type == "outline") + { + ctx.strokeStyle = color; + ctx.outlineText(text, x, y); + } + + ctx.restore(); + } + + this.Scene.prototype.DrawTextCentered = function(text, options) + { + var x = 0, scale = 1, width = this.GetTextWidth(text, options); + + if(typeof options.x != "undefined") + { + x = options.x; + } + + if(typeof options.scale != "undefined") + { + scale = options.scale; + } + + x = x - ((width / 2) * scale * scale); + + options.x = x; + + this.DrawText(text, options); + } + + this.Scene.prototype.GetTextWidth = function(text, options) + { + ctx = this._GetTextContext(options); + var width = ctx.measureText(text).width; + ctx.restore(); + + return width; + } + + this.Scene.prototype.Redraw = function() + { + this.dirty = true; + } + + this.Scene.prototype.$ = function(selector) + { + if(typeof this.cached_selectors[selector] != "undefined") + { + return this.cached_selectors[selector]; + } + else + { + list = this._SelectInstances(this, this.instances, selector); + this.cached_selectors[selector] = list; + return list; + } + } + + this.Scene.prototype._Draw = function() + { + this.draw_count += 1; + + if(this.canvas !== null) + { + var ctx = this.canvas.getContext("2d"); + ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); + + for(i in this.instances) + { + this.instances[i]._Draw(); + } + } + } + + this.Scene.prototype._GetTextContext = function(options) + { + var weight = "normal", style = "normal", font = "sans-serif", size = 16, alpha = 1, scale = 1; + + if(typeof options.bold != "undefined" && options.bold) + { + weight = "bold"; + } + + if(typeof options.italic != "undefined" && options.italic) + { + style = "italic"; + } + + if(typeof options.size != "undefined") + { + size = options.size; + } + + if(typeof options.font != "undefined") + { + font = options.font; + } + + if(typeof options.alpha != "undefined") + { + alpha = options.alpha; + } + + if(typeof options.scale != "undefined") + { + scale = options.scale; + } + + var ctx = this.canvas.getContext("2d"); + + ctx.save(); + + ctx.font = weight + " " + style + " " + size + "px '" + font + "'"; + ctx.globalAlpha = alpha; + ctx.scale(scale, scale); + + return ctx; + } + + this.Scene.prototype._Initialize = function(event) + { + this.last_timestamp = this.date.getTime(); + this.SetInterval("_step", (1000/this.fps), this._Step); + } + + this.Scene.prototype._ProcessClickEvent = function(event) + { + var coordinates = this.canvas.relativeCoordinates(event); + + var changed = this._BubbleEvent("_HandleClickEvent", { + x: coordinates.x, + y: coordinates.y, + button: event.which + }, this.$("/" + coordinates.x + "," + coordinates.y)); + + if(changed == true) + { + this.dirty = true; + } + } + + this.Scene.prototype._ProcessMouseMoveEvent = function(event) + { + var coordinates = this.canvas.relativeCoordinates(event); + this.mouse_coordinates = coordinates; + this.mouse_moved = true; + } + + this.Scene.prototype._SelectInstances = function(context, items, selector) + { + var segments = selector.split("/"); + segments.shift(); + + methods = { + "coordinate": { + "regex": /^(!?)([0-9]+),([0-9]+)$/i, + "action": function(context, items, match){ + var inverted = (match[1] == "!"); + var x = match[2]; + var y = match[3]; + + return items.filter(function(object){ + var hit = false; + + if(object.draw_self === true) + { + var sprite = this._engine.GetSprite(object.sprite); + + if(x >= object.x && x < (object.x + sprite.width) && y > object.y && y < (object.y + sprite.height)) + { + /* Initial region test succeeded. + * TODO: Add bounding rectangles. */ + var relative_x = x - object.x; + var relative_y = y - object.y; + + if(object.precise_collision == false) + { + hit = true; + } + else + { + alpha = sprite.GetAlpha(relative_x, relative_y) / 255; + + if(alpha > object.collision_tolerance) + { + /* Alpha hit. */ + hit = true; + } + } + } + } + + if(inverted == true) + { + return !hit; + } + else + { + return hit; + } + }); + } + }, + "object": { + "regex": /^(!?)([a-z_][a-z0-9_+-]*)$/i, + "action": function(context, items, match){ + inverted = (match[1] == "!"); + name = match[2]; + + return items.filter(function(object){ + if(inverted) + { + return !(name == object.name); + } + else + { + return (name == object.name); + } + }); + } + } + } + + for(i in segments) + { + var segment = segments[i]; + + for(m in methods) + { + var method = methods[m]; + var match = method.regex.exec(segment); + + if(match != null) + { + items = method.action(context, items, match); + break; + } + } + } + + return items; + } + + this.Scene.prototype._Step = function(event) + { + this.step_counter++; + + if(this.step_counter == this.fps) + { + this.step_counter = 0; + + var date = new Date; + var current_timestamp = date.getTime() + this.current_fps = (1000 / (current_timestamp - this.last_timestamp)) * this.fps; + this.last_timestamp = current_timestamp; + } + + if(this.mouse_moved == true) + { + this.dirty = this.CallEvent(this.OnMouseMove, this.mouse_coordinates) ? true : this.dirty; + + var select = function(prefix, coordinates) + { + var selector = "/" + prefix + coordinates.x + "," + coordinates.y; + return this.$(selector); + }.bind(this); + + this.dirty = this._BubbleEvent("_HandleMouseOutEvent", this.mouse_coordinates, select("!", this.mouse_coordinates)) ? true : this.dirty; + this.dirty = this._BubbleEvent("_HandleMouseOverEvent", this.mouse_coordinates, select("", this.mouse_coordinates)) ? true : this.dirty; + this.dirty = this._BubbleEvent("_HandleMouseMoveEvent", this.mouse_coordinates, this.$("/")) ? true : this.dirty; + + this.mouse_moved = false; + } + + if(this.CallEvent(this.OnStep, {}) == true) + { + this.dirty = true; + } + + if(this._BubbleEvent("_HandleStepEvent", {}, this.instances) == true) + { + this.dirty = true; + } + + if(this.dirty == true) + { + this.dirty = false; + this.cached_selectors = {}; + this._Draw(); + } + } + + + /**--------------------------------------**/ + /** SOUNDS **/ + /**--------------------------------------**/ + + this.Sound = function(name, source) + { + if(typeof _engine.sounds[name] !== "undefined") + { + throw { + name: "NameError", + message: "A sound with the given name already exists." + } + } + + if(typeof _engine.resources[source] === "undefined") + { + throw { + name: "ResourceError", + message: "The specified resource does not exist." + } + } + + this._engine = _engine; + this.source = this._engine.resources[source]; + this.name = name; + + this._engine.sounds[name] = this; + } + + this.Sound.prototype.Play = function(options) + { + if(this._engine.sound_enabled == true) + { + this.source.play(options); + } + } + + + /**--------------------------------------**/ + /** OBJECTS **/ + /**--------------------------------------**/ + + this.Object = function(name, proto) + { + if(typeof _engine.objects[name] !== "undefined") + { + throw { + name: "NameError", + message: "An object with the given name already exists." + } + } + + /* Base settings */ + this._engine = _engine; + this.name = ""; + + /* Metrics */ + this.x = 0; + this.y = 0; + this.width = 0; + this.height = 0; + this.alpha = 1; + + /* Collision handling */ + this.collision_tolerance = 0.2; + this.precise_collision = false; + + /* Internal variables */ + this.draw_self = (typeof proto.sprite !== "undefined"); + this.scene = null; + this.last_moused_over = false; + + /* Create a constructor for the object. */ + var skeleton = new Function(); + $.extend(true, skeleton.prototype, this, this._engine.Base, proto); + skeleton.prototype.name = name; + + /* Store constructor and return prototype. */ + this._engine.objects[name] = skeleton; + return skeleton.prototype; + } + + this.Object.prototype.CreateInstance = function(vars) + { + return this._engine.CreateInstance(this, vars); + } + + this.Object.prototype.Destroy = function() + { + this.CallEvent(this.OnDestroy); + + if(this.scene != null) + { + var index = this.scene.instances.indexOf(this); + + if(index != -1) + { + this.scene.instances.splice(index, 1); + } + } + } + + this.Object.prototype._Draw = function() + { + if(this.draw_self == true && typeof this.sprite !== "undefined") + { + if(typeof this._engine.sprites[this.sprite] === "undefined") + { + throw { + name: "SpriteError", + message: "The specified sprite does not exist." + } + } + + this._engine.sprites[this.sprite].Draw(this.scene.canvas, this); + } + + this.CallEvent(this.OnDraw, {canvas: this.scene.canvas}); + } + + this.Object.prototype._HandleClickEvent = function(event) + { + var relative_x = event.x - this.x; + var relative_y = event.y - this.y; + + events = { + 1: this.OnClick, + 2: this.OnMiddleClick, + 3: this.OnRightClick + } + + func = events[event.button]; + + this.CallEvent(func, { + x: event.x, + y: event.y, + button: event.button, + relative_x: relative_x, + relative_y: relative_y + }); + + return true; + } + + this.Object.prototype._HandleMouseMoveEvent = function(event) + { + this.CallEvent(this.OnMouseMove, { + x: event.x, + y: event.y + }); + return true; + } + + this.Object.prototype._HandleMouseOutEvent = function(event) + { + if(this.last_moused_over == true) + { + this.last_moused_over = false; + + this.CallEvent(this.OnMouseOut, { + x: event.x, + y: event.y + }); + + return true; + } + } + + this.Object.prototype._HandleMouseOverEvent = function(event) + { + if(this.last_moused_over == false) + { + var relative_x = event.x - this.x; + var relative_y = event.y - this.y; + + this.last_moused_over = true; + + this.CallEvent(this.OnMouseOver, { + x: event.x, + y: event.y, + relative_x: relative_x, + relative_y: relative_y + }); + + return true; + } + } + + this.Object.prototype._HandleStepEvent = function(event) + { + if(typeof this.sprite != "undefined") + { + var sprite = this._engine.sprites[this.sprite]; + this.width = sprite.width; + this.height = sprite.height; + } + + return this.CallEvent(this.OnStep, event); + } + + /**--------------------------------------**/ + /** SPRITES **/ + /**--------------------------------------**/ + + this.Sprite = function(name, source, options) + { + if(typeof _engine.sprites[name] !== "undefined") + { + throw { + name: "NameError", + message: "A sprite with the given name already exists." + } + } + + if(typeof _engine.resources[source] === "undefined") + { + throw { + name: "ResourceError", + message: "The specified resource does not exist." + } + } + + this._engine = _engine; + this.source = this._engine.resources[source]; + this.name = name; + + if(typeof options.tile_x !== "undefined" && typeof options.tile_y !== "undefined" && typeof options.tile_w !== "undefined" && typeof options.tile_h !== "undefined") + { + this.tile_x = options.tile_x; + this.tile_y = options.tile_y; + this.tile_w = options.tile_w; + this.tile_h = options.tile_h; + this.tile = true; + } + else if(typeof options.tile_x !== "undefined" || typeof options.tile_y !== "undefined" || typeof options.tile_w !== "undefined" || typeof options.tile_h !== "undefined") + { + throw { + name: "SpriteError", + message: "Only a part of the tile parameters were specified." + } + } + else + { + this.tile = false; + } + + /* Store image data for click events and collision detection. */ + var collision_canvas = document.createElement("canvas"); + var width, height; + + if(this.tile == false) + { + width = this.source.width; + height = this.source.height; + } + else if(this.tile == true) + { + width = this.tile_w; + height = this.tile_h; + } + + collision_canvas.width = this.width = width; + collision_canvas.height = this.height = height; + + this.Draw(collision_canvas, null, {x: 0, y: 0, alpha: 1}); + + ctx = collision_canvas.getContext("2d"); + this.image_data = ctx.getImageData(0, 0, width, height); + + delete collision_canvas; + + /* Store in engine. */ + this._engine.sprites[name] = this; + } + + this.Sprite.prototype.Draw = function(canvas, object, options) + { + ctx = canvas.getContext("2d"); + + if((typeof object == "undefined" || object == null) && (typeof options == "undefined" || typeof options.x == "undefined" || typeof options.y == "undefined")) + { + throw { + name: "DrawError", + message: "No drawing coordinates were specified." + } + } + else if(typeof object == "undefined" || object == null) + { + var x = options.x; + var y = options.y; + } + else + { + var x = object.x; + var y = object.y; + } + + if(typeof options != "undefined" && typeof options.alpha != "undefined") + { + var alpha = options.alpha; + } + else if(typeof object != "undefined" && object != null) + { + var alpha = object.alpha; + } + else + { + throw { + name: "DrawError", + message: "No alpha value was specified." + } + } + + ctx.globalAlpha = alpha; + + if(this.tile == true) + { + ctx.drawImage(this.source, this.tile_x, this.tile_y, this.tile_w, this.tile_h, x, y, this.tile_w, this.tile_h); + } + else + { + ctx.drawImage(this.source, x, y); + } + } + + this.Sprite.prototype.GetAlpha = function(x, y) + { + var key = (((y * this.width) + x) * 4) + 3; + return this.image_data.data[key]; + } + + /**--------------------------------------**/ + /** ENGINE FUNCTIONS **/ + /**--------------------------------------**/ + + this.AddItems = function(items) + { + if(typeof items.sprites != "undefined") + { + + for(name in items.sprites) + { + if(typeof items.sprites[name] == "string") + { + /* Stand-alone sprite. */ + new _engine.Sprite(name, items.sprites[name], {}); + } + else + { + /* Probably a tileset. */ + new _engine.Sprite(name, items.sprites[name], { + tile_x: items.sprites[name].tile_x, + tile_y: items.sprites[name].tile_y, + tile_w: items.sprites[name].tile_w, + tile_h: items.sprites[name].tile_h, + }); + } + } + } + + if(typeof items.sounds != "undefined") + { + for(name in items.sounds) + { + new _engine.Sound(name, items.sounds[name]); + } + } + + if(typeof items.objects != "undefined") + { + for(name in items.objects) + { + new _engine.Object(name, items.objects[name]); + } + } + + if(typeof items.scenes != "undefined") + { + for(name in items.scenes) + { + new _engine.Scene(name, items.scenes[name]); + } + } + } + + this.CreateInstance = function(object, vars) + { + this.instance_increment++; + + if(typeof data == "undefined") + { + var data = {id: this.instance_increment}; + } + else + { + data.id = this.instance_increment; + } + + if(typeof object == "string") + { + var instance = new this.objects[object](); + } + else + { + var skeleton = new Function(); + skeleton.prototype = object; + var instance = new skeleton(); + } + + $.extend(true, instance, vars); + + /* Call creation event. */ + instance.CallEvent(instance.OnCreate, {}); + + return instance; + } + + this.GetObject = function(name) + { + return this.objects[name].prototype; + } + + this.GetScene = function(name) + { + return this.scenes[name]; + } + + this.GetSound = function(name) + { + return this.sounds[name]; + } + + this.GetSprite = function(name) + { + return this.sprites[name]; + } + + /**--------------------------------------**/ + /** STANDARD LIBRARY **/ + /**--------------------------------------**/ + + this.Math = {}; + + this.Math.Abs = Math.abs; + this.Math.Absolute = Math.abs; + this.Math.Acos = Math.acos; + this.Math.Arccosine = Math.acos; + this.Math.Asin = Math.asin; + this.Math.Arcsine = Math.asin; + this.Math.Atan = Math.atan; + this.Math.Arctangent = Math.atan; + this.Math.Atan2 = Math.atan2; + this.Math.Arctangent2 = Math.atan2; + this.Math.Ceil = Math.ceil; + this.Math.Ceiling = Math.ceil; + this.Math.Cos = Math.cos; + this.Math.Cosine = Math.cos; + this.Math.Exp = Math.exp; + this.Math.Floor = Math.floor; + this.Math.Log = Math.log; + this.Math.Logarithm = Math.log; + this.Math.Min = Math.min; + this.Math.Minimum = Math.min; + this.Math.Max = Math.max; + this.Math.Maximum = Math.max; + this.Math.Pow = Math.pow; + this.Math.Power = Math.pow; + this.Math.Round = Math.round; + this.Math.Sin = Math.sin; + this.Math.Sine = Math.sin; + this.Math.Sqrt = Math.sqrt; + this.Math.SquareRoot = Math.sqrt; + this.Math.Tan = Math.tan; + this.Math.Tangent = Math.tan; + + this.Random = {}; + + this.Random.Choose = function() + { + if(arguments.length == 0) + { + /* The user passed in nothing. Bail out. */ + throw { + name: "ArgumentError", + message: "No arguments were specified." + } + } + else if(arguments.length == 1 && typeof arguments[0].length != "undefined") + { + /* The user passed in an array. */ + arguments = arguments[0]; + } + + return arguments[Math.floor(Math.random() * arguments.length)]; + } + + this.Random.Number = function(floor, ceiling, precision) + { + var floor = (typeof floor == "undefined") ? 0 : floor; + var ceiling = (typeof ceiling == "undefined") ? 1 : ceiling; + var precision = (typeof ceiling == "undefined") ? 0.00000001 : precision; + + var base_number = Math.random(); + var width = Math.abs(ceiling - floor); + var rounding_factor = 1 / precision; + + var multiplied = floor + (base_number * width); + return Math.floor(multiplied * rounding_factor) / rounding_factor; + } + + this.Random.Pick = function() + { + var chosen = []; + var results = []; + var _arguments = Array.prototype.slice.call(arguments); + var count = _arguments.shift(); + + if(arguments.length == 0) + { + /* The user passed in nothing. Bail out. */ + throw { + name: "ArgumentError", + message: "No arguments were specified." + } + } + else if(_arguments.length == 1 && typeof _arguments[0].length != "undefined") + { + /* The user passed in an array. */ + _arguments = _arguments[0]; + } + + if(count > _arguments.length) + { + /* The user requested more items than exist in the arguments. */ + throw { + name: "ArgumentError", + message: "Not enough arguments were specified. The amount of specified items must be equal to or larger than the requested amount." + } + } + + for(var i = 0; i < count; i++) + { + var id = 0; + + do + { + id = Math.floor(Math.random() * _arguments.length); + } while (chosen.indexOf(id) != -1) + + chosen.push(id); + results.push(_arguments[id]); + } + + return results; + } + + this.Random.String = function(length, alphabet) + { + if(typeof alphabet == "undefined") + { + alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + } + + rand = ""; + + for(i = 0; i < length; i++) + { + rand += alphabet[Math.floor(Math.random() * alphabet.length)]; + } + + return rand; + } + + this.Draw = {}; + + this.Draw.Text = function(x, y, text, options) + { + + } + + this.Draw.Rectangle = function(x1, y1, x2, y2, options) + { + + } + + this.Draw.Line = function(x1, y1, x2, y2, options) + { + + } + + this.Draw.BoxEllipse = function(x1, y1, x2, y2, options) + { + var x = (x1 + x2) / 2; + var y = (y1 + y2) / 2; + var rx = (x2 - x1) / 2; + var ry = (y2 - y1) / 2; + + this.RadiusEllipse(x, y, rx, ry, options); + } + + this.Draw.RadiusEllipse = function(x, y, rx, ry, options) + { + var canvas = $("#gamecanvas")[0]; + var ctx = canvas.getContext("2d"); + ctx.beginPath(); + + if(rx == ry) + { + /* Circle. */ + ctx.arc(x, y, rx, 0, 2 * Math.PI, false); + } + else + { + /* Ellipse. */ + var step = 0.1 + + ctx.moveTo(x + rx, y); + + for (var i = 0; i < Math.PI * 2 + step; i += step) + { + ctx.lineTo(x + Math.cos(i) * rx, y + Math.sin(i) * ry); + } + } + + ctx.lineWidth = 1; + ctx.strokeStyle = 'black'; + ctx.stroke(); + } + + this.Draw.BoxPolygon = function(x1, y1, x2, y2, sides, options) + { + + } + + this.Draw.RadiusPolygon = function(x, y, radius, sides, options) + { + + } +} diff --git a/public_html/templates/error/404.tpl b/public_html/templates/error/404.tpl index da6f430..037b0e5 100644 --- a/public_html/templates/error/404.tpl +++ b/public_html/templates/error/404.tpl @@ -1,4 +1,10 @@ -
-

404 Page not found

- The requested page could not be found. -
+ + + +
+ +
+

404 Page not found

+ The requested page could not be found. +
+