Just the interaction JS scripts

This commit is contained in:
Trevor Berninger 2017-04-13 13:04:28 -07:00
parent f23f9ec698
commit 6b96cfad42
4 changed files with 619 additions and 0 deletions

View file

@ -0,0 +1,179 @@
//
// Interaction.js
// scripts/interaction
//
// Created by Trevor Berninger on 3/20/17.
// Copyright 2017 Limitless ltd.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
(function(){
print("loading interaction script");
var Avatar = false;
var NPC = false;
var previousNPC = false;
var hasCenteredOnNPC = false;
var distance = 10;
var r = 8;
var player = false;
var baselineX = 0;
var baselineY = 0;
var nodRange = 20;
var shakeRange = 20;
var ticker = false;
var heartbeatTimer = false;
function callOnNPC(message) {
if(NPC)
Messages.sendMessage("interactionComs", NPC + ":" + message);
else
Messages.sendMessage("interactionComs", previousNPC + ":" + message);
}
LimitlessSpeechRecognition.onFinishedSpeaking.connect(function(speech) {
print("Got: " + speech);
callOnNPC("voiceData:" + speech);
});
LimitlessSpeechRecognition.onReceivedTranscription.connect(function(speech) {
callOnNPC("speaking");
});
function setBaselineRotations(rot) {
baselineX = rot.x;
baselineY = rot.y;
}
function findLookedAtNPC() {
var intersection = AvatarList.findRayIntersection({origin: MyAvatar.position, direction: Quat.getFront(Camera.getOrientation())}, true);
if (intersection.intersects && intersection.distance <= distance){
var npcAvatar = AvatarList.getAvatar(intersection.avatarID);
if (npcAvatar.displayName.search("NPC") != -1) {
setBaselineRotations(Quat.safeEulerAngles(Camera.getOrientation()));
return intersection.avatarID;
}
}
return false;
}
function isStillFocusedNPC() {
var avatar = AvatarList.getAvatar(NPC);
if (avatar) {
var avatarPosition = avatar.position;
return Vec3.distance(MyAvatar.position, avatarPosition) <= distance && Math.abs(Quat.dot(Camera.getOrientation(), Quat.lookAtSimple(MyAvatar.position, avatarPosition))) > 0.6;
}
return false; // NPC reference died. Maybe it crashed or we teleported to a new world?
}
function onWeLostFocus() {
print("lost NPC: " + NPC);
callOnNPC("onLostFocused");
var baselineX = 0;
var baselineY = 0;
}
function onWeGainedFocus() {
print("found NPC: " + NPC);
callOnNPC("onFocused");
var rotation = Quat.safeEulerAngles(Camera.getOrientation());
baselineX = rotation.x;
baselineY = rotation.y;
LimitlessSpeechRecognition.setListeningToVoice(true);
}
function checkFocus() {
var newNPC = findLookedAtNPC();
if (NPC && newNPC != NPC && !isStillFocusedNPC()) {
onWeLostFocus();
previousNPC = NPC;
NPC = false;
}
if (!NPC && newNPC != false) {
NPC = newNPC;
onWeGainedFocus();
}
}
function checkGesture() {
var rotation = Quat.safeEulerAngles(Camera.getOrientation());
var deltaX = Math.abs(rotation.x - baselineX);
if (deltaX > 180) {
deltaX -= 180;
}
var deltaY = Math.abs(rotation.y - baselineY);
if (deltaY > 180) {
deltaY -= 180;
}
if (deltaX >= nodRange && deltaY <= shakeRange) {
callOnNPC("onNodReceived");
} else if (deltaY >= shakeRange && deltaX <= nodRange) {
callOnNPC("onShakeReceived");
}
}
function tick() {
checkFocus();
if (NPC) {
checkGesture();
}
}
function heartbeat() {
callOnNPC("beat");
}
Messages.subscribe("interactionComs");
Messages.messageReceived.connect(function (channel, message, sender) {
if(channel === "interactionComs" && player) {
var codeIndex = message.search('clientexec');
if(codeIndex != -1) {
var code = message.substr(codeIndex+11);
Script.evaluate(code, '');
}
}
});
this.enterEntity = function(id) {
player = true;
print("Something entered me: " + id);
LimitlessSpeechRecognition.setAuthKey("testKey");
if (!ticker) {
ticker = Script.setInterval(tick, 333);
}
if(!heartbeatTimer) {
heartbeatTimer = Script.setInterval(heartbeat, 1000);
}
};
this.leaveEntity = function(id) {
LimitlessSpeechRecognition.setListeningToVoice(false);
player = false;
print("Something left me: " + id);
if (previousNPC)
Messages.sendMessage("interactionComs", previousNPC + ":leftArea");
if (ticker) {
ticker.stop();
ticker = false;
}
if (heartbeatTimer) {
heartbeatTimer.stop();
heartbeatTimer = false;
}
};
this.unload = function() {
print("Okay. I'm Unloading!");
if (ticker) {
ticker.stop();
ticker = false;
}
};
print("finished loading interaction script");
});

View file

@ -0,0 +1,179 @@
//
// NPCHelpers.js
// scripts/interaction
//
// Created by Trevor Berninger on 3/20/17.
// Copyright 2017 Limitless ltd.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
var audioInjector = false;
var blocked = false;
var playingResponseAnim = false;
var storyURL = "";
var _qid = "start";
print("TESTTEST");
function strContains(str, sub) {
return str.search(sub) != -1;
}
function callbackOnCondition(conditionFunc, ms, callback, count) {
var thisCount = 0;
if (typeof count !== 'undefined') {
thisCount = count;
}
if (conditionFunc()) {
callback();
} else if (thisCount < 10) {
Script.setTimeout(function() {
callbackOnCondition(conditionFunc, ms, callback, thisCount + 1);
}, ms);
} else {
print("callbackOnCondition timeout");
}
}
function playAnim(animURL, looping, onFinished) {
print("got anim: " + animURL);
print("looping: " + looping);
// Start caching the animation if not already cached.
AnimationCache.getAnimation(animURL);
// Tell the avatar to animate so that we can tell if the animation is ready without crashing
Avatar.startAnimation(animURL, 30, 1, false, false, 0, 1);
// Continually check if the animation is ready
callbackOnCondition(function(){
var details = Avatar.getAnimationDetails();
// if we are running the request animation and are past the first frame, the anim is loaded properly
print("running: " + details.running);
print("url and animURL: " + details.url.trim().replace(/ /g, "%20") + " | " + animURL.trim().replace(/ /g, "%20"));
print("currentFrame: " + details.currentFrame);
return details.running && details.url.trim().replace(/ /g, "%20") == animURL.trim().replace(/ /g, "%20") && details.currentFrame > 0;
}, 250, function(){
var timeOfAnim = ((AnimationCache.getAnimation(animURL).frames.length / 30) * 1000) + 100; // frames to miliseconds plus a small buffer
print("animation loaded. length: " + timeOfAnim);
// Start the animation again but this time with frame information
Avatar.startAnimation(animURL, 30, 1, looping, true, 0, AnimationCache.getAnimation(animURL).frames.length);
if (typeof onFinished !== 'undefined') {
print("onFinished defined. setting the timeout with timeOfAnim");
timers.push(Script.setTimeout(onFinished, timeOfAnim));
}
});
}
function playSound(soundURL, onFinished) {
callbackOnCondition(function() {
return SoundCache.getSound(soundURL).downloaded;
}, 250, function() {
if (audioInjector) {
audioInjector.stop();
}
audioInjector = Audio.playSound(SoundCache.getSound(soundURL), {position: Avatar.position, volume: 1.0});
if (typeof onFinished !== 'undefined') {
audioInjector.finished.connect(onFinished);
}
});
}
function npcRespond(soundURL, animURL, onFinished) {
if (typeof soundURL !== 'undefined' && soundURL != '') {
print("npcRespond got soundURL!");
playSound(soundURL, function(){
print("sound finished");
var animDetails = Avatar.getAnimationDetails();
print("animDetails.lastFrame: " + animDetails.lastFrame);
print("animDetails.currentFrame: " + animDetails.currentFrame);
if (animDetails.lastFrame < animDetails.currentFrame + 1 || !playingResponseAnim) {
onFinished();
}
audioInjector = false;
});
}
if (typeof animURL !== 'undefined' && animURL != '') {
print("npcRespond got animURL!");
playingResponseAnim = true;
playAnim(animURL, false, function() {
print("anim finished");
playingResponseAnim = false;
print("injector: " + audioInjector);
if (!audioInjector || !audioInjector.isPlaying()) {
print("resetting Timer");
print("about to call onFinished");
onFinished();
}
});
}
}
function npcRespondBlocking(soundURL, animURL, onFinished) {
print("blocking response requested");
if (!blocked) {
print("not already blocked");
blocked = true;
npcRespond(soundURL, animURL, function(){
if (onFinished){
onFinished();
}blocked = false;
});
}
}
function npcContinueStory(soundURL, animURL, nextID, onFinished) {
if (!nextID) {
nextID = _qid;
}
npcRespondBlocking(soundURL, animURL, function(){
if (onFinished){
onFinished();
}setQid(nextID);
});
}
function setQid(newQid) {
print("setting quid");
print("_qid: " + _qid);
_qid = newQid;
print("_qid: " + _qid);
doActionFromServer("init");
}
function runOnClient(code) {
Messages.sendMessage("interactionComs", "clientexec:" + code);
}
function doActionFromServer(action, data, useServerCache) {
if (action == "start") {
ignoreCount = 0;
_qid = "start";
}
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://gserv_devel.studiolimitless.com/story", true);
xhr.onreadystatechange = function(){
if (xhr.readyState == 4){
if (xhr.status == 200) {
print("200!");
print("evaluating: " + xhr.responseText);
Script.evaluate(xhr.responseText, "");
} else if (xhr.status == 444) {
print("Limitless Serv 444: API error: " + xhr.responseText);
} else {
print("HTTP Code: " + xhr.status + ": " + xhr.responseText);
}
}
};
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
var postData = "url=" + storyURL + "&action=" + action + "&qid=" + _qid;
if (typeof data !== 'undefined' && data != '') {
postData += "&data=" + data;
}
if (typeof useServerCache !== 'undefined' && !useServerCache) {
postData += "&nocache=true";
}
print("Sending: " + postData);
xhr.send(postData);
}

View file

@ -0,0 +1,102 @@
//
// NPC_AC.js
// scripts/interaction
//
// Created by Trevor Berninger on 3/20/17.
// Copyright 2017 Limitless ltd.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
var currentlyUsedIndices = [];
var timers = [];
var currentlyEngaged = false;
var questionNumber = 0;
var heartbeatTimeout = false;
function getRandomRiddle() {
var randIndex = null;
do {
randIndex = Math.floor(Math.random() * 15) + 1;
} while (randIndex in currentlyUsedIndices);
currentlyUsedIndices.push(randIndex);
return randIndex.toString();
}
Script.include("https://raw.githubusercontent.com/Delamare2112/hifi/Interaction/unpublishedScripts/interaction/NPCHelpers.js", function(){
print("NPCHelpers included.");main();
});
var idleAnim = "https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/idle.fbx";
var FST = "https://s3.amazonaws.com/hifi-public/tony/fixed-sphinx/sphinx.fst";
Agent.isAvatar = true;
Avatar.skeletonModelURL = FST;
Avatar.displayName = "NPC";
Avatar.position = {x: 0.3, y: -23.4, z: 8.0};
Avatar.orientation = {x: 0, y: 1, z: 0, w: 0};
// Avatar.position = {x: 1340.3555, y: 4.078, z: -420.1562};
// Avatar.orientation = {x: 0, y: -0.707, z: 0, w: 0.707};
Avatar.scale = 2;
Messages.subscribe("interactionComs");
function endInteraction() {
print("ending interaction");
blocked = false;
currentlyEngaged = false;
if(audioInjector)
audioInjector.stop();
for (var t in timers) {
Script.clearTimeout(timers[t]);
}
if(_qid != "Restarting") {
npcRespondBlocking(
'https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/ScratchDialogue/EarlyExit_0' + (Math.floor(Math.random() * 2) + 1).toString() + '.wav',
'https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/Animation/reversedSphinx.fbx',
function(){
Avatar.startAnimation('https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/Animation/Hifi_Sphinx_Anim_Entrance_Kneel_Combined_with_Intro.fbx', 0);
}
);
}
}
function main() {
storyURL = "https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/Sphinx.json";
Messages.messageReceived.connect(function (channel, message, sender) {
if(!strContains(message, 'beat'))
print(sender + " -> NPC @" + Agent.sessionUUID + ": " + message);
if (channel === "interactionComs" && strContains(message, Agent.sessionUUID)) {
if (strContains(message, 'beat')) {
if(heartbeatTimeout) {
Script.clearTimeout(heartbeatTimeout);
heartbeatTimeout = false;
}
heartbeatTimeout = Script.setTimeout(endInteraction, 1500);
}
else if (strContains(message, "onFocused") && !currentlyEngaged) {
blocked = false;
currentlyEngaged = true;
currentlyUsedIndices = [];
doActionFromServer("start");
} else if (strContains(message, "leftArea")) {
} else if (strContains(message, "speaking")) {
} else {
var voiceDataIndex = message.search("voiceData");
if (voiceDataIndex != -1) {
var words = message.substr(voiceDataIndex+10);
if (!isNaN(_qid) && (strContains(words, "repeat") || (strContains(words, "say") && strContains(words, "again")))) {
doActionFromServer("init");
} else {
doActionFromServer("words", words);
}
}
}
}
});
// Script.update.connect(updateGem);
Avatar.startAnimation("https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/Animation/Hifi_Sphinx_Anim_Entrance_Kneel_Combined_with_Intro.fbx", 0);
}

View file

@ -0,0 +1,159 @@
{
"Name": "10 Questions",
"Defaults":
{
"Actions":
{
"positive": "var x=function(){if(questionNumber>=2){setQid('Finished');return;}var suffix=['A', 'B'][questionNumber++] + '_0' + (Math.floor(Math.random() * 2) + 2).toString() + '.wav';npcContinueStory('https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/ScratchDialogue/RightAnswer'+suffix, 'https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/Animation/RightAnswerB_02.fbx', getRandomRiddle());};x();",
"unknown": "var suffix=(Math.floor(Math.random() * 3) + 1).toString();npcContinueStory('https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/ScratchDialogue/WrongAnswer_0' + suffix + '.wav','https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/Animation/WrongAnswer_0' + suffix + '.fbx', getRandomRiddle());",
"hint": "var suffix=(Math.floor(Math.random() * 2) + 1).toString();npcContinueStory('https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/ScratchDialogue/Hint_0' + suffix + '.wav','https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/Animation/Hint_0' + suffix + '.fbx')"
},
"Responses":
{
"positive": ["yes","yup","yeah","yahoo","sure","affirmative","okay","aye","right","exactly","course","naturally","unquestionably","positively","yep","definitely","certainly","fine","absolutely","positive","love","fantastic"],
"thinking": ["oh", "think about", "i know", "what was", "well", "not sure", "one before", "hold", "one moment", "one second", "1 second", "1 sec", "one sec"],
"hint": ["hint", "heads"]
}
},
"Story":
[
{
"QID": "start",
"init": "questionNumber=0;npcContinueStory('https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/ScratchDialogue/HiFi_Sphinx_Anim_Combined_Entrance_Audio.wav', 'https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/Animation/Hifi_Sphinx_Anim_Entrance_Kneel_Combined_with_Intro.fbx', getRandomRiddle());"
},
{
"QID": "1",
"init": "npcRespondBlocking('https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/ScratchDialogue/Riddle_Blackboard.wav', 'https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/Animation/Riddle_Blackboard.fbx');",
"responses":
{
"positive": ["blackboard", "chalkboard", "chalk board", "slate"]
}
},
{
"QID": "2",
"init": "npcRespondBlocking('https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/ScratchDialogue/Riddle_Breath.wav', 'https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/Animation/Riddle_Breath.fbx');",
"responses":
{
"positive": ["breath", "death"]
}
},
{
"QID": "3",
"init": "npcRespondBlocking('https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/ScratchDialogue/Riddle_Clock.wav', 'https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/Animation/Riddle_Clock.fbx');",
"responses":
{
"positive": ["clock", "cock"]
}
},
{
"QID": "4",
"init": "npcRespondBlocking('https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/ScratchDialogue/Riddle_Coffin.wav', 'https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/Animation/Riddle_Coffin.fbx');",
"responses":
{
"positive": ["coffin", "casket", "possum"]
}
},
{
"QID": "5",
"init": "npcRespondBlocking('https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/ScratchDialogue/Riddle_Coin.wav', 'https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/Animation/Riddle_Coin.fbx');",
"responses":
{
"positive": ["coin", "boing", "coinage", "coin piece", "change", "join"]
}
},
{
"QID": "6",
"init": "npcRespondBlocking('https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/ScratchDialogue/Riddle_Corn.wav', 'https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/Animation/Riddle_Corn.fbx');",
"responses":
{
"positive": ["corn", "born", "maize", "maze", "means", "torn", "horn", "worn", "porn"]
}
},
{
"QID": "7",
"init": "npcRespondBlocking('https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/ScratchDialogue/Riddle_Darkness.wav', 'https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/Animation/Riddle_Darkness.fbx');",
"responses":
{
"positive": ["darkness", "dark", "blackness"]
}
},
{
"QID": "8",
"init": "npcRespondBlocking('https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/ScratchDialogue/Riddle_Gloves.wav', 'https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/Animation/Riddle_Gloves.fbx');",
"responses":
{
"positive": ["gloves", "love"]
}
},
{
"QID": "9",
"init": "npcRespondBlocking('https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/ScratchDialogue/Riddle_Gold.wav', 'https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/Animation/Riddle_Gold.fbx');",
"responses":
{
"positive": ["gold", "old", "bold", "cold", "told"]
}
},
{
"QID": "10",
"init": "npcRespondBlocking('https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/ScratchDialogue/Riddle_River.wav', 'https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/Animation/Riddle_River.fbx');",
"responses":
{
"positive": ["river", "bigger", "stream", "creek", "brook"]
}
},
{
"QID": "11",
"init": "npcRespondBlocking('https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/ScratchDialogue/Riddle_Secret.wav', 'https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/Animation/Riddle_Secret.fbx');",
"responses":
{
"positive": ["secret"]
}
},
{
"QID": "12",
"init": "npcRespondBlocking('https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/ScratchDialogue/Riddle_Shadow.wav', 'https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/Animation/Riddle_Shadow.fbx');",
"responses":
{
"positive": ["shadow"]
}
},
{
"QID": "13",
"init": "npcRespondBlocking('https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/ScratchDialogue/Riddle_Silence.wav', 'https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/Animation/Riddle_Silence.fbx');",
"responses":
{
"positive": ["silence", "lance", "quiet"]
}
},
{
"QID": "14",
"init": "npcRespondBlocking('https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/ScratchDialogue/Riddle_Stairs.wav', 'https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/Animation/Riddle_Stairs.fbx');",
"responses":
{
"positive": ["stairs", "steps", "stair", "stairwell", "there's", "stairway"]
}
},
{
"QID": "15",
"init": "npcRespondBlocking('https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/ScratchDialogue/Riddle_Umbrella.wav', 'https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/Animation/Riddle_Umbrella.fbx');",
"responses":
{
"positive": ["umbrella"]
}
},
{
"QID": "Finished",
"init": "Script.clearTimeout(heartbeatTimeout);heartbeatTimeout = false;npcRespondBlocking('https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/ScratchDialogue/ConclusionRight_02.wav', 'https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/Animation/ConclusionRight_02.fbx', function(){runOnClient('MyAvatar.goToLocation({x: 5, y: -29, z: -63}, true, true);');setQid('Restarting');});",
"positive": "",
"negative": "",
"unknown": ""
},
{
"QID": "Restarting",
"init": "npcRespondBlocking('', 'https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/Animation/reversedSphinx.fbx', function(){Avatar.startAnimation('https://storage.googleapis.com/limitlessserv-144100.appspot.com/hifi%20assets/Animation/Hifi_Sphinx_Anim_Entrance_Kneel_Combined_with_Intro.fbx', 0);_qid='';});",
"positive": "",
"negative": "",
"unknown": ""
}
]
}