You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1457 lines
31 KiB
JavaScript

/* 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)
{
}
}