UNPKG

creatures

Version:

Library to interface with the Creatures 2 game

546 lines (436 loc) 10.7 kB
var Blast = __Protoblast, Fn = Blast.Collection.Function; // Get the Creatures namespace var Creatures = Fn.getNamespace('Develry.Creatures'); /** * The Egg Class * * @author Jelle De Loecker <jelle@develry.be> * @since 0.1.0 * @version 0.2.0 * * @param {CreaturesApplication} app * @param {Array} data */ var Egg = Fn.inherits('Develry.Creatures.Base', function Egg(app, id) { // The application this.app = app; // Creatures sens an egg targ that isn't an egg this.not_an_egg = false; // The targ id this.id = id; // The moniker, this will only need to be fetched once this.moniker = null; this.hex_moniker = null; // The stage of the egg this.stage = 0; // Is the egg paused? this.paused = null; }); /** * Current gender * * @author Jelle De Loecker <jelle@develry.be> * @since 0.2.1 * @version 0.2.1 * * @type {String} */ Egg.setProperty(function gender() { var result = ''; if (this.sex == 0) { result = 'Unknown'; } else if (this.sex == 1) { result = 'Male'; } else if (this.sex == 2) { result = 'Female'; } return result; }); /** * Is this egg hatching? * * @author Jelle De Loecker <jelle@develry.be> * @since 0.2.1 * @version 0.2.1 * * @type {Boolean} */ Egg.setProperty(function hatching() { return this.stage == 6; }); /** * Has this egg hatched? * * @author Jelle De Loecker <jelle@develry.be> * @since 0.2.1 * @version 0.2.1 * * @type {Boolean} */ Egg.setProperty(function hatched() { return this.stage == 7; }); /** * Perform an egg-specific command * * @author Jelle De Loecker <jelle@develry.be> * @since 0.2.1 * @version 0.2.1 * * @param {String} cmd * @param {Function} callback */ Egg.setMethod(function command(cmd, callback) { if (!this.id) { return callback(new Error('This egg has no valid id')); } cmd = "inst,targ " + this.id + "," + cmd; this.app.command(cmd, callback); }); /** * Solve the disappearance of this egg * * @author Jelle De Loecker <jelle@develry.be> * @since 0.2.1 * @version 0.2.1 * * @param {Function} callback */ Egg.setMethod(function solveDisappearance(callback) { var that = this; if (!callback) { callback = Fn.thrower; } // Get all the available creatures this.app.getCreatures(function gotCreatures(err, creatures) { var matching_creature; if (err) { return callback(err); } // Iterate over all the creatures and see if there's a match creatures.forEach(function eachCreature(creature) { if (creature.moniker && creature.moniker == that.moniker) { matching_creature = creature; } }); if (matching_creature) { // If it hasn't been emitted yet, do the hatched event now that.emitOnce('hatched', matching_creature); // And finally the removed event (when the egg shell is gone) that.emit('removed', 'hatched', matching_creature); } else { that.emit('removed'); } }); }); /** * Pause this egg * * @author Jelle De Loecker <jelle@develry.be> * @since 0.2.1 * @version 0.2.1 * * @param {Function} callback */ Egg.setMethod(function pause(callback) { var that = this; if (!callback) { callback = Fn.thrower; } // It's already hatching, nothing to pause if (this.hatching || this.hatched) { return Blast.setImmediate(callback); } this.command('doif pose lt 6,doif tick gt 0,tick 0,endi,endi', function paused(err) { if (err) { return callback(err); } that.paused = true; that.update(callback); }); }); /** * Pause this egg * * @author Jelle De Loecker <jelle@develry.be> * @since 0.2.1 * @version 0.2.1 * * @param {Function} callback */ Egg.setMethod(function resume(callback) { var that = this; if (!callback) { callback = Fn.thrower; } // It's already hatching, nothing to resume if (this.hatching || this.hatched) { return Blast.setImmediate(callback); } this.command('doif pose lt 6,doif tick eq 0,tick 600,endi,endi', function resumed(err) { if (err) { return callback(err); } that.paused = false; that.update(callback); }); }); /** * Hatch this egg * * @author Jelle De Loecker <jelle@develry.be> * @since 0.2.1 * @version 0.2.1 * * @param {Function} callback */ Egg.setMethod(function hatch(callback) { var that = this; if (!callback) { callback = Fn.thrower; } // It's already hatching, nothing to force if (this.hatching || this.hatched) { return Blast.setImmediate(callback); } this.command('doif pose le 6,pose 6,setv attr 195,tick 10,endi', function hatched(err) { if (err) { return callback(err); } that.paused = false; that.update(callback); }); }); /** * Get a parent of this egg * * @author Jelle De Loecker <jelle@develry.be> * @since 0.2.4 * @version 0.2.7 * * @param {String} type mother or father * @param {Function} callback */ Egg.setMethod(function getParent(type, callback) { var that = this, prop = '_parent_' + type; if (this.hasBeenSeen('getting_' + type)) { this.log('verbose', 'Getting', type, 'of egg', this.moniker, 'from cache'); // The event name might start with "got_", it is also fired // when the parent is unable to be found return this.afterOnce('got_' + type, function gotParent() { callback(null, that[prop]); }); } this.log('debug', 'Getting', type, 'of egg', this.moniker, 'for first time'); this.emit('getting_' + type); function done(err, result) { if (err) { that.log('error', 'Error finding', type, 'of egg', that.moniker, err); } else if (result) { that.log('verbose', 'Found', type, 'of egg', that.moniker, ':', result.moniker); } else { that.log('warning', 'Did not find', type, 'of egg', that.moniker); } if (err) { callback(err); } else { that[prop] = result; callback(null, result); } that.emit('got_' + type); }; this.loadGeneFile(function loadedGene(err) { if (err) { return done(err); } let genus = that.gene.getGenesOfName('Genus'); if (!genus || !genus[0]) { return done(new Error('Could not find Genus of egg needed for parent info')); } else { genus = genus[0]; } let moniker = that.app.formatMoniker(genus.data[type + '_moniker']).trim(); if (!moniker) { return done(new Error('Unable to find ' + type + ' moniker of egg ' + that.moniker)); } that.app.getCreature(false, moniker, function gotParent(err, parent) { if (err) { that.log('error', 'Unable to get egg parent creature (' + type + ') with moniker "' + moniker + '"', err); return done(); } if (!parent.id) { return parent.updateByHistory(function updateddone(err) { if (err) { return done(err); } that[prop] = parent; done(null, parent); }); } that[prop] = parent; done(null, parent); }); }); }); /** * Get the mother of this egg * * @author Jelle De Loecker <jelle@develry.be> * @since 0.2.4 * @version 0.2.4 * * @param {Function} callback */ Egg.setMethod(function getMother(callback) { return this.getParent('mother', callback); }); /** * Get the father of this egg * * @author Jelle De Loecker <jelle@develry.be> * @since 0.2.4 * @version 0.2.4 * * @param {Function} callback */ Egg.setMethod(function getFather(callback) { return this.getParent('father', callback); }); /** * Load gene file * * @author Jelle De Loecker <jelle@develry.be> * @since 0.2.4 * @version 0.2.4 * * @param {Function} callback */ Egg.setMethod(function loadGeneFile(callback) { return Creatures.Creature.prototype.loadGeneFile.call(this, callback); }); /** * Init the egg * * @author Jelle De Loecker <jelle@develry.be> * @since 0.2.4 * @version 0.2.4 */ Egg.setMethod(function findParents() { if (this.hasBeenSeen('ready')) { return; } if (this.hasBeenSeen('readying')) { return; } if (!this.moniker || this.hex_moniker == '0') { return; } this.emit('readying'); let that = this; Fn.parallel(function getMother(next) { that.getMother(function gotMother(err, mother) { that.mother = mother; next(err); }); }, function getFather(next) { that.getFather(function gotFather(err, father) { that.father = father; next(err); }); }, function done(err) { if (err) { that.log('error', 'Failed to get parents of egg', that.moniker); } that.emit('ready'); }); }); /** * Update this egg's data * * @author Jelle De Loecker <jelle@develry.be> * @since 0.1.0 * @version 0.2.7 * * @param {Function} callback */ Egg.setMethod(function update(callback) { var that = this, cmd; if (this.not_an_egg) { return Blast.nextTick(callback); } // Construct the command // 'targ ' + this.id + ', cmd = 'dde: putv obv0,dde: putv pose,dde: putv obv1,dde: putv '; if (that.app.is_c1) { cmd += 'obv2'; } else { cmd += 'tick'; } cmd += ',dde: putv obv3'; that.command(cmd, function gotCommand(err, egg_res) { var egg_data; if (err) { return callback(err); } egg_data = egg_res.split('|'); if (egg_data[0] == 0) { that.id = ''; that.removed = true; } // Format the moniker if (!that.moniker) { that.hex_moniker = Number(egg_data[0]).toString(16); that.moniker = that.app.formatMoniker(that.hex_moniker).split('').reverse().join('').trim(); // Make sure we found the parents that.findParents(); } // Some monikers exist out of 0 bytes // (Don't know where they come from though) if (!that.moniker || that.moniker.charCodeAt(0) == 0) { that.moniker = ''; that.not_an_egg = true; return callback(); } // The stage of the egg that.stage = Number(egg_data[1]); // The sex of the egg // 0 is unkown, 1 is male, 2 is female that.sex = Number(egg_data[2]); // Gender properties that.male = that.sex == 1; that.female = that.sex == 2; // Current tick progress that.tick_progress = Number(egg_data[3]); if (that.app.is_c1) { if (egg_data[3] == 2) { that.paused = true; } else { that.paused = false; } } else { if (that.stage <= 3 && that.tick_progress == 0) { that.paused = true; } else { that.paused = false; } } // Stage 7 means it has hatched! if (that.stage == 7) { that.app.getCreature(false, that.moniker, function gotCreature(err, creature) { if (err || !creature) { return; } // Emit the hatched event that.emitOnce('hatched', creature); }); } that.afterOnce('ready', function afterReady() { callback(null); that.emit('updated'); }); }); }); module.exports = Egg;