content/hifi-content/brosche/dev/MoneyTree/Non-minified/ACmoneyTree2.js
2022-02-13 21:50:01 +01:00

1020 lines
No EOL
40 KiB
JavaScript

// ACmoneyTree.js
// Created by Mark Brosche on 10-18-2018
// Copyright 2018 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
//
/* global EventBridge Users AccountServices Agent Avatar EntityViewer */
(function(){
var googleURL = "https://script.google.com/a/highfidelity.io/macros/s/AKfycbxvLCGJwYKGOlszXwm2m-Xa1U90RmnIEJiD6nD7Z8-1RlZaADY/exec";
var request = Script.require('./modules/request.js').request;
// The Metaverse to use
var HIFI_METAVERSE_URL = "https://highfidelity.com";
// The Recent Economic Activity endpoint on the High Fidelity Metaverse
var HIFI_HISTORY_ENDPOINT_URL = HIFI_METAVERSE_URL + "/api/v1/commerce/history";
// The Redmption endpoint on the High Fidelity Metaverse
var HIFI_REDEMPTION_ENDPOINT_URL = HIFI_METAVERSE_URL + "/api/v1/commerce/redeem";
var AVERAGE_INTERVAL = 1.5, // one and a half minutes
AVERAGE_HFC_AMOUNT = 10,
STANDARD_DEVIATION = 5,
SHOW_TIME_LENGTH = 60000, // One minute
RECIPIENT_MAX = 3,
MONEY_TREE_CHANNEL = "MoneyTreeChannel",
AC_SCRIPT_RUN = true,
SEARCH_CENTER = {"x": 0,"y":0,"z":0},
SEARCH_AREA= 1000;
var counterText,
activeText,
targetGiver = [],
targetRecipients = [],
payOnce = false,
randomHFCAmount = null,
userList= [],
coin = [],
interval = null,
indexGiver,
bankers = [],
treeOn = true,
tempList,
messageHandler,
power,
octreeInterval;
var approvedBankerList = [
"markb",
"ryan"
];
var staffList = [
"b",
"Jazmin",
"marko8904",
"mhard",
"theo",
"adamisawake",
"Aitolda",
"Alan_",
"alt.howard",
"amantley",
"amer",
"amukul",
"AndrewNyan",
"andy_batman",
"antoninas",
"asbecker8",
"Ashleigh_Harris",
"Becky",
"BenB",
"bimyou",
"birarda",
"c",
"Caitlyn",
"ChangX",
"Cheetah_Pattern",
"Clement",
"dantescalves",
"dback",
"diogenes",
"dogbones",
"emily",
"Emily_Sykes",
"emilythethird",
"Firebird25",
"freidrica",
"GoofyGoober",
"hifiDave",
"hifi_jamil",
"HifiJaz",
"hifimarko",
"HiFiMicki",
"High.Fidelity",
"howard.stearns",
"huffman",
"huffman2",
"hyperlogic",
"ingerjm0",
"JeffClinton",
"Jess",
"Jherico",
"john.highfidelity",
"JSON",
"jyoum",
"Kayla_HF",
"kencooke",
"kkurian",
"lameboycool",
"leviathan",
"luiscuenca",
"markb",
"maspring",
"miladn",
"mold",
"MissLiviRose",
"nbaldassini",
"Nik",
"Nissim",
"nvrndr",
"OneLisa",
"ovohightower",
"philip",
"r3tk0n",
"realMissLiviRose",
"rickcarr044",
"Roxie",
"Sabrina",
"sam",
"SamGondelman",
"sbbsteam",
"sbirarda",
"Sean",
"seanjones2848",
"serling",
"sethalves",
"shanzam",
"simon_walton",
"sophocles",
"TheBanker",
"thoys",
"WadeWatts",
"wayne",
"yoHighness",
"Ypsilanti",
"zack_hifi",
"ZappoMan",
"zfox",
"zfox1",
"zeenai",
"Battery",
"conference2",
"conference3",
"demo1",
"demo2",
"Langton",
"market",
"purchases",
"Anton.von.Trier",
"kitchen",
"mic1",
"mic2",
"ejahner",
"Freyja",
"qligmaloney",
"userTest",
"highfidelity",
"ryan",
"siphnos",
"ephesos",
"pytho",
"skelina"
];
if (AC_SCRIPT_RUN) {
Agent.isAvatar = true;
Avatar.skeletonModelURL = 'http://hifi-content.s3.amazonaws.com/ozan/dev/avatars/invisible_avatar/invisible_avatar.fst';
Avatar.displayName = "Money Tree Agent";
Avatar.position = {"x":-19.109256744384766,"y":-20.8349714279174805,"z":-11.181184768676758}; // Tree Position
var initialized = false;
var update = function(deltaTime) {
if (!initialized) {
if (Entities.serversExist() && Entities.canRez()) {
Entities.setPacketsPerSecond(6000);
EntityViewer.setPosition(SEARCH_CENTER);
EntityViewer.setCenterRadius(SEARCH_AREA);
// This should allow us to see nano-scale entities from great distances
EntityViewer.setVoxelSizeScale(Number.MAX_VALUE);
octreeInterval = Script.setInterval(function() {
EntityViewer.queryOctree();
}, 1000);
initialized = true;
Script.update.disconnect(update);
}
}
};
Script.update.connect(update);
Script.setTimeout(function(){
try {
Entities.deleteEntity(Entities.findEntitiesByName("Money Tree Counter", SEARCH_CENTER, SEARCH_AREA)[0]);
Entities.deleteEntity(Entities.findEntitiesByName("Money Tree Status", SEARCH_CENTER, SEARCH_AREA)[0]);
Entities.deleteEntity(Entities.findEntitiesByName("Power Button Spawner", SEARCH_CENTER, SEARCH_AREA)[0]);
console.log("[MONEY TREE] deleted stuff");
} catch (e) {
console.log("[MONEY TREE] could not find and delete anything");
}
counterText = Entities.addEntity({
type: "Text",
dimensions: { x: 0.3, y: 0.1854, z: 0.01 },
lineHeight: 0.125,
text: "-",
textColor: {"red": 255, "green": 255, "blue": 255},
backgroundColor: {"red": 0, "green": 0, "blue": 0},
name: "Money Tree Counter",
position: {"x":-17.9620418548584,"y":-10.537128448486328,"z":-10.67333984375},
rotation: {"x":-0.16071832180023193,"y":0.6887953877449036,"z":0.1588284969329834,"w":0.6887840032577515},
visible: true,
collisionless: true,
userData: "{ \"grabbableKey\": { \"grabbable\": false, \"kinematic\": false } }"
});
activeText = Entities.addEntity({
type: "Text",
dimensions: { x: 0.7585, y: 0.1695, z: 0.01 },
lineHeight: 0.115,
text: "STARTING...",
textColor: {"red": 255, "green": 255, "blue": 255},
backgroundColor: {"red": 0, "green": 0, "blue": 0},
name: "Money Tree Status",
position: {"x":-17.9667,"y":-10.5250,"z":-11.4147},
rotation: {"x":-0.15957793593406677,"y":0.6889334321022034,"z":0.1589823216199875,"w":0.6888881921768188},
visible: true,
collisionless: true,
userData: "{ \"grabbableKey\": { \"grabbable\": false, \"kinematic\": false } }"
});
messageHandler = function(channel, message, senderUUID, localOnly) {
if (channel !== MONEY_TREE_CHANNEL) {
print("not on channel");
return;
} else {
message = JSON.parse(message);
}
if (message.type === 'moneyGiven') {
if (senderUUID === targetGiver.nodeID){
for (var i = 0; i < targetRecipients.length; i++) {
if (message.recipientID === targetRecipients[i].nodeID && payOnce === false){
payOnce = true;
sendInput(targetRecipients[i].username);
spawnReceiverMessage(targetRecipients[i].nodeID, randomHFCAmount);
Entities.editEntity(activeText, {text: "WAITING..."});
Script.setTimeout(function(){
payOnce = false;
}, SHOW_TIME_LENGTH);
}
}
}
} else if (message.type === 'tree power') {
treeOn = message.state;
console.log("[MONEY TREE] tree state: ", treeOn);
if (treeOn === true) {
if (interval){
Script.clearInterval(interval);
}
startTree();
Entities.editEntity(activeText, {text: "STARTING..."});
} else {
if (interval){
Script.clearInterval(interval);
console.log("[MONEY TREE] money tree stopping soon");
}
Entities.editEntity(activeText, {text: "OUT OF ORDER"});
}
} else if (message.type === 'entering') {
var nameOnList = false;
var bankerOnList = false;
for ( var i = 0; i < approvedBankerList.length; i++) {
if (message.username === approvedBankerList[i]) {
for (var i = 0; i < bankers.length; i++) {
if ( message.username === bankers[i].username) {
bankerOnList = true;
}
}
if (!bankerOnList) {
bankers.push({
username: message.username,
nodeID: message.nodeID
});
bankerOverlay(bankers.length-1);
bankerOnList = true;
}
Entities.editEntity(counterText, {text: userList.length});
var activeRead = Entities.getEntityProperties(activeText, ['text']);
if (userList.length > 3 && activeRead.text === "MOAR PPL PLZ") {
Entities.editEntity(activeText, {text: "K LET'$ GROW!"});
}
}
}
for (var i = 0; i < userList.length; i++) {
if (message.username === userList[i].username) {
nameOnList = true;
}
}
if (!nameOnList) {
userList.push({
username: message.username,
nodeID: message.nodeID,
staff: false
});
for (var staff = 0; staff < staffList.length; staff++) {
if (message.username === staffList[staff]){
userList[userList.length-1].staff = true;
}
}
Entities.editEntity(counterText, {text: userList.length});
console.log("[MONEY TREE] user list length: ", userList.length);
var activeRead = Entities.getEntityProperties(activeText, ['text']);
if (userList.length >= 3 && activeRead.text === "MOAR PPL PLZ") {
Entities.editEntity(activeText, {text: "K LET'$ GROW!"});
} else if (userList.length < 3) {
Entities.editEntity(activeText, {text: "MOAR PPL PLZ"});
}
}
} else if (message.type === 'leaving') {
try {
for ( var i = 0; i < bankers.length; i++) {
if (message.username === bankers[i].username) {
bankers.splice(i, 1)[0];
Entities.deleteEntity(power);
if (!treeOn) {
Messages.sendMessage(MONEY_TREE_CHANNEL, JSON.stringify({
type: "delete power"
}));
if (power) {
var buttons = Entities.findEntitiesByName("Power Button Spawner", { x: -16.9779, y: -10.3132, z: -10.7944 }, 10);
for (var i = 0; i < buttons.length; i++) {
Entities.deleteEntity(buttons[i]);
}
}
}
}
}
for (var i = 0; i < userList.length; i++) {
if (message.username === userList[i].username) {
userList.splice(i, 1)[0];
Entities.editEntity(counterText, {text: userList.length});
i--;
if (userList.length < 3) {
Entities.editEntity(activeText, {text: "RESTING"});
}
}
}
} catch (e) {
print("[MONEY TREE] Error in retrieving username for deletion");
return;
}
}
};
Messages.messageReceived.connect(messageHandler);
Messages.subscribe(MONEY_TREE_CHANNEL);
try {
for (var i = 0; i < userList.length; i++) {
if (userList[i].username == "") {
userList.splice(i, 1)[0];
}
}
} catch (e) {
print("[MONEY TREE] userList error");
return;
}
}, 1500);
}
function bankerOverlay(index){
if (power){
var buttons = Entities.findEntitiesByName("Power Button Spawner", { x: -16.9779, y: -10.3132, z: -10.7944 }, 10);
for (var i = 0; i < buttons.length; i++) {
Entities.deleteEntity(buttons[i]);
}
Entities.deleteEntity(power);
}
var userData = { bankerID: bankers[index].nodeID, power: treeOn};
console.log("[MONEY TREE] CREATING POWER BUTTON, TREE is:", treeOn);
power = Entities.addEntity({
type: "Box",
dimensions: { x: 0.5, y: 0.5, z: 0.5 },
name: "Power Button Spawner",
script: "https://hifi-content.s3.amazonaws.com/brosche/DomainContent/Hub/MoneyTree/moneyTreeBankerClient.js",
userData: JSON.stringify(userData),
position: { x: -16.9779, y: -9.132, z: -10.7944 },
visible: false,
collisionless: true
});
}
function leftDomain(id){
for (var i = 0; i < userList.length; i++) {
if (userList[i].nodeID === id){
userList.splice(i, 1)[0];
}
}
Entities.editEntity(counterText, {text: userList.length});
if (userList.length < 3) {
Entities.editEntity(activeText, {text: "RESTING"});
}
}
function getMoney() {
try {
var payoutURL = "https://script.google.com/macros/s/AKfycbwwKdRHuSLQX5Ay595PXmKLmJnwzSX13SojHUH9or5LCdclzHg/exec?";
triviaURL = triviaURL + "category=" + "Giraffage_Hemsworth";
request(triviaURL, function (error, data) {
if (!error) {
console.log(JSON.stringify(data));
triviaData = data;
}
});
} catch (err) {
console.log("err:", err);
print("Could not get domain data using userData domainAPIURL");
}
}
// This function is used to send this script's specific version of an HTTP request.
// It's a stripped-down version of High Fidelity's included `request.js` module.
// This function will make the HTTP request and handle the data that's retrieved via a callback.
// It'll also handle dispensing HFC via pre-authorized transactions using HTTP PUT requests.
function request(options, callback) {
var httpRequest = new XMLHttpRequest(), key;
// QT bug: apparently doesn't handle onload. Workaround using readyState.
httpRequest.onreadystatechange = function () {
var READY_STATE_DONE = 4;
var HTTP_OK = 200;
if (httpRequest.readyState >= READY_STATE_DONE) {
var error = (httpRequest.status !== HTTP_OK) && httpRequest.status.toString() + ':' + httpRequest.statusText,
response = !error && httpRequest.responseText,
contentType = !error && httpRequest.getResponseHeader('content-type');
if (!error && contentType.indexOf('application/json') === 0) { // ignoring charset, etc.
try {
response = JSON.parse(response);
} catch (e) {
error = e;
}
}
if (error) {
response = { statusCode: httpRequest.status };
}
callback(error, response);
}
};
if (!options.method) {
options.method = 'GET';
}
if (options.body && (options.method === 'GET')) { // add query parameters
var params = [], appender = (-1 === options.uri.search('?')) ? '?' : '&';
for (key in options.body) {
if (options.body.hasOwnProperty(key)) {
params.push(key + '=' + options.body[key]);
}
}
options.uri += appender + params.join('&');
delete options.body;
}
if (options.json) {
options.headers = options.headers || {};
options.headers["Content-type"] = "application/json";
options.body = JSON.stringify(options.body);
}
for (key in options.headers || {}) {
if (options.headers.hasOwnProperty(key)) {
httpRequest.setRequestHeader(key, options.headers[key]);
}
}
httpRequest.open(options.method, options.uri, true);
httpRequest.send(options.body || null);
}
// This function will get auth data related to a 25-HFC pre-authorized
// transaction from our Google Sheet auth data database.
function getGoogleSheetAuthData(successCallback) {
var googleSheetRequestBody = {
hfc: "25"
};
request({
uri: GOOGLE_SHEET_AUTH_SCRIPT,
method: 'GET',
body: googleSheetRequestBody
}, function(error, response) {
try {
JSON.parse(response);
} catch(e) {
if (e instanceof SyntaxError) {
error = true;
}
}
if (error) {
console.log("ERROR while retrieving authorization data: " + JSON.stringify(response));
console.log("ERROR during slot machine payout: Couldn't get auth data from Google Sheet");
console.log("Slot machine was supposed to pay out to " + slotMachineCurrentPlayer + ".");
slotMachineCurrentPlayer = false;
if (entityExistsInDomain(SLOT_MACHINE_PLAY_TEXT_ID)) {
Entities.editEntity(SLOT_MACHINE_PLAY_TEXT_ID, {text: "Error during payout :("});
}
return false;
} else if (JSON.parse(response).status !== "success") {
console.log("Slot machine DOES NOT have payout funds available!");
console.log("Slot machine was supposed to pay out to " + slotMachineCurrentPlayer + ".");
slotMachineCurrentPlayer = false;
if (entityExistsInDomain(SLOT_MACHINE_PLAY_TEXT_ID)) {
Entities.editEntity(SLOT_MACHINE_PLAY_TEXT_ID, {text: "Error during payout :("});
}
return false;
} else {
console.log("Slot machine DOES have payout funds available! Returning auth data...");
response = JSON.parse(response);
successCallback(response.authorizationID, response.couponID); // payOutToCurrentPlayer()
return true;
}
});
}
// This function will pay out to the current slot machine player in `slotMachineCurrentPlayer`
// based on the passed `authID` and `coupon_id`.
function payOutToCurrentPlayer(authID, couponID) {
// Set up the `redeem` endpoint request body
var hifiRedemptionRequestBody = {
authorization_id: authID,
coupon_id: couponID,
username: slotMachineCurrentPlayer
};
console.log("Attempting payout! Redemption request body: " + JSON.stringify(hifiRedemptionRequestBody));
// Make the call to the redemption endpoint to pay out!
request({
uri: HIFI_REDEMPTION_ENDPOINT_URL,
method: 'PUT',
json: true,
body: hifiRedemptionRequestBody
}, function (error, response) {
if (error || (response.status !== 'success')) {
console.log("ERROR during slot machine payout: ", error || response.status);
console.log("Full response: " + JSON.stringify(response));
console.log("Slot machine was supposed to pay out to " + slotMachineCurrentPlayer + ".");
console.log("SLOT MACHINE DID NOT PAY OUT - Google Sheet will say auth used, but it wasn't!");
slotMachineCurrentPlayer = false;
if (entityExistsInDomain(SLOT_MACHINE_PLAY_TEXT_ID)) {
Entities.editEntity(SLOT_MACHINE_PLAY_TEXT_ID, {text: "Error during payout :("});
}
return;
} else {
console.log("Slot machine paid out to " + slotMachineCurrentPlayer + "!");
slotMachineCurrentPlayer = false;
if (entityExistsInDomain(SLOT_MACHINE_PLAY_TEXT_ID)) {
Entities.editEntity(SLOT_MACHINE_PLAY_TEXT_ID, {text: "YOU WON 25 HFC!!"});
resetPlayTextAfterDelay();
}
}
});
}
// This function will check our pre-authorized funds database to make
// sure we have funds available to pay out.
// If we do have funds available to pay out, we'll call `successCallback(callbackParam)`.
function checkIfSlotMachineHasAvailableFunds(successCallback, callbackParam) {
var googleSheetRequestBody = {
hfc: "25",
justChecking: true
};
console.log("Checking Google Sheet for available authorization data...");
request({
uri: GOOGLE_SHEET_AUTH_SCRIPT,
method: 'GET',
body: googleSheetRequestBody
}, function(error, response) {
try {
JSON.parse(response);
} catch (e) {
if (e instanceof SyntaxError) {
error = true;
}
}
if (error) {
console.log("ERROR while retrieving authorization data: " + JSON.stringify(response));
return false;
} else if (JSON.parse(response).status !== "success") {
console.log("Slot machine DOES NOT have payout authorizations available.");
if (entityExistsInDomain(SLOT_MACHINE_PLAY_TEXT_ID)) {
Entities.editEntity(SLOT_MACHINE_PLAY_TEXT_ID, {text: "Out of order :("});
}
return false;
} else {
console.log("Slot machine DOES have payout authorizations available.");
successCallback(callbackParam); // startSlotMachine(player);
return true;
}
});
}
// This function is used to allow the AC script to see and change entities
// in the domain.
function allowEntityAccess() {
Entities.setPacketsPerSecond(6000);
EntityViewer.setPosition(SLOT_MACHINE_AREA);
EntityViewer.setCenterRadius(1000);
// This should allow us to see nano-scale entities from great distances
EntityViewer.setVoxelSizeScale(Number.MAX_VALUE);
Script.setInterval(function() {
EntityViewer.queryOctree();
}, 1000);
console.log("This AC script now has access to entities in this domain!");
}
// This function checks to make sure that the entity server exists
// and that the AC script has Rez permissions.
// If one or both of those things is false, we'll check again in 5 seconds.
function maybeAllowEntityAccess() {
console.log("Attempting to give this AC script entity access...");
if (Entities.serversExist() && Entities.canRez()) {
allowEntityAccess();
} else {
if (!Entities.canRez()) {
console.log("This AC script doesn't have rez permissions!");
}
Script.setTimeout(maybeAllowEntityAccess, 5000);
}
}
// This function will be called on startup.
function startup() {
// Listen on the slot machine messaging channel!
Messages.subscribe(SLOT_MACHINE_MESSAGING_CHANNEL);
Messages.messageReceived.connect(onMessageReceived);
maybeAllowEntityAccess();
// Make sure the Play Text is set to the default when we're restarting the script.
if (entityExistsInDomain(SLOT_MACHINE_PLAY_TEXT_ID)) {
Entities.editEntity(SLOT_MACHINE_PLAY_TEXT_ID, {text: "Click Red Ball to Play!"});
}
// This function sets up a repeating interval. When the interval timer expires,
// the script will request our Recent Economic Activity.
Script.setInterval(function() {
checkForNewPlayers();
}, CHECK_RECENT_ACTIVITY_INTERVAL_MS);
}
startup();
// This function will be called when the script shuts down.
function shutdown() {
Messages.messageReceived.disconnect(onMessageReceived);
}
function spawnReceiverMessage(receiver, amount){
print("[MONEY TREE] spawing reciever message", JSON.stringify(receiver));
var userData = {
receiverID: receiver,
amount: amount
};
var avatar = AvatarList.getAvatar(receiver);
Entities.addEntity({
type: "Box",
dimensions: { x: 0.5, y: 0.5, z: 0.5 },
name: "Tree Gift Receipt",
script: "https://hifi-content.s3.amazonaws.com/brosche/DomainContent/Hub/MoneyTree/moneyTreeReceiverClient.js",
userData: JSON.stringify(userData),
lifetime: 5,
position: Vec3.sum(avatar.position, Vec3.multiplyQbyV(avatar.orientation, { x: -2.5, y: 0, z: -5 })),
visible: false,
collisionless: true,
parentID: receiver
});
try {
print("[MONEY TREE] making coin particle");
Entities.addEntity({
lifetime: 5,
collidesWith: "",
collisionMask: 0,
collisionless: true,
position: Vec3.sum(avatar.position, Vec3.multiplyQbyV(avatar.orientation, { x: 0, y: 0, z: -1 })),
dimensions: {
x: 0.15,
y: 0.15,
z: 0.15
},
isEmitting: true,
name: "Coin Particle",
type: "ParticleEffect",
userData: "{\"grabbableKey\":{\"grabbable\":false}}",
lifespan: 0.5,
maxParticles: 10,
textures: "https://hifi-content.s3.amazonaws.com/brosche/Trivia/Four%20Square/assets/pictures/tempsnip.png",
emitRate: 10,
emitSpeed: 1.5,
speedSpread: 2,
emitDimensions: {
x: 0,
y: 0,
z: 0
},
emitOrientation: {
x: 0,
y: 0,
z: 0
},
emitterShouldTrail: false,
particleRadius: 0.15,
radiusSpread: 0,
radiusStart: 0,
radiusFinish: 0.15,
color:{
red:255,
blue:255,
green:255
},
colorSpread:{
red:0,
blue:0,
green:0
},
colorStart:{
red:255,
blue:255,
green:255
},
colorFinish:{
red:255,
blue:255,
green:255
},
emitAcceleration:{
x:0,
y:-10,
z:1},
accelerationSpread:{
x:5,
y:3,
z:5
},
alpha: 1,
alphaSpread: 0,
alphaStart: 1,
alphaFinish: 1,
particleSpin: 0,
spinSpread: 0,
spinStart: 0,
spinFinish: 0,
rotateWithEntity: true,
polarStart: 0,
polarFinish: 0,
azimuthStart: -2.9321532249450684,
azimuthFinish: 0.5235987901687622
});
} catch (e) {
print("[MONEY TREE] error spawning coin particle", e);
}
}
function randomizeHFC(){
var funds = true;
var rand = gaussian(AVERAGE_HFC_AMOUNT, STANDARD_DEVIATION);
var listLength =Math.sqrt(userList.length);
var amount = Math.ceil(rand*listLength) - Math.ceil(rand*listLength) % 5;
if (!funds){
Entities.editEntity(activeText, {text: "BANKRUPT!"});
return 0;
}
if (amount >= 50){
amount = 50;
} else if (amount <= 5){
amount = 5;
}
return amount;
}
function randomizeInterval(){
var interval = gaussian(AVERAGE_INTERVAL, 1);
return interval;
}
function createCoinSpawner() {
console.log("[MONEY TREE] SPAWNING COINS");
if (coin.length > 0){
console.log("[MONEY TREE] DELETING COINS");
for (var i = 0; i < coin.length; i++ ) {
Entities.deleteEntity(coin[i]);
}
}
// Show the coins to the giver as overlays
if (targetRecipients[0] == null){
console.log("[MONEY TREE] could not find eligible recipients");
return;
} else if (targetRecipients.length < 2){
console.log("[MONEY TREE] not enough eligible recipients");
return;
} else {
console.log("[MONEY TREE] SPAWNING COINS...");
for (var i = 0; i < targetRecipients.length; i++){
var avatar = AvatarList.getAvatar(targetRecipients[i].nodeID);
var sum = Vec3.sum(avatar.position, Vec3.UP);
var userData = {
giverID: targetGiver.nodeID
};
coin[i] = Entities.addEntity({
type: "Box",
dimensions: { x: 0.5, y: 0.5, z: 0.5 },
name: "Money Tree Gift",
script: "https://hifi-content.s3.amazonaws.com/brosche/DomainContent/Hub/MoneyTree/moneyTreeClient.js",
userData: JSON.stringify(userData),
lifetime: 60,
position: sum,
visible: false,
collisionless: true,
parentID: avatar.sessionUUID
});
}
}
}
function pickAGiver(){
console.log("[MONEY TREE] PICKING GIVER");
// Choose a random user to display coins for giving
// Do not choose a user again until all other users in range have been selected.
indexGiver = randInt(0, userList.length-1);
if (indexGiver < 0){
return;
} else {
if (targetGiver){
if (userList[indexGiver].username === ""){
userList.splice(indexGiver, 1)[0];
if (indexGiver >= userList.length){
indexGiver = randInt(0, userList.length-1);
}
}
if (targetGiver.username !== userList[indexGiver].username){
targetGiver = userList[indexGiver];
} else {
indexGiver = randInt(0, userList.length-1);
targetGiver = userList[indexGiver];
}
} else {
targetGiver = userList[indexGiver];
}
}
}
function pickRecipients(){
console.log("[MONEY TREE] PICKING RECIPIENTS");
targetRecipients = [];
tempList = [];
tempList = userList.slice();
tempList.splice(indexGiver, 1)[0];
for (var i = 0; i < tempList.length; i++) {
if (tempList[i].staff === true) {
console.log("[MONEY TREE] removing staff", tempList[i].username);
tempList.splice(i,1)[0];
i--;
}
}
if (tempList.length < 2) {
console.log("[MONEY TREE] Not enough eligible recipients for receiver selection.");
Entities.editEntity(activeText, {text: "MOAR PPL PLZ"});
return;
}
var recipientCount = (tempList.length > RECIPIENT_MAX) ? RECIPIENT_MAX : tempList.length;
for (var i = 0; i < recipientCount; i++){
var index = randInt(0, tempList.length-1);
targetRecipients.push(tempList.splice(index-i, 1)[0]);
console.log("[MONEY TREE] recipient:", JSON.stringify(targetRecipients[i].username));
}
}
function randFloat(low, high) {
return low + Math.random() * (high - low);
}
function randInt(low, high) {
return Math.floor(randFloat(low, high));
}
function gaussian(mean, stdev) {
// returns a gaussian random function with the given mean and stdev.
var y2;
var useLast = false;
var y1;
if (useLast) {
y1 = y2;
useLast = false;
} else {
var x1, x2, w;
do {
x1 = 2.0 * Math.random() - 1.0;
x2 = 2.0 * Math.random() - 1.0;
w = x1 * x1 + x2 * x2;
} while ( w >= 1.0);
w = Math.sqrt((-2.0 * Math.log(w))/w);
y1 = x1 * w;
y2 = x2 * w;
useLast = true;
}
var retval = mean + stdev * y1;
if (retval > 0) {
return retval;
}
return -retval;
}
function sendInput(recipientUsername) {
// curl -X PUT -d authorization_id=<authorization ID from 1> -d coupon_id=<coupon ID from 1> -d username=steve https://highfidelity.com/api/v1/commerce/redeem;
var paramString = encodeURLParams({
date: new Date().toLocaleString(),
recipientUsername: recipientUsername,
amount: randomHFCAmount
});
var request = new XMLHttpRequest();
request.open('GET', googleURL + "?" + paramString);
request.timeout = 10000;
request.send();
}
function encodeURLParams(params) {
var paramPairs = [];
for (var key in params) {
paramPairs.push(key + "=" + params[key]);
}
return paramPairs.join("&");
}
function sweep(){
try {
var homelessParticles = Entities.findEntitiesByType("ParticleEffect", SEARCH_CENTER, SEARCH_AREA);
if (homelessParticles.length > 0) {
for (var i = 0; i < homelessParticles.length; i++ ) {
Entities.deleteEntity(homelessParticles[i]);
}
}
} catch (e) {
print("[MONEY TREE] particle sweep failed.");
return;
}
try {
var collect = Entities.findEntitiesByName("Coin Particle", SEARCH_CENTER, SEARCH_AREA);
if (collect.length > 0) {
for (var i = 0; i < collect.length; i++ ) {
Entities.editEntity(collect[i], { parentID: null });
Entities.deleteEntity(collect[i]);
}
}
if (coin.length > 0){
for (var i = 0; i < coin.length; i++ ) {
Entities.editEntity(coin[i], { parentID: null });
Entities.deleteEntity(coin[i]);
}
}
} catch (e) {
print("[MONEY TREE] entity sweep failed.");
return;
}
}
function startTree(){
interval = Script.setInterval(function(){
sweep();
Entities.editEntity(activeText, {text: "SEARCHING..."});
if (userList.length >= RECIPIENT_MAX){
randomHFCAmount = randomizeHFC();
if (randomHFCAmount === 0) {
Script.clearInterval(interval);
return;
}
pickAGiver();
console.log("[MONEY TREE] GIVER", JSON.stringify(targetGiver.username));
pickRecipients();
if (targetRecipients.length > 1) {
Entities.editEntity(activeText, {text: "OOH SHINY!"});
createCoinSpawner();
}
} else {
Entities.editEntity(activeText, {text: "MOAR PPL PLZ"});
}
}, randomizeInterval()*SHOW_TIME_LENGTH);
}
function appEnding() {
sweep();
Entities.deleteEntity(counterText);
Entities.deleteEntity(activeText);
if (interval){
Script.clearInterval(interval);
}
if (octreeInterval){
Script.clearInterval(octreeInterval);
}
Messages.unsubscribe(MONEY_TREE_CHANNEL);
Messages.messageReceived.disconnect(messageHandler);
}
startTree();
AvatarList.avatarRemovedEvent.connect(leftDomain);
Messages.subscribe(MONEY_TREE_CHANNEL);
Script.scriptEnding.connect(appEnding);
}());