diff --git a/tutorial/ACAudioSearchAndInject_tutorial.js b/tutorial/ACAudioSearchAndInject_tutorial.js deleted file mode 100644 index 5e2998ff1e..0000000000 --- a/tutorial/ACAudioSearchAndInject_tutorial.js +++ /dev/null @@ -1,308 +0,0 @@ -"use strict"; - -/*jslint nomen: true, plusplus: true, vars: true*/ -/*global AvatarList, Entities, EntityViewer, Script, SoundCache, Audio, print, randFloat*/ -// -// ACAudioSearchAndInject.js -// audio -// -// Created by Eric Levin and Howard Stearns 2/1/2016 -// Copyright 2016 High Fidelity, Inc. -// -// Keeps track of all sounds within QUERY_RADIUS of an avatar, where a "sound" is specified in entity userData. -// Inject as many as practical into the audio mixer. -// See acAudioSearchAndCompatibilityEntitySpawner.js. -// -// This implementation takes some precautions to scale well: -// - It doesn't hastle the entity server because it issues at most one octree query every UPDATE_TIME period, regardless of the number of avatars. -// - It does not load itself because it only gathers entities once every UPDATE_TIME period, and only -// checks entity properties for those small number of entities that are currently playing (plus a RECHECK_TIME period examination of all entities). -// This implementation tries to use all the available injectors. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - -var MSEC_PER_SEC = 1000; -var SOUND_DATA_KEY = "io.highfidelity.soundKey"; // Sound data is specified in userData under this key. -var old_sound_data_key = "soundKey"; // For backwards compatibility. -var QUERY_RADIUS = 50; // meters -var UPDATE_TIME = 100; // ms. We'll update just one thing on this period. -var EXPIRATION_TIME = 5 * MSEC_PER_SEC; // ms. Remove sounds that have been out of range for this time. -var RECHECK_TIME = 10 * MSEC_PER_SEC; // ms. Check for new userData properties this often when not currently playing. -// (By not checking most of the time when not playing, we can efficiently go through all entities without getEntityProperties.) -var UPDATES_PER_STATS_LOG = RECHECK_TIME / UPDATE_TIME; // (It's nice to smooth out the results by straddling a recheck.) - -var DEFAULT_SOUND_DATA = { - volume: 0.5, // userData cannot specify zero volume with our current method of defaulting. - loop: false, // Default must be false with our current method of defaulting, else there's no way to get a false value. - playbackGap: MSEC_PER_SEC, // in ms - playbackGapRange: 0 // in ms -}; - -//var AGENT_AVATAR_POSITION = { x: -1.5327, y: 0.672515, z: 5.91573 }; -var AGENT_AVATAR_POSITION = { x: -2.83785, y: 1.45243, z: -13.6042 }; - -//var isACScript = this.EntityViewer !== undefined; -var isACScript = true; - -if (isACScript) { - Agent.isAvatar = true; // This puts a robot at 0,0,0, but is currently necessary in order to use AvatarList. - Avatar.skeletonModelURL = "http://hifi-content.s3.amazonaws.com/ozan/dev/avatars/invisible_avatar/invisible_avatar.fst"; - Avatar.position = AGENT_AVATAR_POSITION; - Agent.isListeningToAudioStream = true; -} -function ignore() {} -function debug() { // Display the arguments not just [Object object]. - //print.apply(null, [].map.call(arguments, JSON.stringify)); -} - -function randFloat(low, high) { - return low + Math.random() * (high - low); -} - -if (isACScript) { - EntityViewer.setCenterRadius(QUERY_RADIUS); -} - -// ENTITY DATA CACHE -// -var entityCache = {}; // A dictionary of unexpired EntityData objects. -var entityInvalidUserDataCache = {}; // A cache containing the entity IDs that have - // previously been identified as containing non-JSON userData. - // We use a dictionary here so id lookups are constant time. -var examinationCount = 0; -function EntityDatum(entityIdentifier) { // Just the data of an entity that we need to know about. - // This data is only use for our sound injection. There is no need to store such info in the replicated entity on everyone's computer. - var that = this; - that.lastUserDataUpdate = 0; // new entity is in need of rechecking user data - // State Transitions: - // no data => no data | sound data | expired - // expired => stop => remove - // sound data => downloading - // downloading => downloading | waiting - // waiting => playing | waiting (if too many already playing) - // playing => update position etc | no data - that.stop = function stop() { - if (!that.sound) { - return; - } - print("stopping sound", entityIdentifier, that.url); - delete that.sound; - delete that.url; - if (!that.injector) { - return; - } - that.injector.stop(); - delete that.injector; - }; - this.update = function stateTransitions(expirationCutoff, userDataCutoff, now) { - if (that.timestamp < expirationCutoff) { // EXPIRED => STOP => REMOVE - that.stop(); // Alternatively, we could fade out and then stop... - delete entityCache[entityIdentifier]; - return; - } - var properties, soundData; // Latest data, pulled from local octree. - - // getEntityProperties locks the tree, which competes with the asynchronous processing of queryOctree results. - // Most entity updates are fast and only a very few do getEntityProperties. - function ensureSoundData() { // We only getEntityProperities when we need to. - if (properties) { - return; - } - properties = Entities.getEntityProperties(entityIdentifier, ['userData', 'position']); - examinationCount++; // Collect statistics on how many getEntityProperties we do. - debug("updating", that, properties); - try { - var userData = properties.userData && JSON.parse(properties.userData); - soundData = userData && (userData[SOUND_DATA_KEY] || userData[old_sound_data_key]); // Don't store soundData yet. Let state changes compare. - that.lastUserDataUpdate = now; // But do update these ... - that.url = soundData && soundData.url; - that.playAfter = that.url && now; - } catch (err) { - if (!(entityIdentifier in entityInvalidUserDataCache)) { - print(err, properties.userData); - entityInvalidUserDataCache[entityIdentifier] = true; - } - } - } - - // Stumbling on big new pile of entities will do a lot of getEntityProperties. Once. - if (that.lastUserDataUpdate < userDataCutoff) { // NO DATA => SOUND DATA - ensureSoundData(); - } - - if (!that.url) { // NO DATA => NO DATA - return that.stop(); - } - - if (!that.sound) { // SOUND DATA => DOWNLOADING - that.sound = SoundCache.getSound(soundData.url); // SoundCache can manage duplicates better than we can. - } - - if (!that.sound.downloaded) { // DOWNLOADING => DOWNLOADING - return; - } - - if (that.playAfter > now) { // DOWNLOADING | WAITING => WAITING - return; - } - - ensureSoundData(); // We'll try to play/setOptions and will need position, so we might as well get soundData, too. - if (soundData.url !== that.url) { // WAITING => NO DATA (update next time around) - return that.stop(); - } - - var options = { - position: properties.position, - loop: soundData.loop || DEFAULT_SOUND_DATA.loop, - volume: soundData.volume || DEFAULT_SOUND_DATA.volume - }; - - function repeat() { - return !options.loop && (soundData.playbackGap >= 0); - } - - function randomizedNextPlay() { // time of next play or recheck, randomized to distribute the work - var range = soundData.playbackGapRange || DEFAULT_SOUND_DATA.playbackGapRange, - base = repeat() ? ((that.sound.duration * MSEC_PER_SEC) + (soundData.playbackGap || DEFAULT_SOUND_DATA.playbackGap)) : RECHECK_TIME; - return now + base + randFloat(-Math.min(base, range), range); - } - - if (that.injector && soundData.playing === false) { - that.injector.stop(); - that.injector = null; - } - - if (!that.injector) { - if (soundData.playing === false) { // WAITING => PLAYING | WAITING - return; - } - debug("starting", that, options); - that.injector = Audio.playSound(that.sound, options); // Might be null if at at injector limit. Will try again later. - if (that.injector) { - print("started", entityIdentifier, that.url); - } else { // Don't hammer ensureSoundData or injector manager. - that.playAfter = randomizedNextPlay(); - } - return; - } - - that.injector.setOptions(options); // PLAYING => UPDATE POSITION ETC - if (!that.injector.playing) { // Subtle: a looping sound will not check playbackGap. - if (repeat()) { // WAITING => PLAYING - // Setup next play just once, now. Changes won't be looked at while we wait. - that.playAfter = randomizedNextPlay(); - // Subtle: if the restart fails b/c we're at injector limit, we won't try again until next playAfter. - that.injector.restart(); - } else { // PLAYING => NO DATA - that.playAfter = Infinity; // was one-shot and we're finished - } - } - }; -} - -function internEntityDatum(entityIdentifier, timestamp, avatarPosition, avatar) { - ignore(avatarPosition, avatar); // We could use avatars and/or avatarPositions to prioritize which ones to play. - var entitySound = entityCache[entityIdentifier]; - if (!entitySound) { - entitySound = entityCache[entityIdentifier] = new EntityDatum(entityIdentifier); - } - entitySound.timestamp = timestamp; // Might be updated for multiple avatars. That's fine. -} - -var nUpdates = UPDATES_PER_STATS_LOG, lastStats = Date.now(); - -function updateAllEntityData() { // A fast update of all entities we know about. A few make sounds. - var now = Date.now(), - expirationCutoff = now - EXPIRATION_TIME, - userDataRecheckCutoff = now - RECHECK_TIME; - Object.keys(entityCache).forEach(function (entityIdentifier) { - entityCache[entityIdentifier].update(expirationCutoff, userDataRecheckCutoff, now); - }); - if (nUpdates-- <= 0) { // Report statistics. - // For example, with: - // injector-limit = 40 (in C++ code) - // N_SOUNDS = 1000 (from userData in, e.g., acAudioSearchCompatibleEntitySpawner.js) - // replay-period = 3 + 20 = 23 (seconds, ditto) - // stats-period = UPDATES_PER_STATS_LOG * UPDATE_TIME / MSEC_PER_SEC = 10 seconds - // The log should show between each stats report: - // "start" lines ~= injector-limit * P(finish) = injector-limit * stats-period/replay-period = 17 ? - // total attempts at starting ("start" lines + "could not thread" lines) ~= N_SOUNDS = 1000 ? - // entities > N_SOUNDS * (1+ N_SILENT_ENTITIES_PER_SOUND) = 11000 + whatever was in the scene before running spawner - // sounds = N_SOUNDS = 1000 - // getEntityPropertiesPerUpdate ~= playing + failed-starts/UPDATES_PER_STATS_LOG + other-rechecks-each-update - // = injector-limit + (total attempts - "start" lines)/UPDATES_PER_STATS__LOG - // + (entities - playing - failed-starts/UPDATES_PER_STATS_LOG) * P(recheck-in-update) - // where failed-starts/UPDATES_PER_STATS_LOG = (1000-17)/100 = 10 - // = 40 + 10 + (11000 - 40 - 10)*UPDATE_TIME/RECHECK_TIME - // = 40 + 10 + 10950*0.01 = 159 (mostly proportional to enties/RECHECK_TIME) - // millisecondsPerUpdate ~= UPDATE_TIME = 100 (+ some timer machinery time) - // this assignment client activity monitor < 100% cpu - var stats = { - entities: 0, - sounds: 0, - playing: 0, - getEntityPropertiesPerUpdate: examinationCount / UPDATES_PER_STATS_LOG, - millisecondsPerUpdate: (now - lastStats) / UPDATES_PER_STATS_LOG - }; - nUpdates = UPDATES_PER_STATS_LOG; - lastStats = now; - examinationCount = 0; - Object.keys(entityCache).forEach(function (entityIdentifier) { - var datum = entityCache[entityIdentifier]; - stats.entities++; - if (datum.url) { - stats.sounds++; - if (datum.injector && datum.injector.playing) { - stats.playing++; - } - } - }); - print(JSON.stringify(stats)); - } -} - -// Update the set of which EntityData we know about. -// -function updateEntiesForAvatar(avatarIdentifier) { // Just one piece of update work. - // This does at most: - // one queryOctree request of the entity server, and - // one findEntities geometry query of our own octree, and - // a quick internEntityDatum of each of what may be a large number of entityIdentifiers. - // The idea is that this is a nice bounded piece of work that should not be done too frequently. - // However, it means that we won't learn about new entities until, on average (nAvatars * UPDATE_TIME) + query round trip. - var avatar = AvatarList.getAvatar(avatarIdentifier), avatarPosition = avatar && avatar.position; - if (!avatarPosition) { // No longer here. - return; - } - var timestamp = Date.now(); - if (isACScript) { - EntityViewer.setPosition(avatarPosition); - EntityViewer.queryOctree(); // Requests an update, but there's no telling when we'll actually see different results. - } - var entities = Entities.findEntities(avatarPosition, QUERY_RADIUS); - debug("found", entities.length, "entities near", avatar.name || "unknown", "at", avatarPosition); - entities.forEach(function (entityIdentifier) { - internEntityDatum(entityIdentifier, timestamp, avatarPosition, avatar); - }); -} - -// Slowly update the set of data we have to work with. -// -var workQueue = []; -function updateWorkQueueForAvatarsPresent() { // when nothing else to do, fill queue with individual avatar updates - workQueue = AvatarList.getAvatarIdentifiers().map(function (avatarIdentifier) { - return function () { - updateEntiesForAvatar(avatarIdentifier); - }; - }); -} -Script.setInterval(function () { - // There might be thousands of EntityData known to us, but only a few will require any work to update. - updateAllEntityData(); // i.e., this better be pretty fast. - // Each interval, we do no more than one updateEntitiesforAvatar. - if (!workQueue.length) { - workQueue = [updateWorkQueueForAvatarsPresent]; - } - workQueue.pop()(); // There's always one -}, UPDATE_TIME); diff --git a/tutorial/Changelog.md b/tutorial/Changelog.md deleted file mode 100644 index bd923b6841..0000000000 --- a/tutorial/Changelog.md +++ /dev/null @@ -1,3 +0,0 @@ - * home-tutorial-34 - * Update tutorial to only start if `HMD.active` - * Update builder's grid to use "Good - Sub-meshes" for collision shape type diff --git a/tutorial/entityData.js b/tutorial/entityData.js deleted file mode 100644 index b14185e78f..0000000000 --- a/tutorial/entityData.js +++ /dev/null @@ -1,131 +0,0 @@ -fireworkURLs = [ - "atp:/tutorial_models/bomb1.fbx", - "atp:/tutorial_models/bomb2.fbx", - "atp:/tutorial_models/bomb3.fbx", - "atp:/tutorial_models/bomb4.fbx", - "atp:/tutorial_models/bomb5.fbx", - "atp:/tutorial_models/bomb6.fbx", -]; - -fireworkBaseProps = { - "collisionsWillMove": 1, - velocity: { - x: 0, - y: -0.2, - z: 0 - }, - "dynamic": 1, - "gravity": { - "x": 0, - "y": -10, - "z": 0 - }, - "id": "{1c4061bc-b2e7-4435-bc47-3fcc39ae6624}", - "modelURL": "atp:/tutorial_models/bomb1.fbx", - "owningAvatarID": "{00000000-0000-0000-0000-000000000000}", - "position": { - "x": 0.11612319946289062, - "y": 0, - "z": 0.21749019622802734 - }, - "queryAACube": { - "scale": 0.24519434571266174, - "x": -0.0064739733934402466, - "y": -0.12259717285633087, - "z": 0.094893023371696472 - }, - "rotation": { - "w": -0.083054840564727783, - "x": 0.93615627288818359, - "y": 0.34154272079467773, - "z": -0.0073701143264770508 - }, - "shapeType": "simple-hull", - "type": "Model", - "userData": "{\n \"hifiHomeKey\": {\n \"reset\": true\n }\n}" -} ; - - -birdFirework2 = { - "collisionsWillMove": 1, - velocity: { - x: 0, - y: -0.01, - z: 0 - }, - "dynamic": 1, - "gravity": { - "x": 0, - "y": -10, - "z": 0 - }, - "id": "{ba067084-8d0f-4eeb-a8a1-c6814527c1bb}", - "modelURL": "atp:/tutorial_models/bomb2.fbx", - "owningAvatarID": "{00000000-0000-0000-0000-000000000000}", - "position": { - "x": 0, - "y": 0.014694660902023315, - "z": 0 - }, - "queryAACube": { - "scale": 0.24011452496051788, - "x": -0.12005726248025894, - "y": -0.10536260157823563, - "z": -0.12005726248025894 - }, - "rotation": { - "w": 0.55410087108612061, - "x": 0.36000609397888184, - "y": -0.33641564846038818, - "z": -0.67092394828796387 - }, - "shapeType": "simple-compound", - "type": "Model", - "userData": "{\n \"hifiHomeKey\": {\n \"reset\": true\n }\n}" -}; - - -Step1BlockData = { - "clientOnly": 0, - "color": { - "blue": 0, - "green": 0, - "red": 255 - }, - "created": "2016-08-22T22:54:07Z", - "dimensions": { - "x": 0.20000000298023224, - "y": 0.20000000298023224, - "z": 0.20000000298023224 - }, - name: "tutorial/block", - "collisionsWillMove": 1, - velocity: { - x: 0, - y: -0.2, - z: 0 - }, - "dynamic": 1, - "gravity": { - "x": 0, - "y": -10, - "z": 0 - }, - "id": "{5c7223f8-3bc5-4cb4-913c-0e93f5994ca2}", - "owningAvatarID": "{00000000-0000-0000-0000-000000000000}", - "queryAACube": { - "scale": 0.34641015529632568, - "x": -0.17320507764816284, - "y": -0.17320507764816284, - "z": -0.17320507764816284 - }, - "rotation": { - "w": 1, - "x": -0.0001373291015625, - "y": -7.62939453125e-05, - "z": -0.0003204345703125 - }, - "shape": "Cube", - "type": "Box", - "userData": JSON.stringify({ hifiHomeKey: { reset: true } }), -}; diff --git a/tutorial/firePit/fire.js b/tutorial/firePit/fire.js deleted file mode 100644 index 4565975351..0000000000 --- a/tutorial/firePit/fire.js +++ /dev/null @@ -1,181 +0,0 @@ -// Originally written by James Pollack, modified by Ryan Huffman for the tutorial -// -// this script turns an entity into an exploder -- anything that collides with it will be vaporized! - -(function() { - - function debug() { - var args = Array.prototype.slice.call(arguments); - args.unshift("fire.js | "); - print.apply(this, args); - } - - var _this = this; - - function Fire() { - _this = this; - } - - var RED = { - red: 255, - green: 0, - blue: 0 - }; - - var ORANGE = { - red: 255, - green: 165, - blue: 0 - }; - - var YELLOW = { - red: 255, - green: 255, - blue: 0 - }; - - var GREEN = { - red: 0, - green: 255, - blue: 0 - }; - - var BLUE = { - red: 0, - green: 0, - blue: 255 - }; - - var INDIGO = { - red: 128, - green: 0, - blue: 128 - }; - - var VIOLET = { - red: 75, - green: 0, - blue: 130 - }; - - var colors = [RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET]; - - var firePitSoundURL = Script.resolvePath("fire_burst.wav"); - debug("Firepit burst sound url is: ", firePitSoundURL); - - var explodeTextureURL = Script.resolvePath("explode.png"); - debug("Firepit explode texture url is: ", explodeTextureURL); - - Fire.prototype = { - preload: function(entityID) { - debug("Preload"); - this.entityID = entityID; - this.EXPLOSION_SOUND = SoundCache.getSound(firePitSoundURL); - }, - collisionWithEntity: function(myID, otherID, collisionInfo) { - debug("Collided with entity: ", myID, otherID); - var otherProps = Entities.getEntityProperties(otherID); - var data = null; - try { - data = JSON.parse(otherProps.userData); - } catch (err) { - debug('ERROR GETTING USERDATA!'); - } - if (data === null || "") { - debug("Data is null or empty", data); - return; - } else { - debug("Got data", data); - if (data.hasOwnProperty('hifiHomeKey')) { - debug("Has hifiHomeKey"); - if (data.hifiHomeKey.reset === true) { - debug("Reset is true"); - _this.playSoundAtCurrentPosition(); - _this.explodeWithColor(); - Entities.deleteEntity(otherID) - debug("Sending local message"); - Messages.sendLocalMessage('Entity-Exploded', JSON.stringify({ - entityID: otherID, - position: Entities.getEntityProperties(this.entityID).position - })); - debug("Done sending local message"); - } - } - } - }, - explodeWithColor: function() { - var myProps = Entities.getEntityProperties(this.entityID); - var color = colors[Math.floor(Math.random() * colors.length)]; - var explosionParticleProperties = { - "color": color, - "isEmitting": 1, - "maxParticles": 1000, - "lifespan": 0.25, - "emitRate": 1, - "emitSpeed": 0.1, - "speedSpread": 1, - "emitOrientation": Quat.getUp(myProps.rotation), - "emitDimensions": { - "x": 0, - "y": 0, - "z": 0 - }, - "polarStart": 0, - "polarFinish": 0, - "azimuthStart": 0, - "azimuthFinish": 0, - "emitAcceleration": { - "x": 0, - "y": 0, - "z": 0 - }, - "accelerationSpread": { - "x": 0, - "y": 0, - "z": 0 - }, - "particleRadius": 0.829, - "radiusSpread": 0, - "radiusStart": 0.361, - "radiusFinish": 0.294, - "colorSpread": { - "red": 0, - "green": 0, - "blue": 0 - }, - "colorStart": { - "red": 255, - "green": 255, - "blue": 255 - }, - "colorFinish": { - "red": 255, - "green": 255, - "blue": 255 - }, - "alpha": 1, - "alphaSpread": 0, - "alphaStart": -0.2, - "alphaFinish": 0.5, - "emitterShouldTrail": 0, - "textures": explodeTextureURL, - "type": "ParticleEffect", - lifetime: 1, - position: myProps.position - }; - - var explosion = Entities.addEntity(explosionParticleProperties); - }, - playSoundAtCurrentPosition: function() { - - var audioProperties = { - volume: 0.5, - position: Entities.getEntityProperties(this.entityID).position - }; - - Audio.playSound(this.EXPLOSION_SOUND, audioProperties); - }, - } - - return new Fire(); -}); diff --git a/tutorial/firePit/flicker.js b/tutorial/firePit/flicker.js deleted file mode 100644 index f4406286c4..0000000000 --- a/tutorial/firePit/flicker.js +++ /dev/null @@ -1,52 +0,0 @@ -// Originally written for the Home content set. Pulled into the tutorial by Ryan Huffman -(function() { - - var MINIMUM_LIGHT_INTENSITY = 50.0; - var MAXIMUM_LIGHT_INTENSITY = 200.0; - var LIGHT_FALLOFF_RADIUS = 0.1; - var LIGHT_INTENSITY_RANDOMNESS = 0.1; - - function randFloat(low, high) { - return low + Math.random() * (high - low); - } - - var _this; - - function FlickeringFlame() { - _this = this; - } - - var totalTime = 0; - var spacer = 2; - FlickeringFlame.prototype = { - preload: function(entityID) { - this.entityID = entityID; - Script.update.connect(this.update); - }, - update: function(deltaTime) { - - totalTime += deltaTime; - if (totalTime > spacer) { - var howManyAvatars = AvatarList.getAvatarIdentifiers().length; - var intensity = (MINIMUM_LIGHT_INTENSITY + (MAXIMUM_LIGHT_INTENSITY + (Math.sin(totalTime) * MAXIMUM_LIGHT_INTENSITY))); - intensity += randFloat(-LIGHT_INTENSITY_RANDOMNESS, LIGHT_INTENSITY_RANDOMNESS); - - Entities.editEntity(_this.entityID, { - intensity: intensity - }); - - spacer = Math.random(0, 100) * (2 / howManyAvatars); - totalTime = 0; - } else { - //just keep counting - } - }, - unload: function() { - Script.update.disconnect(this.update) - } - } - - return new FlickeringFlame - - -}); diff --git a/tutorial/fuse.js b/tutorial/fuse.js deleted file mode 100644 index 59306f4113..0000000000 --- a/tutorial/fuse.js +++ /dev/null @@ -1,119 +0,0 @@ -// -// fuse.js -// -// Created by Ryan Huffman on 9/1/16. -// Copyright 2016 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -(function() { - Script.include('utils.js'); - - var DEBUG = true; - function debug() { - if (DEBUG) { - var args = Array.prototype.slice.call(arguments); - args.unshift("fuse.js | "); - print.apply(this, args); - } - } - - var active = false; - - var fuseSound = SoundCache.getSound("atp:/tutorial_sounds/fuse.wav"); - function getChildProperties(entityID, propertyNames) { - var childEntityIDs = Entities.getChildrenIDs(entityID); - var results = {} - for (var i = 0; i < childEntityIDs.length; ++i) { - var childEntityID = childEntityIDs[i]; - var properties = Entities.getEntityProperties(childEntityID, propertyNames); - results[childEntityID] = properties; - } - return results; - } - var Fuse = function() { - }; - Fuse.prototype = { - light: function() { - debug("Received light()", this.entityID); - - var visible = Entities.getEntityProperties(this.entityID, ['visible']).visible; - if (!visible) { - debug("Fuse is not visible, returning"); - return; - } - - if (active) { - debug("Fuse is active, returning"); - return; - } - active = true; - - Entities.editEntity(this.entityID, { - animation: { - currentFrame: 1, - lastFrame: 150, - running: 1, - url: "atp:/tutorial_models/fuse.fbx", - loop: 0 - }, - }); - var injector = Audio.playSound(fuseSound, { - position: Entities.getEntityProperties(this.entityID, 'position').position, - volume: 0.7, - loop: true - }); - - var childrenProps = getChildProperties(this.entityID, ['type']); - for (var childEntityID in childrenProps) { - debug("Updating: ", childEntityID); - var props = childrenProps[childEntityID]; - if (props.type == "ParticleEffect") { - Entities.editEntity(childEntityID, { - emitRate: 140, - }); - } else if (props.type == "Light") { - Entities.editEntity(childEntityID, { - visible: true, - }); - } - } - - var self = this; - Script.setTimeout(function() { - debug("Setting off fireworks"); - var spinnerID = "{dd13fcd5-616f-4749-ab28-2e1e8bc512e9}"; - Entities.callEntityMethod(spinnerID, "onLit"); - injector.stop(); - - var childrenProps = getChildProperties(self.entityID, ['type']); - for (var childEntityID in childrenProps) { - debug("Updating: ", childEntityID); - var props = childrenProps[childEntityID]; - if (props.type == "ParticleEffect") { - Entities.editEntity(childEntityID, { - emitRate: 0, - }); - } else if (props.type == "Light") { - Entities.editEntity(childEntityID, { - visible: false, - }); - } - } - - }, 4900); - - Script.setTimeout(function() { - debug("Setting fuse to inactive"); - active = false; - }, 14000); - }, - preload: function(entityID) { - debug("Preload"); - this.entityID = entityID; - }, - }; - return new Fuse(); -}); diff --git a/tutorial/fuseCollider.js b/tutorial/fuseCollider.js deleted file mode 100644 index 953fcd316d..0000000000 --- a/tutorial/fuseCollider.js +++ /dev/null @@ -1,18 +0,0 @@ -(function() { - Script.include('utils.js'); - - var Fuse = function() { - }; - Fuse.prototype = { - onLit: function() { - print("fuseCollider.js | Lit", this.entityID); - var fuseID = "{c8944a13-9acb-4d77-b1ee-851845e98357}" - Entities.callEntityMethod(fuseID, "light"); - }, - preload: function(entityID) { - print("fuseCollider.js | preload"); - this.entityID = entityID; - }, - }; - return new Fuse(); -}); diff --git a/tutorial/lighter/butaneLighter.js b/tutorial/lighter/butaneLighter.js deleted file mode 100644 index f37769f867..0000000000 --- a/tutorial/lighter/butaneLighter.js +++ /dev/null @@ -1,192 +0,0 @@ -// -// Created by Thijs Wenker on September 14, 2016. -// Copyright 2016 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -(function() { - var _this; - - function getResourceURL(file) { - return 'atp:/' + file; - }; - - const LIGHTER_ON_SOUND_URL = getResourceURL('tutorial_sounds/lighter_on.wav'); - const BUTANE_SOUND_URL = getResourceURL('tutorial_sounds/butane.wav'); - - // TODO: fix this in the client, changing the sound volume while a sound is playing doesn't seem to work right now - const DYNAMIC_SOUND_VOLUME = false; - const BUTANE_MIN_SOUND_VOLUME = 0.05; - - const FLAME_LENGTH = 0.05; - - const BUTANE_SOUND_SETTINGS = { - volume: 0.4, - loop: true, - playbackGap: 1000, - playbackGapRange: 1000 - }; - - const LIGHTER_ON_SOUND_SETTINGS = { - volume: 0.5, - loop: false - }; - - function RemoteLogSender(channel, identifier) { - this.channel = channel; - this.identifier = identifier; - } - - RemoteLogSender.prototype = { - channel: null, - identifier: null, - debug: function(message) { - Messages.sendLocalMessage(this.channel, JSON.stringify({ - message: '[DEBUG ' + this.identifier + '] ' + message - })); - } - }; - - var remoteLogSender = null; - - function debugPrint(message) { - if (remoteLogSender !== null) { - remoteLogSender.debug(message); - } - } - - ButaneLighter = function() { - _this = this; - _this.triggerValue = 0.0; // be sure to set this value in the constructor, otherwise it will be a shared value - _this.isFiring = false; - } - - ButaneLighter.prototype = { - entityID: null, - lighterOnSound: null, - butaneSound: null, - lighterOnSoundInjector: null, - butaneSoundInjector: null, - butaneSoundInjectorOptions: null, - lighterParticleEntity: null, - buttonBeingPressed: null, - triggerValue: null, - isFiring: null, - getLighterParticleEntity: function() { - var result = null; - Entities.getChildrenIDs(_this.entityID).forEach(function(entity) { - var name = Entities.getEntityProperties(entity, ['name']).name; - if (name === 'lighter_particle') { - result = entity; - } - }); - return result; - }, - preload: function(entityID) { - _this.entityID = entityID; - _this.lighterOnSound = SoundCache.getSound(LIGHTER_ON_SOUND_URL); - _this.butaneSound = SoundCache.getSound(BUTANE_SOUND_URL); - var properties = Entities.getEntityProperties(_this.entityID, ['userData']); - try { - var userData = JSON.parse(properties.userData); - if (userData['debug'] !== undefined && userData['debug']['sessionUUID'] === MyAvatar.sessionUUID && - userData['debug']['channel'] !== undefined) - { - remoteLogSender = new RemoteLogSender(userData['debug']['channel'], _this.entityID); - remoteLogSender.debug('Debugger initialized'); - } - } catch (e) { - //failed to detect if we have a debugger - } - debugPrint(_this.getLighterParticleEntity()); - }, - startEquip: function(entityID, args) { - _this.lighterParticleEntity = _this.getLighterParticleEntity(); - }, - continueEquip: function(entityID, args) { - _this.triggerValue = Controller.getValue(args[0] === 'left' ? Controller.Standard.LT : Controller.Standard.RT); - if (_this.triggerValue > 0.2) { - if (!_this.isFiring) { - _this.startFiring(); - } - _this.tryToIgnite(); - _this.updateButaneSound() - return; - } - _this.stopFiring(); - }, - startFiring: function() { - if (_this.isFiring) { - return; - } - _this.isFiring = true; - if (_this.lighterOnSound.downloaded) { - // We don't want to override the default volume setting, so lets clone the default SETTINGS object - var lighterOnOptions = JSON.parse(JSON.stringify(LIGHTER_ON_SOUND_SETTINGS)); - lighterOnOptions['position'] = Entities.getEntityProperties(_this.entityID, ['position']).position; - _this.lighterOnSoundInjector = Audio.playSound(_this.lighterOnSound, lighterOnOptions); - } - if (_this.butaneSound.downloaded) { - _this.butaneSoundInjectorOptions = JSON.parse(JSON.stringify(BUTANE_SOUND_SETTINGS)); - _this.butaneSoundInjectorOptions['position'] = Entities.getEntityProperties(_this.lighterParticleEntity, ['position']).position; - if (DYNAMIC_SOUND_VOLUME) { - _this.butaneSoundInjectorOptions['volume'] = BUTANE_MIN_SOUND_VOLUME; - } - _this.butaneSoundInjector = Audio.playSound(_this.butaneSound, _this.butaneSoundInjectorOptions); - } - Entities.editEntity(_this.lighterParticleEntity, {isEmitting: _this.isFiring}); - - }, - stopFiring: function() { - if (!_this.isFiring) { - return; - } - _this.isFiring = false; - Entities.editEntity(_this.lighterParticleEntity, {isEmitting: _this.isFiring}); - _this.stopButaneSound(); - }, - tryToIgnite: function() { - var flameProperties = Entities.getEntityProperties(_this.lighterParticleEntity, ['position', 'rotation']); - var pickRay = { - origin: flameProperties.position, - direction: Quat.inverse(Quat.getFront(flameProperties.rotation)) - } - var intersection = Entities.findRayIntersection(pickRay, true, [], [_this.entityID, _this.lighterParticleEntity]); - if (intersection.intersects && intersection.distance <= FLAME_LENGTH) { - var properties = Entities.getEntityProperties(intersection.entityID, 'script'); - if (properties.script !== '') { - Entities.callEntityMethod(intersection.entityID, 'onLit', [_this.triggerValue]); - debugPrint('Light it up! found: ' + intersection.entityID); - } - } - }, - releaseEquip: function(entityID, args) { - _this.stopFiring(); - // reset trigger value; - _this.triggerValue = 0.0; - }, - updateButaneSound: function() { - if (_this.butaneSoundInjector !== null && _this.butaneSoundInjector.isPlaying()) { - _this.butaneSoundInjectorOptions = _this.butaneSoundInjector.options; - _this.butaneSoundInjectorOptions['position'] = Entities.getEntityProperties(_this.entityID, ['position']).position; - if (DYNAMIC_SOUND_VOLUME) { - _this.butaneSoundInjectorOptions['volume'] = ((BUTANE_SOUND_SETTINGS.volume - BUTANE_MIN_SOUND_VOLUME) * - _this.triggerValue) + BUTANE_MIN_SOUND_VOLUME; - } - _this.butaneSoundInjector.options = _this.butaneSoundInjectorOptions; - } - }, - stopButaneSound: function() { - if (_this.butaneSoundInjector !== null && _this.butaneSoundInjector.isPlaying()) { - _this.butaneSoundInjector.stop(); - } - _this.butaneSoundInjector = null; - }, - unload: function() { - _this.stopButaneSound(); - }, - }; - return new ButaneLighter(); -}) diff --git a/tutorial/lighter/createButaneLighter.js b/tutorial/lighter/createButaneLighter.js deleted file mode 100644 index 1a6b94d0f6..0000000000 --- a/tutorial/lighter/createButaneLighter.js +++ /dev/null @@ -1,220 +0,0 @@ -// -// Created by Thijs Wenker on September 14, 2016. -// Copyright 2016 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -const TEST_MODE = false; -const SCRIPT_URL = 'atp:/tutorial/lighter/butaneLighter.js'; - -//Creates an entity and returns a mixed object of the creation properties and the assigned entityID -var createEntity = function(entityProperties, parent) { - if (parent.rotation !== undefined) { - if (entityProperties.rotation !== undefined) { - entityProperties.rotation = Quat.multiply(parent.rotation, entityProperties.rotation); - } else { - entityProperties.rotation = parent.rotation; - } - } - if (parent.position !== undefined) { - var localPosition = (parent.rotation !== undefined) ? Vec3.multiplyQbyV(parent.rotation, entityProperties.position) : entityProperties.position; - entityProperties.position = Vec3.sum(localPosition, parent.position) - } - if (parent.id !== undefined) { - entityProperties.parentID = parent.id; - } - entityProperties.id = Entities.addEntity(entityProperties); - return entityProperties; -}; - -createButaneLighter = function(transform) { - var entityProperties = { - collisionsWillMove: true, - dimensions: { - x: 0.025599999353289604, - y: 0.057399999350309372, - z: 0.37419998645782471 - }, - dynamic: true, - gravity: { - x: 0, - y: -9.8, - z: 0 - }, - velocity: { - x: 0, - y: -0.01, - z: 0 - }, - modelURL: 'atp:/tutorial_models/lighterIceCreamSandwich.fbx', - name: 'BrutaneLighter', - shapeType: 'simple-compound', - type: 'Model', - userData: JSON.stringify({ - "tag": "equip-temporary", - "grabbableKey": { - "invertSolidWhileHeld": true - }, - "wearable": { - "joints": { - "RightHand": [ - { - "x": 0.049671292304992676, - "y": 0.09825992584228516, - "z": 0.03760027885437012 - }, - { - "x": 0.6562752723693848, - "y": 0.27598991990089417, - "z": 0.6638742685317993, - "w": -0.22890058159828186 - } - ], - "LeftHand": [ - { - "x": -0.028073370456695557, - "y": 0.09609812498092651, - "z": 0.039550721645355225 - }, - { - "x": -0.6697965264320374, - "y": 0.22050897777080536, - "z": 0.6544681191444397, - "w": 0.27283111214637756 - } - ] - } - } - }), - script: SCRIPT_URL - }; - return createEntity(entityProperties, transform); -} - -function createFireParticle(butaneLighter) { - var entityProperties = { - userData: JSON.stringify({ tag: "equip-temporary" }), - accelerationSpread: { - x: 0.1, - y: 0, - z: 0.1 - }, - alpha: 0.039999999105930328, - alphaFinish: 0.039999999105930328, - alphaStart: 0.039999999105930328, - azimuthFinish: 0.039999999105930328, - azimuthStart: 0, - dimensions: { - x: 0.49194091558456421, - y: 0.49194091558456421, - z: 0.49194091558456421 - }, - emitAcceleration: { - x: 0, - y: 0, - z: 0 - }, - emitOrientation: { - w: 1, - x: -1.52587890625e-05, - y: -1.52587890625e-05, - z: -1.52587890625e-05 - }, - emitRate: 770, - emitSpeed: 0.014000000432133675, - isEmitting: false, - lifespan: 0.37000000476837158, - maxParticles: 820, - name: 'lighter_particle', - particleRadius: 0.0027000000700354576, - position: { - x: -0.00044769048690795898, - y: 0.016354814171791077, - z: 0.19217036664485931 - }, - radiusFinish: 0.0027000000700354576, - radiusSpread: 3, - radiusStart: 0.0027000000700354576, - rotation: { - w: 1, - x: -0.0001678466796875, - y: -1.52587890625e-05, - z: -1.52587890625e-05 - }, - speedSpread: 0.56999999284744263, - textures: 'atp:/textures/fire3.png', - type: 'ParticleEffect', - - - "color": { - "red": 255, - "green": 255, - "blue": 255 - }, - "isEmitting": 0, - "maxParticles": 820, - "lifespan": 0.28, - "emitRate": 1100, - "emitSpeed": 0.007, - "speedSpread": 0.5699999928474426, - "emitOrientation": { - "x": -0.0000152587890625, - "y": -0.0000152587890625, - "z": -0.0000152587890625, - "w": 1 - }, - "emitDimensions": { - "x": 0, - "y": 0, - "z": 0 - }, - "polarStart": 0, - "polarFinish": 0, - "azimuthStart": 0, - "azimuthFinish": 0.03999999910593033, - "emitAcceleration": { - "x": 0, - "y": 0, - "z": 0 - }, - "accelerationSpread": { - "x": 0, - "y": 0, - "z": 0 - }, - "particleRadius": 0.0037, - "radiusSpread": 3, - "radiusStart": 0.008, - "radiusFinish": 0.0004, - "colorSpread": { - "red": 0, - "green": 0, - "blue": 0 - }, - "colorStart": { - "red": 255, - "green": 255, - "blue": 255 - }, - "colorFinish": { - "red": 255, - "green": 255, - "blue": 255 - }, - "alpha": 0.03999999910593033, - "alphaSpread": 0, - "alphaStart": 0.141, - "alphaFinish": 0.02, - "emitterShouldTrail": 0, - "textures": "atp:/textures/fire3.png" - }; - return createEntity(entityProperties, butaneLighter); -} - -doCreateButaneLighter = function(transform) { - var butaneLighter = createButaneLighter(transform); - createFireParticle(butaneLighter); - return butaneLighter; -} diff --git a/tutorial/ownershipToken.js b/tutorial/ownershipToken.js deleted file mode 100644 index 4a970af66d..0000000000 --- a/tutorial/ownershipToken.js +++ /dev/null @@ -1,188 +0,0 @@ -if (!Function.prototype.bind) { - Function.prototype.bind = function(oThis) { - if (typeof this !== 'function') { - // closest thing possible to the ECMAScript 5 - // internal IsCallable function - throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable'); - } - - var aArgs = Array.prototype.slice.call(arguments, 1), - fToBind = this, - fNOP = function() {}, - fBound = function() { - return fToBind.apply(this instanceof fNOP - ? this - : oThis, - aArgs.concat(Array.prototype.slice.call(arguments))); - }; - - if (this.prototype) { - // Function.prototype doesn't have a prototype property - fNOP.prototype = this.prototype; - } - fBound.prototype = new fNOP(); - - return fBound; - }; -} - -function getOption(options, key, defaultValue) { - if (options.hasOwnProperty(key)) { - return options[key]; - } - return defaultValue; -} - -var TOKEN_NAME_PREFIX = "ownership_token-"; - -function getOwnershipTokenID(parentEntityID) { - var childEntityIDs = Entities.getChildrenIDs(parentEntityID); - var ownerID = null; - var ownerName = ''; - for (var i = 0; i < childEntityIDs.length; ++i) { - var childID = childEntityIDs[i]; - var properties = Entities.getEntityProperties(childID, ['name', 'userData', 'lifetime', 'age']); - var childName = properties.name; - if (childName.indexOf(TOKEN_NAME_PREFIX) == 0) { - if (ownerID === null || childName < ownerName) { - ownerID = childID; - ownerName = childName; - } - } - } - return ownerID; -} - -function createOwnershipToken(name, parentEntityID) { - return Entities.addEntity({ - type: "Box", - name: TOKEN_NAME_PREFIX + name, - visible: false, - parentID: parentEntityID, - locationPosition: { x: 0, y: 0, z: 0 }, - dimensions: { x: 100, y: 100, z: 100 }, - collisionless: true, - lifetime: 5 - }); -} - -var DEBUG = true; -function debug() { - if (DEBUG) { - var args = Array.prototype.slice.call(arguments); - print.apply(this, args); - } -} - -var TOKEN_STATE_DESTROYED = -1; -var TOKEN_STATE_UNOWNED = 0; -var TOKEN_STATE_REQUESTING_OWNERSHIP = 1; -var TOKEN_STATE_OWNED = 2; - -OwnershipToken = function(name, parentEntityID, options) { - this.name = MyAvatar.sessionUUID + "-" + Math.floor(Math.random() * 10000000); - this.parentEntityID = parentEntityID; - - // How often to check whether the token is available if we don't currently own it - this.checkEverySeconds = getOption(options, 'checkEverySeconds', 1000); - this.updateTokenLifetimeEvery = getOption(options, 'updateTokenLifetimeEvery', 2000); - - this.onGainedOwnership = getOption(options, 'onGainedOwnership', function() { }); - this.onLostOwnership = getOption(options, 'onLostOwnership', function() { }); - - this.ownershipTokenID = null; - this.setState(TOKEN_STATE_UNOWNED); -}; - -OwnershipToken.prototype = { - destroy: function() { - debug(this.name, "Destroying token"); - this.setState(TOKEN_STATE_DESTROYED); - }, - - setState: function(newState) { - if (this.state == newState) { - debug(this.name, "Warning: Trying to set state to the current state"); - return; - } - - if (this.updateLifetimeID) { - debug(this.name, "Clearing update lifetime interval"); - Script.clearInterval(this.updateLifetimeID); - this.updateLifetimeID = null; - } - - if (this.checkOwnershipAvailableID) { - Script.clearInterval(this.checkOwnershipAvailableID); - this.checkOwnershipAvailableID = null; - } - - if (this.state == TOKEN_STATE_OWNED) { - this.onLostOwnership(this); - } - - if (newState == TOKEN_STATE_UNOWNED) { - this.checkOwnershipAvailableID = Script.setInterval( - this.tryRequestingOwnership.bind(this), this.checkEverySeconds); - - } else if (newState == TOKEN_STATE_REQUESTING_OWNERSHIP) { - - } else if (newState == TOKEN_STATE_OWNED) { - this.onGainedOwnership(this); - this.updateLifetimeID = Script.setInterval( - this.updateTokenLifetime.bind(this), this.updateTokenLifetimeEvery); - } else if (newState == TOKEN_STATE_DESTROYED) { - Entities.deleteEntity(this.ownershipTokenID); - } - - debug(this.name, "Info: Switching to state:", newState); - this.state = newState; - }, - updateTokenLifetime: function() { - if (this.state != TOKEN_STATE_OWNED) { - debug(this.name, "Error: Trying to update token while it is unowned"); - return; - } - - debug(this.name, "Updating entity lifetime"); - var age = Entities.getEntityProperties(this.ownershipTokenID, 'age').age; - Entities.editEntity(this.ownershipTokenID, { - lifetime: age + 5 - }); - }, - tryRequestingOwnership: function() { - if (this.state == TOKEN_STATE_REQUESTING_OWNERSHIP || this.state == TOKEN_STATE_OWNED) { - debug(this.name, "We already have or are requesting ownership"); - return; - } - - var ownerID = getOwnershipTokenID(this.parentEntityID); - if (ownerID !== null) { - // Already owned, return - debug(this.name, "Token already owned by another client, returning. Owner: " + owenerID + ", Us: " + this.name); - return; - } - - this.ownershipTokenID = createOwnershipToken(this.name, this.parentEntityID); - this.setState(TOKEN_STATE_REQUESTING_OWNERSHIP); - - function checkOwnershipRequest() { - var ownerID = getOwnershipTokenID(this.parentEntityID); - if (ownerID == this.ownershipTokenID) { - debug(this.name, "Info: Obtained ownership"); - this.setState(TOKEN_STATE_OWNED); - } else { - if (ownerID === null) { - debug(this.name, "Warning: Checked ownership request and no tokens existed"); - } - debug(this.name, "Info: Lost ownership request") - this.ownershipTokenID = null; - this.setState(TOKEN_STATE_UNOWNED); - } - } - - Script.setTimeout(checkOwnershipRequest.bind(this), 2000); - }, -}; - -debug("Returning from ownershipToken"); diff --git a/tutorial/spinner.js b/tutorial/spinner.js deleted file mode 100644 index 2edbb43700..0000000000 --- a/tutorial/spinner.js +++ /dev/null @@ -1,84 +0,0 @@ -// -// spinner.js -// -// Created by Ryan Huffman on 9/1/16. -// Copyright 2016 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -(function() { - var DEBUG = true; - function debug() { - if (DEBUG) { - print.apply(this, arguments); - } - } - - var spinnerSound = SoundCache.getSound("atp:/tutorial_sounds/Pinwheel.L.wav"); - var Spinner = function() { - }; - function getChildProperties(entityID, propertyNames) { - var childEntityIDs = Entities.getChildrenIDs(entityID); - var results = {} - for (var i = 0; i < childEntityIDs.length; ++i) { - var childEntityID = childEntityIDs[i]; - var properties = Entities.getEntityProperties(childEntityID, propertyNames); - results[childEntityID] = properties; - } - return results; - } - Spinner.prototype = { - onLit: function() { - debug("spinner.js | Spinner lit"); - Entities.editEntity(this.entityID, { - "angularDamping": 0.1, - "angularVelocity": { - "x": 20.471975326538086, - "y": 0, - "z": 0 - }, - }); - var injector = Audio.playSound(spinnerSound, { - position: Entities.getEntityProperties(this.entityID, 'position').position, - volume: 1.0, - loop: false - }); - - var childrenProps = getChildProperties(this.entityID, ['type']); - for (var childEntityID in childrenProps) { - var props = childrenProps[childEntityID]; - if (props.type == "ParticleEffect") { - debug("spinner.js | Modifying: ", childEntityID); - Entities.editEntity(childEntityID, { - emitRate: 35, - }); - } - } - Messages.sendLocalMessage("Tutorial-Spinner", "wasLit"); - - var self = this; - Script.setTimeout(function() { - debug("spinner.js | Finishing spinner"); - injector.stop(); - - var childrenProps = getChildProperties(self.entityID, ['type']); - for (var childEntityID in childrenProps) { - var props = childrenProps[childEntityID]; - if (props.type == "ParticleEffect") { - debug("spinner.js | Modifying: ", childEntityID); - Entities.editEntity(childEntityID, { - emitRate: 0, - }); - } - } - }, 4900); - }, - preload: function(entityID) { - debug("spinner.js | Preload"); - this.entityID = entityID; - }, - }; - return new Spinner(); -}); diff --git a/tutorial/success.wav b/tutorial/success.wav deleted file mode 100644 index 597e2b91b6..0000000000 Binary files a/tutorial/success.wav and /dev/null differ diff --git a/tutorial/success48.wav b/tutorial/success48.wav deleted file mode 100644 index 802d0a777f..0000000000 Binary files a/tutorial/success48.wav and /dev/null differ diff --git a/tutorial/tutorial.js b/tutorial/tutorial.js deleted file mode 100644 index 97528b9b3b..0000000000 --- a/tutorial/tutorial.js +++ /dev/null @@ -1,1202 +0,0 @@ -// -// tutorial.js -// -// Created by Ryan Huffman on 9/1/16. -// Copyright 2016 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -Script.include("entityData.js"); -Script.include("lighter/createButaneLighter.js"); -Script.include("tutorialEntityIDs.js"); - -if (!Function.prototype.bind) { - Function.prototype.bind = function(oThis) { - if (typeof this !== 'function') { - // closest thing possible to the ECMAScript 5 - // internal IsCallable function - throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable'); - } - - var aArgs = Array.prototype.slice.call(arguments, 1), - fToBind = this, - fNOP = function() {}, - fBound = function() { - return fToBind.apply(this instanceof fNOP - ? this - : oThis, - aArgs.concat(Array.prototype.slice.call(arguments))); - }; - - if (this.prototype) { - // Function.prototype doesn't have a prototype property - fNOP.prototype = this.prototype; - } - fBound.prototype = new fNOP(); - - return fBound; - }; -} - -var DEBUG = true; -function debug() { - if (DEBUG) { - var args = Array.prototype.slice.call(arguments); - args.unshift("tutorial.js | "); - print.apply(this, args); - } -} - -var INFO = true; -function info() { - if (INFO) { - var args = Array.prototype.slice.call(arguments); - args.unshift("tutorial.js | "); - print.apply(this, args); - } -} - -const CONTROLLER_TOUCH = 'touch'; -const CONTROLLER_VIVE = 'vive'; - -var NEAR_BOX_SPAWN_NAME = "tutorial/nearGrab/box_spawn"; -var FAR_BOX_SPAWN_NAME = "tutorial/farGrab/box_spawn"; -var GUN_SPAWN_NAME = "tutorial/gun_spawn"; -var TELEPORT_PAD_NAME = "tutorial/teleport/pad" - -var successSound = SoundCache.getSound("atp:/tutorial_sounds/good_one.L.wav"); -var firecrackerSound = SoundCache.getSound("atp:/tutorial_sounds/Pops_Firecracker.wav"); - - -var CHANNEL_AWAY_ENABLE = "Hifi-Away-Enable"; -function setAwayEnabled(value) { - var message = value ? 'enable' : 'disable'; - Messages.sendLocalMessage(CHANNEL_AWAY_ENABLE, message); -} - -findEntity = function(properties, searchRadius, filterFn) { - var entities = findEntities(properties, searchRadius, filterFn); - return entities.length > 0 ? entities[0] : null; -} - -// Return all entities with properties `properties` within radius `searchRadius` -findEntities = function(properties, searchRadius, filterFn) { - if (!filterFn) { - filterFn = function(properties, key, value) { - return value == properties[key]; - } - } - searchRadius = searchRadius ? searchRadius : 100000; - var entities = Entities.findEntities({ x: 0, y: 0, z: 0 }, searchRadius); - var matchedEntities = []; - var keys = Object.keys(properties); - for (var i = 0; i < entities.length; ++i) { - var match = true; - var candidateProperties = Entities.getEntityProperties(entities[i], keys); - for (var key in properties) { - if (!filterFn(properties, key, candidateProperties[key])) { - // This isn't a match, move to next entity - match = false; - break; - } - } - if (match) { - matchedEntities.push(entities[i]); - } - } - - return matchedEntities; -} - -function findEntitiesWithTag(tag) { - return findEntities({ userData: "" }, 10000, function(properties, key, value) { - data = parseJSON(value); - return data.tag === tag; - }); -} - -/** - * A controller is made up of parts, and each part can have multiple "layers," - * which are really just different texures. For example, the "trigger" part - * has "normal" and "highlight" layers. - */ -function setControllerPartLayer(part, layer) { - data = {}; - data[part] = layer; - Messages.sendLocalMessage('Controller-Set-Part-Layer', JSON.stringify(data)); -} - -/** - * Spawn entities and return the newly created entity's ids. - * @param {object[]} entityPropertiesList A list of properties of the entities - * to spawn. - */ -function spawn(entityPropertiesList, transform, modifyFn) { - if (!transform) { - transform = { - position: { x: 0, y: 0, z: 0 }, - rotation: { x: 0, y: 0, z: 0, w: 1 } - } - } - var ids = []; - for (var i = 0; i < entityPropertiesList.length; ++i) { - var data = entityPropertiesList[i]; - data.position = Vec3.sum(transform.position, data.position); - data.rotation = Quat.multiply(data.rotation, transform.rotation); - if (modifyFn) { - data = modifyFn(data); - } - var id = Entities.addEntity(data); - ids.push(id); - } - return ids; -} - -/** - * @function parseJSON - * @param {string} jsonString The string to parse. - * @return {object} Return an empty if the string was not valid JSON, otherwise - * the parsed object is returned. - */ -function parseJSON(jsonString) { - var data; - try { - data = JSON.parse(jsonString); - } catch(e) { - data = {}; - } - return data; -} - -/** - * Spawn entities with `tag` in the userData. - * @function spawnWithTag - */ -function spawnWithTag(entityData, transform, tag) { - function modifyFn(data) { - var userData = parseJSON(data.userData); - userData.tag = tag; - data.userData = JSON.stringify(userData); - debug("In modify", tag, userData, data.userData); - return data; - } - return spawn(entityData, transform, modifyFn); -} - -/** - * Delete all entities with the tag `tag` in their userData. - * @function deleteEntitiesWithTag - */ -function deleteEntitiesWithTag(tag) { - debug("searching for...:", tag); - var entityIDs = findEntitiesWithTag(tag); - for (var i = 0; i < entityIDs.length; ++i) { - Entities.deleteEntity(entityIDs[i]); - } -} - -function editEntitiesWithTag(tag, propertiesOrFn) { - var entities = TUTORIAL_TAG_TO_ENTITY_IDS_MAP[tag]; - - debug("Editing tag: ", tag); - if (entities) { - for (entityID in entities) { - debug("Editing: ", entityID, ", ", propertiesOrFn, ", Is in local tree: ", isEntityInLocalTree(entityID)); - if (isFunction(propertiesOrFn)) { - Entities.editEntity(entityID, propertiesOrFn(entityIDs[i])); - } else { - Entities.editEntity(entityID, propertiesOrFn); - } - } - } -} - -// From http://stackoverflow.com/questions/5999998/how-can-i-check-if-a-javascript-variable-is-function-type -function isFunction(functionToCheck) { - var getType = {}; - return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]'; -} - -/** - * Return `true` if `entityID` can be found in the local entity tree, otherwise `false`. - */ -function isEntityInLocalTree(entityID) { - return Entities.getEntityProperties(entityID, 'visible').visible !== undefined; -} - -/** - * - */ -function showEntitiesWithTags(tags) { - for (var i = 0; i < tags.length; ++i) { - showEntitiesWithTag(tags[i]); - } -} - -function showEntitiesWithTag(tag) { - var entities = TUTORIAL_TAG_TO_ENTITY_IDS_MAP[tag]; - if (entities) { - for (entityID in entities) { - var data = entities[entityID]; - - var collisionless = data.visible === false ? true : false; - if (data.collidable !== undefined) { - collisionless = data.collidable === true ? false : true; - } - if (data.soundKey) { - data.soundKey.playing = true; - } - var newProperties = { - visible: data.visible == false ? false : true, - collisionless: collisionless, - userData: JSON.stringify(data), - }; - debug("Showing: ", entityID, ", Is in local tree: ", isEntityInLocalTree(entityID)); - Entities.editEntity(entityID, newProperties); - } - } else { - debug("ERROR | No entities for tag: ", tag); - } - - return; - // Dynamic method, suppressed for now - //editEntitiesWithTag(tag, function(entityID) { - // var userData = Entities.getEntityProperties(entityID, "userData").userData; - // var data = parseJSON(userData); - // var collisionless = data.visible === false ? true : false; - // if (data.collidable !== undefined) { - // collisionless = data.collidable === true ? false : true; - // } - // if (data.soundKey) { - // data.soundKey.playing = true; - // } - // var newProperties = { - // visible: data.visible == false ? false : true, - // collisionless: collisionless, - // userData: JSON.stringify(data), - // }; - // Entities.editEntity(entityID, newProperties); - //}); -} - -function hideEntitiesWithTags(tags) { - for (var i = 0; i < tags.length; ++i) { - hideEntitiesWithTag(tags[i]); - } -} - -function hideEntitiesWithTag(tag) { - var entities = TUTORIAL_TAG_TO_ENTITY_IDS_MAP[tag]; - if (entities) { - for (entityID in entities) { - var data = entities[entityID]; - - if (data.soundKey) { - data.soundKey.playing = false; - } - var newProperties = { - visible: false, - collisionless: 1, - ignoreForCollisions: 1, - userData: JSON.stringify(data), - }; - - debug("Hiding: ", entityID, ", Is in local tree: ", isEntityInLocalTree(entityID)); - Entities.editEntity(entityID, newProperties); - } - } - - return; - // Dynamic method, suppressed for now - //editEntitiesWithTag(tag, function(entityID) { - // var userData = Entities.getEntityProperties(entityID, "userData").userData; - // var data = parseJSON(userData); - // if (data.soundKey) { - // data.soundKey.playing = false; - // } - // var newProperties = { - // visible: false, - // collisionless: 1, - // ignoreForCollisions: 1, - // userData: JSON.stringify(data), - // }; - // Entities.editEntity(entityID, newProperties); - //}); -} - -/** - * Return the entity properties for an entity with a given name if it is in our - * cached list of entities. Otherwise, return undefined. - */ -function getEntityWithName(name) { - debug("Getting entity with name:", name); - var entityID = TUTORIAL_NAME_TO_ENTITY_PROPERTIES_MAP[name]; - debug("Entity id: ", entityID, ", Is in local tree: ", isEntityInLocalTree(entityID)); - return entityID; -} - -function playSuccessSound() { - Audio.playSound(successSound, { - position: MyAvatar.position, - volume: 0.7, - loop: false - }); -} - -function playFirecrackerSound(position) { - Audio.playSound(firecrackerSound, { - position: position, - volume: 0.5, - loop: false - }); -} - -/** - * This disables everything, including: - * - * - The door to leave the tutorial - * - Overlays - * - Hand controlelrs - * - Teleportation - * - Advanced movement - * - Equip and far grab - * - Away mode - */ -function disableEverything() { - editEntitiesWithTag('door', { visible: true, collisionless: false }); - Menu.setIsOptionChecked("Overlays", false); - Controller.disableMapping('handControllerPointer-click'); - Messages.sendLocalMessage('Hifi-Advanced-Movement-Disabler', 'disable'); - Messages.sendLocalMessage('Hifi-Teleport-Disabler', 'both'); - Messages.sendLocalMessage('Hifi-Grab-Disable', JSON.stringify({ - nearGrabEnabled: true, - holdEnabled: false, - farGrabEnabled: false, - myAvatarScalingEnabled: false, - objectScalingEnabled: false, - })); - setControllerPartLayer('touchpad', 'blank'); - setControllerPartLayer('trigger', 'blank'); - setControllerPartLayer('joystick', 'blank'); - setControllerPartLayer('grip', 'blank'); - setControllerPartLayer('button_a', 'blank'); - setControllerPartLayer('button_b', 'blank'); - setControllerPartLayer('tips', 'blank'); - - hideEntitiesWithTag('finish'); - - setAwayEnabled(false); -} - -/** - * This reenables everything that disableEverything() disables. This can be - * used when leaving the tutorial to ensure that nothing is left disabled. - */ -function reenableEverything() { - editEntitiesWithTag('door', { visible: false, collisionless: true }); - Menu.setIsOptionChecked("Overlays", true); - Controller.enableMapping('handControllerPointer-click'); - Messages.sendLocalMessage('Hifi-Advanced-Movement-Disabler', 'enable'); - Messages.sendLocalMessage('Hifi-Teleport-Disabler', 'none'); - Messages.sendLocalMessage('Hifi-Grab-Disable', JSON.stringify({ - nearGrabEnabled: true, - holdEnabled: true, - farGrabEnabled: true, - myAvatarScalingEnabled: true, - objectScalingEnabled: true, - })); - setControllerPartLayer('touchpad', 'blank'); - setControllerPartLayer('trigger', 'blank'); - setControllerPartLayer('joystick', 'blank'); - setControllerPartLayer('grip', 'blank'); - setControllerPartLayer('button_a', 'blank'); - setControllerPartLayer('button_b', 'blank'); - setControllerPartLayer('tips', 'blank'); - MyAvatar.shouldRenderLocally = true; - setAwayEnabled(true); -} - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -// // -// STEP: DISABLE CONTROLLERS // -// // -/////////////////////////////////////////////////////////////////////////////// -var stepStart = function() { - this.name = 'start'; -}; -stepStart.prototype = { - start: function(onFinish) { - disableEverything(); - - HMD.requestShowHandControllers(); - - onFinish(); - }, - cleanup: function() { - } -}; - - - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -// // -// STEP: ENABLE CONTROLLERS // -// // -/////////////////////////////////////////////////////////////////////////////// - -var stepEnableControllers = function() { - this.shouldLog = false; -}; -stepEnableControllers.prototype = { - start: function(onFinish) { - reenableEverything(); - HMD.requestHideHandControllers(); - onFinish(); - }, - cleanup: function() { - } -}; - - - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -// // -// STEP: Orient and raise hands above head // -// // -/////////////////////////////////////////////////////////////////////////////// -var stepOrient = function(tutorialManager) { - this.name = 'orient'; - this.tags = ["orient", "orient-" + tutorialManager.controllerName]; -} -stepOrient.prototype = { - start: function(onFinish) { - this.active = true; - - var tag = this.tag; - - // Spawn content set - //editEntitiesWithTag(this.tag, { visible: true }); - showEntitiesWithTags(this.tags); - - this.checkIntervalID = null; - function checkForHandsAboveHead() { - debug("Orient | Checking for hands above head"); - if (MyAvatar.getLeftPalmPosition().y > (MyAvatar.getHeadPosition().y + 0.1)) { - Script.clearInterval(this.checkIntervalID); - this.checkIntervalID = null; - location = "/tutorial"; - Script.setTimeout(playSuccessSound, 150); - this.active = false; - onFinish(); - } - } - this.checkIntervalID = Script.setInterval(checkForHandsAboveHead.bind(this), 500); - }, - cleanup: function() { - debug("Orient | Cleanup"); - if (this.active) { - this.active = false; - } - if (this.overlay) { - this.overlay.destroy(); - this.overlay = null; - } - if (this.checkIntervalID) { - Script.clearInterval(this.checkIntervalID); - this.checkIntervalID = null; - } - //editEntitiesWithTag(this.tag, { visible: false, collisionless: 1 }); - hideEntitiesWithTags(this.tags); - } -}; - - - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -// // -// STEP: Near Grab // -// // -/////////////////////////////////////////////////////////////////////////////// -var stepNearGrab = function(tutorialManager) { - this.name = 'nearGrab'; - this.tags = ["bothGrab", "nearGrab", "nearGrab-" + tutorialManager.controllerName]; - this.tempTag = "nearGrab-temporary"; - this.birdIDs = []; - - this.controllerName = tutorialManager.controllerName; - - Messages.subscribe("Entity-Exploded"); - Messages.messageReceived.connect(this.onMessage.bind(this)); -} -stepNearGrab.prototype = { - start: function(onFinish) { - this.finished = false; - this.onFinish = onFinish; - - if (this.controllerName === CONTROLLER_TOUCH) { - setControllerPartLayer('tips', 'both_triggers'); - setControllerPartLayer('trigger', 'highlight'); - setControllerPartLayer('grip', 'highlight'); - } else { - setControllerPartLayer('tips', 'trigger'); - setControllerPartLayer('trigger', 'highlight'); - } - - // Show content set - showEntitiesWithTags(this.tags); - - var boxSpawnPosition = getEntityWithName(NEAR_BOX_SPAWN_NAME).position; - function createBlock(fireworkNumber) { - fireworkBaseProps.position = boxSpawnPosition; - fireworkBaseProps.modelURL = fireworkURLs[fireworkNumber % fireworkURLs.length]; - debug("Creating firework with url: ", fireworkBaseProps.modelURL); - return spawnWithTag([fireworkBaseProps], null, this.tempTag)[0]; - } - - this.birdIDs = []; - this.birdIDs.push(createBlock.bind(this)(0)); - this.birdIDs.push(createBlock.bind(this)(1)); - this.birdIDs.push(createBlock.bind(this)(2)); - this.positionWatcher = new PositionWatcher(this.birdIDs, boxSpawnPosition, -0.4, 4); - }, - onMessage: function(channel, message, seneder) { - if (this.finished) { - return; - } - if (channel == "Entity-Exploded") { - debug("NearGrab | Got entity-exploded message: ", message); - - var data = parseJSON(message); - if (this.birdIDs.indexOf(data.entityID) >= 0) { - debug("NearGrab | It's one of the firecrackers"); - playFirecrackerSound(data.position); - playSuccessSound(); - this.finished = true; - this.onFinish(); - } - } - }, - cleanup: function() { - debug("NearGrab | Cleanup"); - this.finished = true; - setControllerPartLayer('tips', 'blank'); - setControllerPartLayer('trigger', 'normal'); - setControllerPartLayer('grip', 'normal'); - hideEntitiesWithTags(this.tags); - deleteEntitiesWithTag(this.tempTag); - if (this.positionWatcher) { - this.positionWatcher.destroy(); - this.positionWatcher = null; - } - } -}; - - - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -// // -// STEP: Far Grab // -// // -/////////////////////////////////////////////////////////////////////////////// -var stepFarGrab = function() { - this.name = 'farGrab'; - this.tag = "farGrab"; - this.tempTag = "farGrab-temporary"; - this.finished = true; - this.birdIDs = []; - - Messages.subscribe("Entity-Exploded"); - Messages.messageReceived.connect(this.onMessage.bind(this)); -} -stepFarGrab.prototype = { - start: function(onFinish) { - this.finished = false; - this.onFinish = onFinish; - - showEntitiesWithTag('bothGrab', { visible: true }); - - setControllerPartLayer('tips', 'trigger'); - setControllerPartLayer('trigger', 'highlight'); - Messages.sendLocalMessage('Hifi-Grab-Disable', JSON.stringify({ - farGrabEnabled: true, - })); - var tag = this.tag; - - // Spawn content set - showEntitiesWithTag(this.tag); - - var boxSpawnPosition = getEntityWithName(FAR_BOX_SPAWN_NAME).position; - function createBlock(fireworkNumber) { - fireworkBaseProps.position = boxSpawnPosition; - fireworkBaseProps.modelURL = fireworkURLs[fireworkNumber % fireworkURLs.length]; - debug("Creating firework with url: ", fireworkBaseProps.modelURL); - return spawnWithTag([fireworkBaseProps], null, this.tempTag)[0]; - } - - this.birdIDs = []; - this.birdIDs.push(createBlock.bind(this)(3)); - this.birdIDs.push(createBlock.bind(this)(4)); - this.birdIDs.push(createBlock.bind(this)(5)); - this.positionWatcher = new PositionWatcher(this.birdIDs, boxSpawnPosition, -0.4, 4); - }, - onMessage: function(channel, message, seneder) { - if (this.finished) { - return; - } - if (channel == "Entity-Exploded") { - debug("FarGrab | Got entity-exploded message: ", message); - var data = parseJSON(message); - if (this.birdIDs.indexOf(data.entityID) >= 0) { - debug("FarGrab | It's one of the firecrackers"); - playFirecrackerSound(data.position); - playSuccessSound(); - this.finished = true; - this.onFinish(); - } - } - }, - cleanup: function() { - debug("FarGrab | Cleanup"); - this.finished = true; - setControllerPartLayer('tips', 'blank'); - setControllerPartLayer('trigger', 'normal'); - hideEntitiesWithTag(this.tag, { visible: false}); - deleteEntitiesWithTag(this.tempTag); - if (this.positionWatcher) { - this.positionWatcher.destroy(); - this.positionWatcher = null; - } - } -}; - -function PositionWatcher(entityIDs, originalPosition, minY, maxDistance) { - debug("Creating position watcher"); - this.watcherIntervalID = Script.setInterval(function() { - for (var i = 0; i < entityIDs.length; ++i) { - var entityID = entityIDs[i]; - var props = Entities.getEntityProperties(entityID, ['position']); - if (props.position.y < minY || Vec3.distance(originalPosition, props.position) > maxDistance) { - Entities.editEntity(entityID, { - position: originalPosition, - velocity: { x: 0, y: -0.01, z: 0 }, - angularVelocity: { x: 0, y: 0, z: 0 } - }); - } - } - }, 1000); -} - -PositionWatcher.prototype = { - destroy: function() { - debug("Destroying position watcher"); - Script.clearInterval(this.watcherIntervalID); - } -}; - - - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -// // -// STEP: Equip // -// // -/////////////////////////////////////////////////////////////////////////////// -var stepEquip = function(tutorialManager) { - const controllerName = tutorialManager.controllerName; - this.controllerName = controllerName; - - this.name = 'equip'; - - this.tags = ["equip", "equip-" + controllerName]; - this.tagsPart1 = ["equip-part1", "equip-part1-" + controllerName]; - this.tagsPart2 = ["equip-part2", "equip-part2-" + controllerName]; - this.tempTag = "equip-temporary"; - - this.PART1 = 0; - this.PART2 = 1; - this.PART3 = 2; - this.COMPLETE = 3; - - Messages.subscribe('Tutorial-Spinner'); - Messages.messageReceived.connect(this.onMessage.bind(this)); -} -stepEquip.prototype = { - start: function(onFinish) { - if (this.controllerName === CONTROLLER_TOUCH) { - setControllerPartLayer('tips', 'grip'); - setControllerPartLayer('grip', 'highlight'); - } else { - setControllerPartLayer('tips', 'trigger'); - setControllerPartLayer('trigger', 'highlight'); - } - - Messages.sendLocalMessage('Hifi-Grab-Disable', JSON.stringify({ - holdEnabled: true, - })); - - var tag = this.tag; - - // Spawn content set - showEntitiesWithTags(this.tags); - showEntitiesWithTags(this.tagsPart1); - - this.currentPart = this.PART1; - - function createLighter() { - var transform = {}; - - var boxSpawnProps = getEntityWithName(GUN_SPAWN_NAME); - transform.position = boxSpawnProps.position; - transform.rotation = boxSpawnProps.rotation; - transform.velocity = { x: 0, y: -0.01, z: 0 }; - transform.angularVelocity = { x: 0, y: 0, z: 0 }; - this.spawnTransform = transform; - return doCreateButaneLighter(transform).id; - } - - - this.lighterID = createLighter.bind(this)(); - this.startWatchingLighter(); - debug("Created lighter", this.lighterID); - this.onFinish = onFinish; - }, - startWatchingLighter: function() { - if (!this.watcherIntervalID) { - debug("Starting to watch lighter position"); - this.watcherIntervalID = Script.setInterval(function() { - debug("Checking lighter position"); - var props = Entities.getEntityProperties(this.lighterID, ['position']); - if (props.position.y < -0.4 - || Vec3.distance(this.spawnTransform.position, props.position) > 4) { - debug("Moving lighter back to table"); - Entities.editEntity(this.lighterID, this.spawnTransform); - } - }.bind(this), 1000); - } - }, - stopWatchingGun: function() { - if (this.watcherIntervalID) { - debug("Stopping watch of lighter position"); - Script.clearInterval(this.watcherIntervalID); - this.watcherIntervalID = null; - } - }, - onMessage: function(channel, message, sender) { - if (this.currentPart == this.COMPLETE) { - return; - } - - debug("Equip | Got message", channel, message, sender, MyAvatar.sessionUUID); - - if (channel == "Tutorial-Spinner") { - if (this.currentPart == this.PART1 && message == "wasLit") { - this.currentPart = this.PART2; - debug("Equip | Starting part 2"); - Script.setTimeout(function() { - debug("Equip | Starting part 3"); - this.currentPart = this.PART3; - hideEntitiesWithTags(this.tagsPart1); - showEntitiesWithTags(this.tagsPart2); - setControllerPartLayer('trigger', 'normal'); - setControllerPartLayer('grip', 'highlight'); - setControllerPartLayer('tips', 'grip'); - Messages.subscribe('Hifi-Object-Manipulation'); - debug("Equip | Finished starting part 3"); - }.bind(this), 9000); - } - } else if (channel == "Hifi-Object-Manipulation") { - if (this.currentPart == this.PART3) { - var data = parseJSON(message); - if (data.action == 'release' && data.grabbedEntity == this.lighterID) { - debug("Equip | Got release, finishing step"); - this.stopWatchingGun(); - this.currentPart = this.COMPLETE; - playSuccessSound(); - Script.setTimeout(this.onFinish.bind(this), 1500); - } - } - } - }, - cleanup: function() { - debug("Equip | Got yaw action"); - if (this.watcherIntervalID) { - Script.clearInterval(this.watcherIntervalID); - this.watcherIntervalID = null; - } - - setControllerPartLayer('tips', 'blank'); - setControllerPartLayer('grip', 'normal'); - setControllerPartLayer('trigger', 'normal'); - this.stopWatchingGun(); - this.currentPart = this.COMPLETE; - - if (this.checkCollidesTimer) { - Script.clearInterval(this.checkCollidesTimer); - this.checkColllidesTimer = null; - } - - hideEntitiesWithTags(this.tagsPart1); - hideEntitiesWithTags(this.tagsPart2); - hideEntitiesWithTags(this.tags); - deleteEntitiesWithTag(this.tempTag); - } -}; - - - - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -// // -// STEP: Turn Around // -// // -/////////////////////////////////////////////////////////////////////////////// -var stepTurnAround = function(tutorialManager) { - this.name = 'turnAround'; - - this.tags = ["turnAround", "turnAround-" + tutorialManager.controllerName]; - this.tempTag = "turnAround-temporary"; - - this.onActionBound = this.onAction.bind(this); - this.numTimesSnapTurnPressed = 0; - this.numTimesSmoothTurnPressed = 0; -} -stepTurnAround.prototype = { - start: function(onFinish) { - setControllerPartLayer('joystick', 'highlight'); - setControllerPartLayer('touchpad', 'arrows'); - setControllerPartLayer('tips', 'arrows'); - - showEntitiesWithTags(this.tags); - - this.numTimesSnapTurnPressed = 0; - this.numTimesSmoothTurnPressed = 0; - this.smoothTurnDown = false; - Controller.actionEvent.connect(this.onActionBound); - - this.interval = Script.setInterval(function() { - debug("TurnAround | Checking if finished", - this.numTimesSnapTurnPressed, this.numTimesSmoothTurnPressed); - var FORWARD_THRESHOLD = 90; - var REQ_NUM_TIMES_SNAP_TURN_PRESSED = 3; - var REQ_NUM_TIMES_SMOOTH_TURN_PRESSED = 2; - - var dir = Quat.getFront(MyAvatar.orientation); - var angle = Math.atan2(dir.z, dir.x); - var angleDegrees = ((angle / Math.PI) * 180); - - var hasTurnedEnough = this.numTimesSnapTurnPressed >= REQ_NUM_TIMES_SNAP_TURN_PRESSED - || this.numTimesSmoothTurnPressed >= REQ_NUM_TIMES_SMOOTH_TURN_PRESSED; - var facingForward = Math.abs(angleDegrees) < FORWARD_THRESHOLD - if (hasTurnedEnough && facingForward) { - Script.clearInterval(this.interval); - this.interval = null; - playSuccessSound(); - onFinish(); - } - }.bind(this), 100); - }, - onAction: function(action, value) { - var STEP_YAW_ACTION = 6; - var SMOOTH_YAW_ACTION = 4; - - if (action == STEP_YAW_ACTION && value != 0) { - debug("TurnAround | Got step yaw action"); - ++this.numTimesSnapTurnPressed; - } else if (action == SMOOTH_YAW_ACTION) { - debug("TurnAround | Got smooth yaw action"); - if (this.smoothTurnDown && value === 0) { - this.smoothTurnDown = false; - ++this.numTimesSmoothTurnPressed; - } else if (!this.smoothTurnDown && value !== 0) { - this.smoothTurnDown = true; - } - } - }, - cleanup: function() { - debug("TurnAround | Cleanup"); - try { - Controller.actionEvent.disconnect(this.onActionBound); - } catch (e) { - } - - setControllerPartLayer('joystick', 'normal'); - setControllerPartLayer('touchpad', 'blank'); - setControllerPartLayer('tips', 'blank'); - - if (this.interval) { - Script.clearInterval(this.interval); - } - hideEntitiesWithTags(this.tags); - deleteEntitiesWithTag(this.tempTag); - } -}; - - - - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -// // -// STEP: Teleport // -// // -/////////////////////////////////////////////////////////////////////////////// -var stepTeleport = function(tutorialManager) { - this.name = 'teleport'; - - this.tags = ["teleport", "teleport-" + tutorialManager.controllerName]; - this.tempTag = "teleport-temporary"; -} -stepTeleport.prototype = { - start: function(onFinish) { - setControllerPartLayer('button_a', 'highlight'); - setControllerPartLayer('touchpad', 'teleport'); - setControllerPartLayer('tips', 'teleport'); - - Messages.sendLocalMessage('Hifi-Teleport-Disabler', 'none'); - - // Wait until touching teleport pad... - var padProps = getEntityWithName(TELEPORT_PAD_NAME); - var xMin = padProps.position.x - padProps.dimensions.x / 2; - var xMax = padProps.position.x + padProps.dimensions.x / 2; - var zMin = padProps.position.z - padProps.dimensions.z / 2; - var zMax = padProps.position.z + padProps.dimensions.z / 2; - function checkCollides() { - debug("Teleport | Checking if on pad..."); - - var pos = MyAvatar.position; - - debug('Teleport | x', pos.x, xMin, xMax); - debug('Teleport | z', pos.z, zMin, zMax); - - if (pos.x > xMin && pos.x < xMax && pos.z > zMin && pos.z < zMax) { - debug("Teleport | On teleport pad"); - Script.clearInterval(this.checkCollidesTimer); - this.checkCollidesTimer = null; - playSuccessSound(); - onFinish(); - } - } - this.checkCollidesTimer = Script.setInterval(checkCollides.bind(this), 500); - - showEntitiesWithTags(this.tags); - }, - cleanup: function() { - debug("Teleport | Cleanup"); - setControllerPartLayer('button_a', 'normal'); - setControllerPartLayer('touchpad', 'blank'); - setControllerPartLayer('tips', 'blank'); - - if (this.checkCollidesTimer) { - Script.clearInterval(this.checkCollidesTimer); - } - hideEntitiesWithTags(this.tags); - deleteEntitiesWithTag(this.tempTag); - } -}; - - - - - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -// // -// STEP: Finish // -// // -/////////////////////////////////////////////////////////////////////////////// -var stepFinish = function() { - this.name = 'finish'; - - this.tag = "finish"; - this.tempTag = "finish-temporary"; -} -stepFinish.prototype = { - start: function(onFinish) { - editEntitiesWithTag('door', { visible: false, collisonless: true }); - showEntitiesWithTag(this.tag); - Settings.setValue("tutorialComplete", true); - onFinish(); - }, - cleanup: function() { - } -}; - -var stepCleanupFinish = function() { - this.name = 'cleanup'; - - this.shouldLog = false; -} -stepCleanupFinish.prototype = { - start: function(onFinish) { - hideEntitiesWithTag('finish'); - onFinish(); - }, - cleanup: function() { - } -}; - - - - - -TutorialManager = function() { - var STEPS; - - var currentStepNum = -1; - var currentStep = null; - var startedTutorialAt = 0; - var startedLastStepAt = 0; - var didFinishTutorial = false; - - var wentToEntryStepNum; - var VERSION = 2; - var tutorialID; - - var self = this; - - // The real controller name is the actual detected controller name, or 'unknown' - // if one is not found. - if (HMD.isSubdeviceContainingNameAvailable("OculusTouch")) { - this.controllerName = "touch"; - this.realControllerName = "touch"; - } else if (HMD.isHandControllerAvailable("OpenVR")) { - this.controllerName = "vive"; - this.realControllerName = "vive"; - } else { - info("ERROR, no known hand controller found, defaulting to Vive"); - this.controllerName = "vive"; - this.realControllerName = "unknown"; - } - - this.startTutorial = function() { - currentStepNum = -1; - currentStep = null; - startedTutorialAt = Date.now(); - - // Old versions of interface do not have the Script.generateUUID function. - // If Script.generateUUID is not available, default to an empty string. - tutorialID = Script.generateUUID ? Script.generateUUID() : ""; - STEPS = [ - new stepStart(this), - new stepOrient(this), - new stepFarGrab(this), - new stepNearGrab(this), - new stepEquip(this), - new stepTurnAround(this), - new stepTeleport(this), - new stepFinish(this), - new stepEnableControllers(this), - ]; - wentToEntryStepNum = STEPS.length; - for (var i = 0; i < STEPS.length; ++i) { - STEPS[i].cleanup(); - } - MyAvatar.shouldRenderLocally = false; - this.startNextStep(); - } - - this.onFinish = function() { - debug("onFinish", currentStepNum); - if (currentStep && currentStep.shouldLog !== false) { - self.trackStep(currentStep.name, currentStepNum); - } - - self.startNextStep(); - } - - this.startNextStep = function() { - if (currentStep) { - currentStep.cleanup(); - } - - ++currentStepNum; - - // This always needs to be set because we use this value when - // tracking that the user has gone through the entry portal. When the - // tutorial finishes, there is a last "pseudo" step that the user - // finishes when stepping into the portal. - startedLastStepAt = Date.now(); - - if (currentStepNum >= STEPS.length) { - // Done - info("DONE WITH TUTORIAL"); - currentStepNum = -1; - currentStep = null; - didFinishTutorial = true; - return false; - } else { - info("Starting step", currentStepNum); - currentStep = STEPS[currentStepNum]; - currentStep.start(this.onFinish); - return true; - } - }.bind(this); - - this.restartStep = function() { - if (currentStep) { - currentStep.cleanup(); - currentStep.start(this.onFinish); - } - } - - this.stopTutorial = function() { - if (currentStep) { - currentStep.cleanup(); - HMD.requestHideHandControllers(); - } - reenableEverything(); - currentStepNum = -1; - currentStep = null; - } - - this.trackStep = function(name, stepNum) { - var timeToFinishStep = (Date.now() - startedLastStepAt) / 1000; - var tutorialTimeElapsed = (Date.now() - startedTutorialAt) / 1000; - UserActivityLogger.tutorialProgress( - name, stepNum, timeToFinishStep, tutorialTimeElapsed, - tutorialID, VERSION, this.realControllerName); - } - - // This is a message sent from the "entry" portal in the courtyard, - // after the tutorial has finished. - this.enteredEntryPortal = function() { - info("Got enteredEntryPortal"); - if (didFinishTutorial) { - info("Tracking wentToEntry"); - this.trackStep("wentToEntry", wentToEntryStepNum); - } - } -} - -// To run the tutorial: -// -//var tutorialManager = new TutorialManager(); -//tutorialManager.startTutorial(); -// -// -//var keyReleaseHandler = function(event) { -// if (event.isShifted && event.isAlt) { -// print('here', event.text); -// if (event.text == "F12") { -// if (!tutorialManager.startNextStep()) { -// tutorialManager.startTutorial(); -// } -// } else if (event.text == "F11") { -// tutorialManager.restartStep(); -// } else if (event.text == "F10") { -// MyAvatar.shouldRenderLocally = !MyAvatar.shouldRenderLocally; -// } else if (event.text == "r") { -// tutorialManager.stopTutorial(); -// tutorialManager.startTutorial(); -// } -// } -//}; -//Controller.keyReleaseEvent.connect(keyReleaseHandler); diff --git a/tutorial/tutorialEntityIDs.js b/tutorial/tutorialEntityIDs.js deleted file mode 100644 index f53ac1a56c..0000000000 --- a/tutorial/tutorialEntityIDs.js +++ /dev/null @@ -1,360 +0,0 @@ -TUTORIAL_TAG_TO_ENTITY_IDS_MAP = { - "teleport-vive": { - "{7df1abc4-1b7c-4352-985c-f3f6ad8d65b7}": { - "tag": "teleport-vive" - } - }, - "teleport-touch": { - "{ff064b9e-7fa4-4693-a386-a67b9f92a948}": { - "tag": "teleport-touch" - } - }, - "turnAround-vive": { - "{9b14f224-b2f6-447f-bb86-f5d875cf4c33}": { - "tag": "turnAround-vive" - } - }, - "turnAround-touch": { - "{ce74b3ca-d1c7-4980-bd98-2d488095a39e}": { - "tag": "turnAround-touch" - } - }, - "teleport": { - "{4478f7b5-d3ac-4213-9a7b-ad8cd69575b8}": { - "tag": "teleport" - } - }, - "finish": { - "{340e05b5-88df-4b2b-b43c-756dd714d6d8}": { - "tag": "finish" - } - }, - "door": { - "{9c5b0fee-e695-4516-94cd-153371e3857b}": { - "tag": "door" - } - }, - "farGrab": { - "{70fcd96c-cd59-4f23-9ca5-a167f2f85680}": { - "visible": false, - "tag": "farGrab" - }, - "{ff7b9793-0d94-4f18-bc09-4ab589126e60}": { - "tag": "farGrab" - }, - "{fdd77d2c-af36-41c1-ba57-74b7ae79d996}": { - "tag": "farGrab" - }, - "{e11700f6-bc9a-411f-9ddc-bf265d4e3ccf}": { - "tag": "farGrab" - }, - "{95850c56-cd1c-42b9-ab6b-a163a6f2878f}": { - "tag": "farGrab" - } - }, - "nearGrab-vive": { - "{88221a22-b710-4d35-852b-5257b0aa77dc}": { - "tag": "nearGrab-vive" - } - }, - "nearGrab-touch": { - "{7c0f2fde-6c5c-459b-bf82-421979cebf2e}": { - "tag": "nearGrab-touch" - } - }, - "nearGrab": { - "{55c861ef-60ca-4722-a6c5-9c6967966ec5}": { - "tag": "nearGrab" - }, - "{644d655b-ae66-43b1-9bab-a44b9a8ad632}": { - "tag": "nearGrab" - }, - "{8bf0baa1-88d0-448a-a782-100d4413bd82}": { - "tag": "nearGrab" - }, - "{5cf22b9c-fb22-4854-8821-554422980b24}": { - "visible": false, - "tag": "nearGrab" - } - }, - "equip-part1-touch": { - "{470f0634-8be7-4b52-a8bd-5183d489fcb6}": { - "tag": "equip-part1-touch" - } - }, - "equip-part1-vive": { - "{97ced5e7-fc81-40f9-a9e8-f85b4b30f24c}": { - "tag": "equip-part1-vive" - } - }, - "equip-part1": { - "{d73822ca-0a34-4cf4-a530-3258ac459a14}": { - "tag": "equip-part1" - }, - "{8572d991-5777-45df-97bf-7243d7b12f81}": { - "tag": "equip-part1" - }, - "{da5ea72e-54b6-41ac-b711-742b062b6968}": { - "tag": "equip-part1" - }, - "{c8944a13-9acb-4d77-b1ee-851845e98357}": { - "tag": "equip-part1" - }, - "{e9481c78-1a21-43f7-b54c-58f2efdf3c8f}": { - "tag": "equip-part1" - }, - "{ca3c28f3-15fc-4349-a85e-eaca0fad6434}": { - "tag": "equip-part1" - }, - "{09ddcb94-52a7-4f50-a5a2-db9db28fc519}": { - "tag": "equip-part1" - }, - "{dd13fcd5-616f-4749-ab28-2e1e8bc512e9}": { - "tag": "equip-part1" - } - }, - "equip-part2-vive": { - "{b5d17eda-90ab-40cf-b973-efcecb2e992e}": { - "tag": "equip-part2-vive" - }, - "{6307cd16-dd1d-4988-a339-578178436b45}": { - "tag": "equip-part2-vive" - } - }, - "equip-part2-touch": { - "{69195139-e020-4739-bb2c-50faebc6860a}": { - "tag": "equip-part2-touch" - }, - "{9b0a99ae-221b-4e59-ba3c-d8e64a083774}": { - "tag": "equip-part2-touch" - } - }, - "bothGrab": { - "{14792a6e-dc6f-4e7a-843f-4b109b06b5a4}": { - "visible": false, - "tag": "bothGrab", - "collidable": true - }, - "{215dcd14-88fc-4604-9033-cbd2a660178a}": { - "tag": "bothGrab" - }, - "{fbc2e40d-0633-45ac-b1c9-97fc8465f93b}": { - "tag": "bothGrab" - }, - "{6752dad6-109d-4dc5-aef7-dc8509468cf4}": { - "tag": "bothGrab" - }, - "{178e2c71-dff5-4231-8d28-df47fddf4709}": { - "soundKey": { - "playbackGapRange": 0, - "url": "atp:/sounds/crackling_fire.L.wav", - "volume": 0.5, - "playbackGap": 5, - "playing": false, - "loop": true - }, - "tag": "bothGrab" - }, - "{52445ac5-8730-4457-827e-6c076d2c609c}": { - "tag": "bothGrab" - } - }, - "raiseHands": { - "{7139e45d-25cf-470b-b133-c0fda0099d2b}": { - "tag": "raiseHands" - } - }, - "equip": { - "{e7897c9c-f4fa-4989-a383-28af56c2e544}": { - "visible": false, - "tag": "equip" - }, - "{9df518da-9e65-4b76-8a79-eeefdb0b7310}": { - "visible": false, - "tag": "equip" - }, - "{1a77c20e-5d9b-4b54-bf20-1416141a7ca8}": { - "tag": "equip" - } - }, - "orient-vive": { - "{95d233ab-ed0a-46e1-b047-1c542688ef3f}": { - "tag": "orient-vive" - } - }, - "orient-touch": { - "{1c95f945-ec46-4aac-b0f1-e64e073dbfaa}": { - "tag": "orient-touch" - } - } -}; - -TUTORIAL_NAME_TO_ENTITY_PROPERTIES_MAP = { - "tutorial/gun_spawn": { - "clientOnly": 0, - "collisionless": 1, - "color": { - "blue": 0, - "green": 0, - "red": 255 - }, - "created": "2016-09-08T18:38:24Z", - "dimensions": { - "x": 0.0649842768907547, - "y": 0.0649842768907547, - "z": 0.0649842768907547 - }, - "id": "{9df518da-9e65-4b76-8a79-eeefdb0b7310}", - "ignoreForCollisions": 1, - "lastEdited": 1481926907366120, - "lastEditedBy": "{b80185ea-0936-4397-a5a4-3a64004f545f}", - "name": "tutorial/gun_spawn", - "owningAvatarID": "{00000000-0000-0000-0000-000000000000}", - "position": { - "x": 0.60231781005859375, - "y": 0.68465065956115723, - "z": 0.39223569631576538 - }, - "queryAACube": { - "scale": 0.11255607008934021, - "x": 0.54603976011276245, - "y": 0.62837260961532593, - "z": 0.33595764636993408 - }, - "rotation": { - "w": -0.025101065635681152, - "x": 0.70666050910949707, - "y": 0.70666050910949707, - "z": -0.025131583213806152 - }, - "shape": "Cube", - "type": "Box", - "userData": "{\"visible\":false,\"tag\":\"equip\"}", - "visible": 0 - }, - "tutorial/nearGrab/box_spawn": { - "clientOnly": 0, - "collisionless": 1, - "color": { - "blue": 255, - "green": 0, - "red": 255 - }, - "created": "2016-09-08T18:38:24Z", - "dimensions": { - "x": 0.082253716886043549, - "y": 0.082253716886043549, - "z": 0.082253716886043549 - }, - "id": "{5cf22b9c-fb22-4854-8821-554422980b24}", - "ignoreForCollisions": 1, - "lastEdited": 1481926907334206, - "lastEditedBy": "{b80185ea-0936-4397-a5a4-3a64004f545f}", - "name": "tutorial/nearGrab/box_spawn", - "owningAvatarID": "{00000000-0000-0000-0000-000000000000}", - "position": { - "x": 0.61857688426971436, - "y": 0.80955326557159424, - "z": 0.36191046237945557 - }, - "queryAACube": { - "scale": 0.14246761798858643, - "x": 0.54734307527542114, - "y": 0.73831945657730103, - "z": 0.29067665338516235 - }, - "rotation": { - "w": 1, - "x": -1.52587890625e-05, - "y": -1.52587890625e-05, - "z": -1.52587890625e-05 - }, - "shape": "Cube", - "type": "Box", - "userData": "{\"visible\":false,\"tag\":\"nearGrab\"}", - "visible": 0 - }, - "tutorial/farGrab/box_spawn": { - "clientOnly": 0, - "collisionless": 1, - "color": { - "blue": 255, - "green": 0, - "red": 255 - }, - "created": "2016-09-08T18:38:24Z", - "dimensions": { - "x": 0.16850528120994568, - "y": 0.16850528120994568, - "z": 0.16850528120994568 - }, - "id": "{70fcd96c-cd59-4f23-9ca5-a167f2f85680}", - "ignoreForCollisions": 1, - "lastEdited": 1481926908795578, - "lastEditedBy": "{b80185ea-0936-4397-a5a4-3a64004f545f}", - "name": "tutorial/farGrab/box_spawn", - "owningAvatarID": "{00000000-0000-0000-0000-000000000000}", - "position": { - "x": 3.4866282939910889, - "y": 0.67159509658813477, - "z": 0.47892442345619202 - }, - "queryAACube": { - "scale": 0.64707136154174805, - "x": 3.2037394046783447, - "y": 0.33042514324188232, - "z": 0.14542555809020996 - }, - "rotation": { - "w": 1, - "x": -1.52587890625e-05, - "y": -1.52587890625e-05, - "z": -1.52587890625e-05 - }, - "shape": "Cube", - "type": "Box", - "userData": "{\"visible\":false,\"tag\":\"farGrab\"}", - "visible": 0 - }, - "tutorial/teleport/pad": { - "userData": "{\"tag\":\"teleport\"}", - "rotation": { - "y": -0.9702650308609009, - "x": -2.1246911273919977e-05, - "z": -4.222852112434339e-06, - "w": 0.2420452982187271 - }, - "dimensions": { - "y": 0.4365682601928711, - "x": 2.1751723289489746, - "z": 2.175173044204712 - }, - "collisionless": 1, - "created": "2016-09-08T18:38:24Z", - "queryAACube": { - "y": -1.7979401350021362, - "x": 7.5136213302612305, - "scale": 3.106983184814453, - "z": -1.4602710008621216 - }, - "visible": 0, - "angularVelocity": { - "y": -0.5235987901687622, - "x": 0, - "z": 0 - }, - "clientOnly": 0, - "owningAvatarID": "{00000000-0000-0000-0000-000000000000}", - "angularDamping": 0, - "position": { - "y": -0.2444484978914261, - "x": 9.067112922668457, - "z": 0.09322060644626617 - }, - "modelURL": "atp:/alan/dev/Teleport-Pad.fbx", - "ignoreForCollisions": 1, - "type": "Model", - "id": "{4478f7b5-d3ac-4213-9a7b-ad8cd69575b8}", - "name": "tutorial/teleport/pad" - } -}; diff --git a/tutorial/tutorialStartZone.js b/tutorial/tutorialStartZone.js deleted file mode 100644 index 13e5ac89d0..0000000000 --- a/tutorial/tutorialStartZone.js +++ /dev/null @@ -1,51 +0,0 @@ -(function() { - var TutorialStartZone = function() { - print("TutorialStartZone | Creating"); - }; - - TutorialStartZone.prototype = { - preload: function(entityID) { - print("TutorialStartZone | Preload"); - this.entityID = entityID; - this.sendStartIntervalID = null; - }, - enterEntity: function() { - var self = this; - // send message to outer zone - print("TutorialStartZone | Entered the tutorial start area"); - if (HMD.isHMDAvailable() && HMD.isHandControllerAvailable() && HMD.active) { - function sendStart() { - print("TutorialStartZone | Checking parent ID"); - var parentID = Entities.getEntityProperties(self.entityID, 'parentID').parentID; - print("TutorialStartZone | Parent ID is: ", parentID); - if (parentID) { - print("TutorialStartZone | Sending start"); - Entities.callEntityMethod(parentID, 'onEnteredStartZone'); - } else { - print("TutorialStartZone | ERROR: No parent id found on tutorial start zone"); - } - } - this.sendStartIntervalID = Script.setInterval(sendStart, 1500); - sendStart(); - } else { - print("TutorialStartZone | User tried to go to tutorial without active HMD and hand controllers, sending back to /"); - Window.alert("To proceed with this tutorial, please connect your Vive or Oculus headset and hand controllers."); - location = "/"; - } - }, - leaveEntity: function() { - print("TutorialStartZone | Exited the tutorial start area"); - if (this.sendStartIntervalID) { - Script.clearInterval(this.sendStartIntervalID); - } - var parentID = Entities.getEntityProperties(this.entityID, 'parentID').parentID; - print("TutorialStartZone | Parent ID is: ", parentID); - if (parentID) { - print("TutorialStartZone | Sending onLeftStartZone"); - Entities.callEntityMethod(parentID, 'on'); - } - } - }; - - return new TutorialStartZone(); -}); diff --git a/tutorial/tutorialZone.js b/tutorial/tutorialZone.js deleted file mode 100644 index 78443ef7df..0000000000 --- a/tutorial/tutorialZone.js +++ /dev/null @@ -1,142 +0,0 @@ -if (!Function.prototype.bind) { - Function.prototype.bind = function(oThis) { - if (typeof this !== 'function') { - // closest thing possible to the ECMAScript 5 - // internal IsCallable function - throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable'); - } - - var aArgs = Array.prototype.slice.call(arguments, 1), - fToBind = this, - fNOP = function() {}, - fBound = function() { - return fToBind.apply(this instanceof fNOP - ? this - : oThis, - aArgs.concat(Array.prototype.slice.call(arguments))); - }; - - if (this.prototype) { - // Function.prototype doesn't have a prototype property - fNOP.prototype = this.prototype; - } - fBound.prototype = new fNOP(); - - return fBound; - }; -} - -(function() { - Script.include("ownershipToken.js"); - Script.include("tutorial.js"); - - var CHANNEL_AWAY_ENABLE = "Hifi-Away-Enable"; - function setAwayEnabled(value) { - var message = value ? 'enable' : 'disable'; - Messages.sendLocalMessage(CHANNEL_AWAY_ENABLE, message); - } - - var TutorialZone = function() { - print("TutorialZone | Creating"); - this.token = null; - }; - - TutorialZone.prototype = { - keyReleaseHandler: function(event) { - print(event.text); - if (event.isShifted && event.isAlt) { - if (event.text == "F12") { - if (!this.tutorialManager.startNextStep()) { - this.tutorialManager.startTutorial(); - } - } else if (event.text == "F11") { - this.tutorialManager.restartStep(); - } else if (event.text == "F10") { - MyAvatar.shouldRenderLocally = !MyAvatar.shouldRenderLocally; - } else if (event.text == "r") { - this.tutorialManager.stopTutorial(); - this.tutorialManager.startTutorial(); - } - } - }, - preload: function(entityID) { - print("TutorialZone | Preload"); - this.entityID = entityID; - }, - onEnteredStartZone: function() { - print("TutorialZone | Got onEnteredStartZone"); - var self = this; - if (!this.token) { - print("TutorialZone | Creating token"); - // The start zone has been entered, hide the overlays immediately - setAwayEnabled(false); - Menu.setIsOptionChecked("Overlays", false); - MyAvatar.shouldRenderLocally = false; - Toolbars.getToolbar("com.highfidelity.interface.toolbar.system").writeProperty("visible", false); - this.token = new OwnershipToken(Math.random() * 100000, this.entityID, { - onGainedOwnership: function(token) { - print("TutorialZone | GOT OWNERSHIP"); - if (!self.tutorialManager) { - self.tutorialManager = new TutorialManager(); - } - self.tutorialManager.startTutorial(); - print("TutorialZone | making bound release handler"); - self.keyReleaseHandlerBound = self.keyReleaseHandler.bind(self); - print("TutorialZone | binding"); - Controller.keyReleaseEvent.connect(self.keyReleaseHandlerBound); - print("TutorialZone | done"); - }, - onLostOwnership: function(token) { - print("TutorialZone | LOST OWNERSHIP"); - if (self.tutorialManager) { - print("TutorialZone | stopping tutorial.."); - self.tutorialManager.stopTutorial(); - print("TutorialZone | done"); - Controller.keyReleaseEvent.disconnect(self.keyReleaseHandlerBound); - } else { - print("TutorialZone | no tutorial manager..."); - } - } - }); - } - }, - onLeftStartZone: function() { - print("TutorialZone | Got onLeftStartZone"); - - // If the start zone was exited, and the tutorial hasn't started, go ahead and - // re-enable the HUD/Overlays - if (!this.tutorialManager) { - Menu.setIsOptionChecked("Overlays", true); - MyAvatar.shouldRenderLocally = true; - setAwayEnabled(true); - Toolbars.getToolbar("com.highfidelity.interface.toolbar.system").writeProperty("visible", true); - } - }, - - onEnteredEntryPortal: function() { - print("TutorialZone | Got onEnteredEntryPortal"); - if (this.tutorialManager) { - print("TutorialZone | Calling enteredEntryPortal"); - this.tutorialManager.enteredEntryPortal(); - } - }, - - enterEntity: function() { - print("TutorialZone | ENTERED THE TUTORIAL AREA"); - }, - leaveEntity: function() { - print("TutorialZone | EXITED THE TUTORIAL AREA"); - if (this.token) { - print("TutorialZone | Destroying token"); - this.token.destroy(); - this.token = null; - } - if (this.tutorialManager) { - this.tutorialManager.stopTutorial(); - //this.tutorialManager = null; - } - } - }; - - return new TutorialZone(); -});