Sic/frame1.as
From Organic Design wiki
//
// Liscenced under LGPL: www.gnu.org/copyleft/lesser.html
//
// Nad - 2003 - SIC-Games
// Frame1: GENERAL DECLARATIONS
//
FSCommand("fullscreen",true);
// GLOBALS
// SPACE
// SPACE.CREATE
// SPACE.FRAME
// TEMPLATE
// 3D OBJECT CLASSES
// Spark
// Ball
// OBJECT CLASS
// GUN FIRE CLASS
// BULLET CLASS
// GUN CLASS
// STAR-BURST CLASS
// TORUS CLASS
// IMPLODE CLASS
// STARFIELD CLASS
// 3D MOTION CLASSES
// FLOAT
// INTERFACES
// interfaces.addInterface
// interfaces.deleteInterface
// interfaces.sync
// interfaces.ack
// updateInterfaces
// NETWORK
// processOutgoingEvents
// processIncomingEvents
// createEvent
// sendMessage
// processMessage
// SHELL
// _____________________________________________________________________________________________________________________ //
// GLOBALS
now = new Date();
time = now.getTime();
allSpaces = []; // Keep track of all spaces so all their frame() can be executed
CWD = '';
// _____________________________________________________________________________________________________________________ //
// SPACE
// Initialise passed movieclip as a 3D space
function initialiseSpace(newSpace) {
_root.allSpaces.push(newSpace);
newSpace.create = _root.space.create;
newSpace.frame = _root.space.frame;
newSpace.active = true; // Enables/disables space dynamics
newSpace.space = newSpace; // create() function used at all levels expects space to be this.space;
newSpace.rotation = 0; // global rotation of space
newSpace.shipRotation = 0; // global rotation of ship (which the screens are windows out of)
newSpace.applySR = true;
newSpace.zbuff = []; // Z ordered symbol-refs of all 3D objects
newSpace.zbLength = 0; // Since zbuff is sorted, we can use an end-ptr instead of pushing/splicing
newSpace.children = []; // Top layer children
newSpace.template = _root.template; // Template object for creating new symbols into the space
newSpace.zSCREEN = 1000; // Distance from origin (eye) to screen
}
// _____________________________________________________________________________________________________________________ //
// SPACE.CREATE
// Method: The space and all its objects inherit this method for creating child objects
// Creates a symbol for the 3D-object (spacer is used if classes[thisClass].symbol == null)
// The passed data object extends the space.template used to initialise the new object
// - called from events: guid,time,method,class...
space = {};
space.create = function(parameters) {
var space = this.space;
var time = 1*parameters[1];
if (time == 0) time = _root.time;
// Name object from create-event-guid (so it can be referred to across peers)
var instanceName = parameters[0];
if (instanceName == 0) instanceName = _root.guid();
var symbol, hasSymbol = false;
var class = parameters[3];
var classRef = _root.classes[class];
if (class == 'obj') symbol = parameters[4];
else symbol = classRef.symbol;
// Create new child symbol using the 3D-object template (space.template)
space.createEmptyMovieClip(instanceName, 10000-space.zbLength); // NOTE! 10000-layer cos z-buffering not working
var child = space[instanceName];
if (symbol != null) {
child.createEmptyMovieClip('swf', 0);
child.swf.loadMovie('./swf/'+symbol);
hasSymbol = true;
}
var template = space.template;
for (var i in template) child[i] = template[i];
this.children.push(child); // object available in hierachical update tree of frame() calls
space.zbuff[space.zbLength++] = child; // place object into z-buffer for layer sorting
// Populate new child symbol/object
for (var i in classRef) child[i] = classRef[i];
child.space = space;
child.class = class;
child.parent = this;
child.applySR = this.applySR;
child.colour = new Color(child.swf);
child.children = [];
child.hasSymbol = hasSymbol;
child.time = time;
child._alpha = 0;
child.die = false;
// Set the objects' dynamics() and call its init() - parameters[3] is 3DO-class
if (classRef.init != null) classRef.init.call(child, parameters); // names and stores parameters, creates children etc
return child;
};
// _____________________________________________________________________________________________________________________ //
// SPACE.FRAME
// Method: Called every frame (not generic)
// - this is the top level frame function called by SWF on frame2
space.frame = function() {
var space = this.space;
// Execute the template.frame() of each top-level child
for (var i = this.children.length-1; i >= 0; --i) {
var obj = this.children[i];
obj.ax = obj.ay = obj.az = 0;
obj.frame();
// delete from this child list if marked for death
if (obj.die) this.children.splice(i,1);
}
// Reduce the 3D coordinates to 2D for *ALL* objects with symbols (ie all layers, empty)
// - ax,ay,az are absolute positions calculated in child frame() exec layers
for (var i = 0; i < space.zbLength; i++) {
var obj = space.zbuff[i];
if (obj.die) obj.az = -100000000; // dead ones will get sorted to the end
else {
// Global rotation
if (obj.applySR) {
if (space.rotation != 0) obj.rotate('ax', 'az', space.rotation);
// Ship rotation
if (space.shipRotation != 0) {
if (_root.network.thisIndex == 0) obj.rotate('ax', 'ay', space.shipRotation);
else if (_root.network.thisIndex == 1) obj.rotate('ay', 'az', space.shipRotation);
else if (_root.network.thisIndex == 2) obj.rotate('ay', 'ax', space.shipRotation);
else if (_root.network.thisIndex == 3) obj.rotate('az', 'ay', space.shipRotation);
}
}
// 3D -> 2D
var m = space.zSCREEN/obj.az;
obj._x = obj.ax*m;
obj._y = obj.ay*m;
// 3D -> Scale
if (m < 0) m = 0; else if (m > 10) m = 10;
obj._xscale = obj._yscale = obj.scale*m;
// 3D -> Lighting
//if (m <= 0.25) light = 1; else if (m < 1) light = (m-0.25)*10000/75; else light = 100;
//light = light/2+50;
//obj.colour.setTransform({ra:light, ga:light, ba:light});
obj._alpha = obj.alpha;
}
}
// Sort buffer by Z and synchronise rendering levels
for (var i = 0; i < space.zbLength-1; i++) {
var obj = space.zbuff[i];
var maxz = obj.az, maxp = i;
for (var j = i+1; j < space.zbLength; j++) if (space.zbuff[j].az > maxz) {
maxz = space.zbuff[j].az;
maxp = j;
}
if (maxp != i) {
obj.swapDepths(space.zbuff[maxp]);
space.zbuff[i] = space.zbuff[maxp];
space.zbuff[maxp] = obj;
}
}
// Delete nodes marked for death (they will have been sorted to the end of the buffer)
while (space.zbuff[space.zbLength-1].die) space.zbuff[--space.zbLength].removeMovieClip();
//logClr();
//for (var i = 0; i < space.zbLength-1; i++) logAdd(space.zbuff[i].getDepth());
};
// _____________________________________________________________________________________________________________________ //
// TEMPLATE
// - Create a set of methods and properties inherited by all symbols created in the space
// - various dynamics() and effects() can add and maintain other properties
template = {};
template.space = null; // set by create() A ref to the space object
template.create = space.create; // Inherits generic create() method
template.parent = null; // Set by create(), a ref to the parent of this object
template.children = null; // Children of this object (must be initialised by create)
template.die = false; // Object deletion must be handled ny the space.frame()
template.motion = []; // Motion functions to call in frame()
template.colour = null; // Set by create() - objects colour transform
template.scale = 100; // symbol scale
template.alpha = 100; // symbol scale
template.time = 0; // Objects' absolute birth time
template.x = 0; // Objects relative position (ie relative to birth location and time)
template.y = 0; //
template.z = 0; //
// per-frame method for 3D-objects (not the space itself which has its own frame function)
// - frame() calculates the absolute position from the relative positions in the parent-child chain of each object
template.frame = function() {
var p = [this.x, this.y, this.z];
var t = _root.time-this.time;
// Initialise symbol when loaded
var swf = this.swf;
if ((swf._width > 0) && (++swf.ctr == 1)) {
swf._x = -swf._width/2;
swf._y = -swf._height/2;
}
// Update objects dynamic properties
if (!this.die) {
if (this.dynamics != null) this.dynamics(t);
// Execute this objects' current motion effects x += f(t)
for (var i = 0; i < this.motion.length; i++)
_root.motion[this.motion[i]].call(this, t);
// Update absolute location for space.frame() to render
this.ax += this.x;
this.ay += this.y;
this.az += this.z;
}
// Execute the frame() of each child
// - if this is dead, propagate death to descendents
for (var i = this.children.length-1; i >= 0; --i) {
var obj = this.children[i];
if (this.die) obj.die = true;
else {
obj.ax = this.ax;
obj.ay = this.ay;
obj.az = this.az;
}
obj.frame.call(obj);
}
// Restore x,y,z
//this.x = p.shift();// *** bullet collision doesn't work properly when these are restored...?
//this.y = p.shift();
//this.z = p.shift();
};
// Rotate an object
template.rotate = function(x, y, a) {
a += Math.atan2(this[y], this[x]);
var r = Math.sqrt(this[x]*this[x]+this[y]*this[y]);
this[x] = Math.cos(a)*r;
this[y] = Math.sin(a)*r;
};
// _____________________________________________________________________________________________________________________ //
// 3D OBJECT CLASSES
// NOTE: (Not using languages' classes here as actionscript too lame-arse)
// Each class has:
// - init(data) used to create and layout child objects within itself (and can instantiate an asscoiated symbol too)
// - dynamics() called from it's frame() which then also calls space.update
// each dynamics can call a set of effects functions depending on its state and time
// NOTE: dynamics must base all changes on time
// NOTE: dynamics are responsible for their coordinates being relative to parent
// - this is because some dynamics update their own coodinates and some their childrens
// - classes may has only a symbol and no init() or dynamics()
// these phases and layers should be tree nodes
classes = {};
// _____________________________________________________________________________________________________________________ //
// Spark
classes.spark = {};
classes.spark.init = function(parameters) {
this.lat = parameters[4];
this.lon = parameters[5];
};
classes.spark.symbol = 'obj-spark.swf';
// Ball
classes.ball = {};
classes.ball.init = function(parameters) {
this.lat = parameters[4];
this.lon = parameters[5];
};
classes.ball.symbol = 'ball.swf';
// _____________________________________________________________________________________________________________________ //
// OBJECT CLASS
classes.obj = {};
classes.obj.init = function(parameters) {
this.create([0,0,'','implode',0,0,0]);
this.shootable = false;
this.motion = ['float'];
var ri = this.time;
this.rc = 1500;
this.rr = 200+_root.rnd(ri,2)*1000;
this.rt = 0.0005+_root.rnd(ri,1)*0.0005;
this.v = 0.0001+_root.rnd(ri+5,1)*0.0004;
if (_root.rnd(ri+5,2) > 0.5) this.v = -this.v;
this.yr = 50+_root.rnd(ri+10,1)*500;
this.yt = 0.001+_root.rnd(ri+10,2)*0.001;
};
classes.obj.dynamics = function(t) {
var swf = this.swf;
// fade object in
this.alpha = t/20;
if (this.alpha > 100) this.alpha = this.shootable = 100;
// set object frame
this.f = 1+Math.floor((t/50)%swf._totalframes);
swf.gotoAndStop(this.f);
// Motion
var r = this.rc+_root.motion.squareSine(t*this.rt)*this.rr;
this.y = Math.sin(t*this.yt)*this.yr;
r += Math.cos(t*this.yt)*this.yr;
this.x = r*Math.sin(t*this.v);
this.z = r*Math.cos(t*this.v);
};
// _____________________________________________________________________________________________________________________ //
// GUN FIRE CLASS
classes.fire = {};
classes.fire.symbol = 'obj-spark.swf';
classes.fire.init = function(parameters) {
this.applySR = false;
this.alpha = 0;
this.state = false;
};
classes.fire.dynamics = function(t) {
this.swf.gotoAndStop(2);
var gun = _root.gun;
this.x = gun.object.ax+gun.ox[gun.frame]/10;
this.y = gun.object.ay+gun.oy[gun.frame]/10;
this.z = gun.object.az;
if (this.state) {
this.time = _root.time;
this.state = false;
_root.sounds.gun1.start();
this.space.create([0,0,'','bullet']);
_root.gun.lastShot = _root.time;
}
this.alpha = 100-t/2;
if (this.alpha < 0) this.alpha = 0;
};
// _____________________________________________________________________________________________________________________ //
// BULLET CLASS
classes.bullet = {};
classes.bullet.symbol = 'obj-spark.swf';
classes.bullet.init = function(parameters) {
this.applySR = false;
this.x = _root.gun.fire.ax;
this.y = _root.gun.fire.ay;
this.z = _root.gun.fire.az;
this.dx = (_root._xmouse-512) - _root.gun.fire.ax;
this.dy = (_root._ymouse-384) - _root.gun.fire.ay;
};
classes.bullet.dynamics = function(t) {
this.swf.gotoAndStop(2);
this.x = _root.gun.fire.ax + this.dx*t/200;
this.y = _root.gun.fire.ay + this.dy*t/200;
this.z = _root.gun.fire.az+t*5;
if (this.z > 2000) this.die = true;
// check all shootable objects for hit
for (var i = 0; i < _root.game.children.length; i++) {
var obj = _root.game.children[i];
if (obj.shootable) {
var dx = this.x - obj.x;
var dy = this.y - obj.y;
var dz = this.z - obj.z;
var d2 = dx*dx+dy*dy+dz*dz;
if (d2<5000) {
// Hit! - do death and explosion sounds locally
_root.sounds['die'+int(Math.random()*10)].start();
createEvent('now,playSound,gun5,100', --_root.localguid);
createEvent(''+(_root.time+490)+',playSound,gun4,100', --_root.localguid);
_root.game.create([0,0,'','starBurst',10,0.25,obj.x,obj.y,obj.z]);
// propagate the kill
createEvent('now,objects.kill,'+obj._name, null);
// Make sure obj can't be hit twice and bullet can't hit twice
obj.shootable = false;
this.die = true;
i = _root.game.children.length;
}
}
}
};
// _____________________________________________________________________________________________________________________ //
// GUN CLASS
classes.gun = {};
classes.gun.motion = ['float'];
classes.gun.init = function(parameters) {
this.applySR = false;
};
classes.gun.symbol = 'obj-gun.swf';
classes.gun.dynamics = function(t) {
this.x = 0;
this.y = 30;
this.z = 100;
this.scale = 25;
this.swf.gotoAndStop(_root.gun.frame);
};
// _____________________________________________________________________________________________________________________ //
// STAR-BURST CLASS
classes.starBurst = {};
classes.starBurst.symbol = 'obj-spark.swf';
classes.subBurst = {};
// starBurst: stars,force,x,y,z
classes.starBurst.init = function(parameters) {
var guid = parameters[0];
this.stars = parameters[4];
this.force = parameters[5];
this.x = 1.0*parameters[6];
this.y = 1.0*parameters[7];
this.z = 1.0*parameters[8];
this._visible = false;
var ri = this.time;
for (var i = 0; i < this.stars; i++) {
var lat = _root.rnd(ri,1)*2*Math.PI;
var lon = _root.rnd(ri+10,1)*2*Math.PI;
ri+=20;
var obj = this.create([0,this.time,'','subBurst',4,1.5,500,lat,lon,ri]);
}
};
// subBurst: stars,force,start,fadeout,lat,lon
classes.subBurst.init = function(parameters) {
this.stars = parameters[4];
this.force = parameters[5];
this.start = parameters[6];
this.lat = parameters[7];
this.lon = parameters[8];
var ri = 1*parameters[9];
for (var i = 0; i < this.stars; i++) {
var lat = _root.rnd(ri,3)*2*Math.PI;
var lon = _root.rnd(ri+31,3)*2*Math.PI;
ri+=51;
var obj = this.create([0,0,'','spark',lat,lon]);
obj.index = i;
}
};
classes.subBurst.symbol = 'obj-spark.swf';
classes.starBurst.dynamics = function(t) {
var onlyOne = true;
// This is a subBurst
if (this.start != null) {
this.swf.gotoAndStop(4);
if (t > this.start) {
this.radius = (t-this.start)*this.force;
onlyOne = false;
}
}
else {
this.swf.gotoAndStop(1);
this.radius = 100+t*this.force;
}
this.force = this.force*0.97;
if (this.alpha < 0) this.alpha = 0;
var a = 100-(t/30);
if (a < 0) {
if (this.parent == this.space) this.die = true;
a = 0;
}
// Update child positions: x = 0 + f(t) stylz
for (var i = 0; i < this.children.length; i++) {
var star = this.children[i];
var s = this.radius*Math.cos(star.lon);
star.x = s*Math.cos(star.lat+t/500);
star.y = this.radius*Math.sin(star.lon)+t*t/8000;
star.z = s*Math.sin(star.lat+t/500);
if (onlyOne && (i>0)) star.alpha = 0; else star.alpha = a;
}
};
classes.subBurst.dynamics = classes.starBurst.dynamics;
// _____________________________________________________________________________________________________________________ //
// TORUS CLASS
classes.torus = {};
// torus: points,radius,speed (has been converted specifically to target object)
classes.torus.init = function(parameters) {
this.applySR = false;
this.points = 1*parameters[4];
this.radius = 1.0*parameters[5];
this.speed = 1.0*parameters[6];
for (var i = 0; i < this.points; i++) this.create([0,0,'','spark',50]);
};
classes.torus.dynamics = function(t) {
this.x = _root._xmouse-512;
this.y = _root._ymouse-384;
this.Z = 1000;
var s;
if (++this.ctr%50<12) s = 0; else s = t/250;
var sec = Math.round(t/100);
for (var i = 0; i < this.children.length; i++) {
var point = this.children[i];
point.swf.gotoAndStop(1);
var angle = 2*Math.PI*i/this.children.length+this.angle/this.children.length+s;
var r = this.parent.radius+this.radius*Math.sin(angle);
point.x = this.x+r*Math.cos(this.angle);
point.y = this.y+this.radius*Math.cos(angle);
point.z = this.z+r*Math.sin(this.angle);
point.scale = 200;
if (s == 0) point._visible = (sec%2==0); else point._visible = true;
}
};
// _____________________________________________________________________________________________________________________ //
// IMPLODE CLASS
classes.implode = {};
classes.implode.init = function(parameters) {
this.stars = 25;
this.radius = 200;
this.x = 1.0*parameters[4];
this.y = 1.0*parameters[5];
this.z = 1.0*parameters[6];
var ri = this.time;
for (var i = 0; i < this.stars; i++) {
var lat = _root.rnd(ri,1)*2*Math.PI;
var lon = _root.rnd(ri+10,1)*2*Math.PI;
var obj = this.create([0,0,'','spark',lat,lon]);
obj.v = _root.rnd(ri+20,1)*100+10;
obj.scale = 50;
ri+=30;
}
};
classes.implode.dynamics = function(t) {
this.radius = 500-t/3;
if (this.radius < 100) this.radius = 100;
var a = t/10;
if (a > 200) this.die = true;
if (a > 100) a = 200-a;
for (var i = 0; i < this.children.length; i++) {
var star = this.children[i];
var r = this.radius*star.v/50;
var s = r*Math.cos(star.lon);
star.x = s*Math.cos(star.lat+t/star.v/2);
star.y = r*Math.sin(star.lon);
star.z = s*Math.sin(star.lat+t/star.v/2);
star.alpha = a/2;
}
};
// _____________________________________________________________________________________________________________________ //
// STARFIELD CLASS
classes.starField = {};
classes.starField.init = function(parameters) {
this.stars = 100;
this.radius = 2000;
var ri = this.time;
for (var i = 0; i < this.stars; i++) {
var lat = _root.rnd(ri,1)*2*Math.PI;
var lon = _root.rnd(ri+10,1)*2*Math.PI;
var obj = this.create([0,0,'','spark',lat,lon]);
obj.v = _root.rnd(ri+20,1)*100+10;
obj.scale = 50;
ri+=30;
}
};
classes.starField.dynamics = function(t) {
this.radius = 500-t/3;
if (this.radius < 100) this.radius = 100;
var a = t/10;
if (a > 200) this.die = true;
if (a > 100) a = 200-a;
for (var i = 0; i < this.children.length; i++) {
var star = this.children[i];
var r = this.radius*star.v/50;
var s = r*Math.cos(star.lon);
star.x = s*Math.cos(star.lat+t/star.v/2);
star.y = r*Math.sin(star.lon);
star.z = s*Math.sin(star.lat+t/star.v/2);
star.alpha = a/2;
}
};
// _____________________________________________________________________________________________________________________ //
// 3D MOTION CLASSES
// - 3D Motion functions called by an objects' frame() if in its motion[] list
// FLOAT
// Adds the metaparticles movement to passed object
motion = {};
motion.float = function(t) {
var a = t/400;
var m = (this._width+this._height)*this.scale/10000;
var api4 = a*Math.PI/4;
var api8 = a*Math.PI/8;
var cospi4 = Math.cos(api4);
var cospi8 = Math.cos(api8);
var sinpi4 = Math.sin(api4);
var sinpi8 = Math.sin(api8);
this.x += m*cospi4*sinpi8;
this.y += m*cospi4*cospi8;
this.z += m*sinpi4;
};
motion.squareSine = function(t) {
var i = Math.floor(t/Math.PI)%6;
if ((i == 1) || (i == 2)) return -1;
if (i > 3) return 1;
return Math.cos(t);
};
// _____________________________________________________________________________________________________________________ //
// INTERFACES
// the swf addresses the object structure directly (its hash)
// maintains a list of the active interfaces
// - first when ordered by key (guid) is timeServer
// - timeServer sends current time after it hasn't recvd a time for >5s
interfaces = {};
interfaces.active = {};
// These functions are methods so they can be executed by event-messages
// - addInterface should propagate an ack event so it gains everyones info
// interfaces.addInterface
interfaces.addInterface = function(parameters) {
var guid = parameters.shift();
var method = parameters.shift();
var i = parameters[1];
logAdd('interfaces.addInterface('+i+')');
var ai = _root.interfaces.active;
ai[i] = 1;
updateInterfaces();
createEvent('now,interfaces.ack,'+_root.network.thisInterface, null);
};
// interfaces.deleteInterface
interfaces.deleteInterface = function(parameters) {
logAdd('interfaces.deleteInterface()');
var guid = parameters.shift();
var time = parameters.shift();
var method = parameters.shift();
var i = parameters[0];
var ai = _root.interfaces.active;
delete ai[i];
updateInterfaces();
};
// interfaces.sync
interfaces.sync = function(parameters) {
logAdd('sync');
_root.timeError = getTimer();
if (parameters[3] == _root.network.thisInterface) return; // don't ack our own sync
if (_root.network.thisIndex != 0) return; // only the first interface responds to syncs
createEvent('now,interfaces.ack,'+_root.network.thisInterface+','+_root.time, null);
};
// Receiving an ack from another IF
// - set time from ack;
// interfaces.ack
interfaces.ack = function(parameters) {
var guid = parameters.shift();
var method = parameters.shift();
var i = parameters[1];
if (i == _root.network.thisInterface) return; // don't ack ourselves
logAdd('interfaces.ack('+i+')');
var ai = _root.interfaces.active;
ai[i] = 1;
updateInterfaces();
};
// Currently just logs
// updateInterface
function updateInterfaces() {
var ai = _root.interfaces.active;
var orderedList = [];
for (var guid in ai) orderedList.push(guid);
orderedList.sort();
for (var i = 0; i < orderedList.length; i++) {
var j = orderedList[i];
if (j == _root.network.thisInterface) _root.network.thisIndex = i;
j = j.substr(-6);
logAdd(' '+i+' : SWF-'+j.toUpperCase());
}
var index = _root.network.thisIndex;
logAdd(' My index is '+index);
logAdd(' I am '+_root.network.thisInterface);
var p = _root.demo.personas;
var i = index%4;
_root.demo.setPersona(p[i]);
logAdd(" I have an index, so I've set my persona and angle...");
logAdd(" I am the "+p[i]+".");
_root.game.rotation = i*Math.PI/2;
logAdd(" My space is rotated by "+(_root.game.rotation/Math.PI)+' Pi radians.');
}
// _____________________________________________________________________________________________________________________ //
// NETWORK
network = new XMLSocket();
network.port = 2012;
network.thisGuid = guid();
network.thisPeer = null; // defined after first message from our peer
network.peers = [];
network.thisInterface = null; // known after peer known
network.incomingEvents = {};
network.outgoingEvents = {};
network.finishedEvents = {};
// When connected to our peer, send out info
network.onConnect = function(success) {
_root.network.connected = success;
sendMessage('port='+network.port+'&add=interface&guid='+network.thisGuid, '');
};
// Decode incoming message
network.onData = function(data) {
var msg = data.split("|");
var subject = msg[0];
var content = msg[1];
// split subject query-string and extract our peer and our name
logAdd(subject);
var qs = subject.split("&");
for (var i = 0; i < qs.length; i++) {
var j = qs[i].split("=");
if (j[0] == 'to') _root.network.thisInterface = j[1];
if ((j[0] == 'from') && (_root.network.thisPeer == null)) {
var peer = _root.network.thisPeer = j[1];
logAdd('My peer is '+peer);
// make a guess at the persona (%n of last ip part)
// var p = _root.demo.personas;
// var k = peer.split('.');
// k = k[k.length-1].split(':');
// p = p[(k[0]%_root.demo.personas.length)-1];
// _root.demo.setPersona(p);
// logAdd(" I'll take a guess at my persona from my own IP number...");
// logAdd(" I am the "+p+".");
}
if (j[0] == 'peers') {
_root.network.peers = j[1].split(',');
_root.network.peers.push(_root.network.thisPeer);
}
}
// Split content quey-string and execute each event (guid=time,cmd,parameters...)
qs = content.split("&");
for (var i = 0; i < qs.length; i++) {
var j = qs[i].split("=");
if (_root.network.finishedEvents[guid] == null) createEvent(j[1], j[0]); // parameters, [guid]
}
};
// Send a message to the associated peer.pl
function sendMessage(subject, content) {
logAdd('Sending ('+subject+')');
_root.network.send(subject+"|"+content); // SWF automatically appends \x00
}
// _____________________________________________________________________________________________________________________ //
// Sends queue of local events needing propagation
// processOutgoingEvents
function processOutgoingEvents() {
var oe = _root.network.outgoingEvents;
var fe = _root.network.finishedEvents;
// Build a query-string of the queued-events
var msg = [];
for (var guid in oe) msg.push(guid+"="+oe[guid]);
var qs = msg.join("&");
// Send queued and unprocessed events if any
if (qs.length > 0) sendMessage('', qs);
// Clear outgoing events buffer now that they've been propagated
_root.network.outgoingEvents = {};
}
// Executes events which were received before their birth-time
// processIncomingEvents
function processIncomingEvents() {
var ie = _root.network.incomingEvents;
var fe = _root.network.finishedEvents;
_root.del = [];
for (var guid in ie) createEvent(ie[guid], guid); // inefficient way - calls createEvent every time
// Can't delete items in ie while looping through ie
while (_root.del.length > 0) delete ie[_root.del.pop()];
}
// Create a new event locally
// createEvent
function createEvent(parameters, guid) {
var ie = _root.network.incomingEvents;
var oe = _root.network.outgoingEvents;
var fe = _root.network.finishedEvents;
var plist = parameters.split(",");
var t = 1*plist[0];
// If no guid, event is new and needs to be propagated outward and also queued in incoming for local creation
if (guid == null) {
guid = _root.guid();
oe[guid] = parameters;
} else if (fe[guid]) return;
ie[guid] = parameters;
// Execute events' method if birth-time past, else queue in incomings
if (t <= _root.time) {
var path = '_root.'+plist[1];
plist[0] = t;
plist.unshift(guid);
var eventMethod = eval(path);
var parent = eval(parent(path));
logAdd(parameters);
eventMethod.call(parent, plist);
_root.del.push(guid);
fe[guid] = true;
}
return guid;
}
// _____________________________________________________________________________________________________________________ //
function guid() {
return 'g'+(Math.random()+getTimer());
}
function parent(s) {
return s.substr(0,s.lastIndexOf('.'));
}
// Sends log output to its associated perl-peer for output
// - use logPattern = ^\. to filter since they all start with ...guid
function logAdd(entry) {
//sendMessage('log='+entry, '');
if (_root.shell._visible == false) return;
_root.shell.lines.push(entry);
while (_root.shell.lines.length>_root.shell.buffer) _root.shell.lines.shift();
_root.shell.text = _root.shell.lines.join("\n");
_root.shell.setTextFormat(_root.shell.format);
}
function logClr() {
_root.shell.lines = [];
}
function tab(list, w) {
for (var i = 0; i < list.length; i++) {
var pad = ' ';
var s = list[i];
var l = s.length;
s = s.substr(0,w);
if (s.length < w) s = s+p.substr(0,w-l);
}
}
// _____________________________________________________________________________________________________________________ //
// SHELL
function initialiseShell() {
_root.createTextField('shell',5,0,0,1024,768);
var shell = _root.shell;
shell.multiline = true;
shell.wordWrap = true;
shell.border = false;
shell.selectable = false;
shell.wordwrap = false;
shell.format = new TextFormat();
shell.format.color = 0xff00;
shell.format.font = 'Courier New';
shell.format.size = 24;
shell.lines = [];
shell.buffer = 28;
shell._visible = false;
shell.state = 0;
shell.onKeyDown = function() {
var shell = _root.shell;
_root.perl.perlScroll = false;
_root.demo._visible = _root.demo.active = false;
_root.game._visible = _root.game.active = true;
_root.environment.lastActivity = _root.time;
// Shell/game control key
if (Key.isDown(Key.CONTROL) && Key.getCode() == Key.HOME)
shell._visible = (shell.state = ++shell.state%3) != 0;
// Return if shell invisible, else do command entry/execution
if (!shell._visible) return;
var s = shell.lines;
var l = shell.lines.length-1;
var start = _root.CWD.length+16;
if (Key.getCode() == Key.DELETEKEY) s[l] = s[l].substr(0,start);
else if (Key.getCode() == Key.BACKSPACE) {
if (s[l].length > start) s[l] = s[l].substr(0, s[l].length-1);
}
else if (Key.getCode() == Key.ENTER) {
var input = s[l].substr(start,1000);
if (input != '') {
// Extract command and data portions of input
var obj;
var cmd = input.split(' ');
var parameters;
if (cmd.length > 1) parameters = input.substr(input.indexOf(' ')+1,1000);
cmd = cmd[0];
if ((cmd == '?') || (cmd == 'help')) {
// help - lame, cmd code and syntax strings should be in shell object
logAdd(' sickShell Commands:');
logAdd(' demo view peers');
logAdd(' ls cd set sync time');
logAdd(' interfaces perl connect');
logAdd(' Keys:');
logAdd(' CTRL + HOME : enable/disable game and shell');
}
else if (cmd == 'ls') {
// ls
if (parameters == null) obj = refFromPath(_root.CWD); else obj = refFromPath(parameters);
var n=0;
for (var i in obj) {
var t = typeOf(obj[i]);
if (obj == _root) {
if (t == 'object' || t == 'movieclip') {s.push(' '+i+' ('+t+')'); n++;}
} else {s.push(' '+i+' ('+t+')'); n++;}
}
logAdd(''+n+' object(s).');
}
else if (cmd == 'cd') {
// cd
if (parameters == '..') _root.CWD = fixPath(parent(_root.CWD));
else if (parameters != null) {
obj = refFromPath(parameters);
if (obj != null) _root.CWD = fixPath(parameters);
}
}
else if (cmd == 'set') {
// set
var j = parameters.split('=');
obj = refFromPath(j[0]);
var t = typeOf(obj);
if ((t != 'undefined') && (t != 'object') && (t != 'movieclip') && (t != 'function')) {
obj=j[1];
logAdd(' '+j[0]+' set to '+j[1]);
} else logAdd('Could not set '+j[0]+' to '+j[1]);
}
else if (cmd == 'connect') {
// connect
sendMessage('connect='+parameters, '');
logAdd('Connection requested');
}
else if (cmd == 'sync') {
// sync
_root.timeError = -getTimer();
logAdd('Time reset.');
}
else if (cmd == 'time') {
// time
logAdd('Time : '+time);
}
else if (cmd == 'interfaces') {
// interfaces
updateInterfaces();
}
else if (cmd == 'peers') {
// peers
for (var i = 0; i < _root.network.peers.length; i++)
logAdd(' '+i+' : '+_root.network.peers[i]);
logAdd(' My peer is '+_root.network.thisPeer);
}
else if (cmd == 'view') {
// view
_root.environment.angle = 0.0+parameters;
logAdd(' View angle set to '+_root.environment.angle);
}
else if (cmd == 'demo') {
// demo
if (parameters == null) {
_root.demo._visible = _root.demo.active = true;
_root.game._visible = _root.game.active = false;
}
else {
_root.demo.setPersona(parameters);
logAdd(' Persona : '+_root.demo.persona);
}
}
else if (cmd == 'rand') {
// rand
logAdd(prand(100));
}
else logAdd('Unknown command: '+input);
};
prompt();
}
else s[l] += String.fromCharCode(Key.getAscii());
while (s.length > _root.shell.buffer) s.shift();
_root.shell.text = s.join("\n");
_root.shell.setTextFormat(_root.shell.format);
};
Key.addListener(shell);
prompt();
}
function prompt() {
_root.shell.lines.push("sickShell:_root"+_root.CWD+'$');
}
// todo: change events to use this
function refFromPath(path) {
if (path == '.') return _root;
var cwd = _root.CWD;
if (path == '') path = cwd;
else if (path.indexOf('.') != 0) path = cwd+'.'+path;
var ref = eval('_root'+path);
if (ref == null) logAdd("Couldn't resolve object!");
return ref;
}
// todo: get rid of this shit
function fixPath(path) {
var cwd = _root.CWD;
if (cwd == '.') cwd = '';
if (path.indexOf('.') != 0) path = cwd+'.'+path;
return path;
}