The prism contains one single script.
/////////////////////////////////////////////////////////////////////////// // Copyright (C) Wizardry and Steamworks 2022 - License: GNU GPLv3 // // Please see: http://www.gnu.org/licenses/gpl.html for legal details, // // rights of fair usage, the disclaimer and warranty conditions. // /////////////////////////////////////////////////////////////////////////// // Patent WO2001046821A1 by Yanon Volcani & David B. Fogel // /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 // /////////////////////////////////////////////////////////////////////////// string wasListToCSV(list l) { list v = []; do { string a = llDumpList2String( llParseStringKeepNulls( llList2String( l, 0 ), ["\""], [] ), "\"\"" ); if(llParseStringKeepNulls( a, [" ", ",", "\n", "\""], [] ) != (list) a ) a = "\"" + a + "\""; v += a; l = llDeleteSubList(l, 0, 0); } while(l != []); return llDumpList2String(v, ","); } /////////////////////////////////////////////////////////////////////////// // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 // /////////////////////////////////////////////////////////////////////////// list wasCSVToList(string csv) { list l = []; list s = []; string m = ""; do { string a = llGetSubString(csv, 0, 0); csv = llDeleteSubString(csv, 0, 0); if(a == "") { jump continue; } if(a == ",") { if(llList2String(s, -1) != "\"") { l += m; m = ""; jump continue; } m += a; jump continue; } if(a == "\"" && llGetSubString(csv, 0, 0) == a) { m += a; csv = llDeleteSubString(csv, 0, 0); jump continue; } if(a == "\"") { if(llList2String(s, -1) != a) { s += a; jump continue; } s = llDeleteSubList(s, -1, -1); jump continue; } m += a; @continue; } while(csv != ""); // postcondition: length(s) = 0 if(llStringLength(m) == 0) { return l; } return l + m; } /////////////////////////////////////////////////////////////////////////// // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 // /////////////////////////////////////////////////////////////////////////// string wasKeyValueGet(string k, string data) { if(llStringLength(data) == 0) return ""; if(llStringLength(k) == 0) return ""; list a = llParseStringKeepNulls(data, ["&", "="], []); integer i = llListFindList(llList2ListStrided(a, 0, -1, 2), [ k ]); if(i != -1) return llList2String(a, 2*i+1); return ""; } /////////////////////////////////////////////////////////////////////////// // Copyright (C) 2014 Wizardry and Steamworks - License: CC BY 2.0 // /////////////////////////////////////////////////////////////////////////// string wasKeyValueSet(string k, string v, string data) { if(llStringLength(k) == 0) return ""; if(llStringLength(v) == 0) return ""; if(llStringLength(data) == 0) return k + "=" + v; integer i = llListFindList( llList2ListStrided( llParseString2List(data, ["&", "="], []), 0, -1, 2 ), [ k ]); if(i != -1) return llDumpList2String( llListReplaceList( llParseString2List(data, ["&"], []), [ k + "=" + v ], i, i), "&"); return data + "&" + k + "=" + v; } list BASIC_EMOTIONS = [ "anger", "disgust", "fear", "happiness", "sadness", "surprise" ]; string emotions; list words = []; // for notecard reading integer line; // key-value data will be read into this list list tuples; integer channel; string exception; default { state_entry() { llParticleSystem( [ PSYS_SRC_TEXTURE, ".compute", PSYS_PART_START_SCALE, < .7, .7, 0 >, 6, < .7, .7, 0 >, PSYS_PART_START_COLOR, <1, 1, 1>, PSYS_PART_END_COLOR, <1, 1, 1>, PSYS_PART_START_ALPHA, .1, PSYS_PART_END_ALPHA, .002, PSYS_SRC_BURST_PART_COUNT, 0x7FFFFFFF, PSYS_PART_MAX_AGE, 0.2, PSYS_SRC_MAX_AGE, 0, PSYS_SRC_PATTERN, (integer)4, PSYS_SRC_BURST_SPEED_MIN, 0, PSYS_SRC_BURST_SPEED_MAX, 0, PSYS_SRC_ANGLE_BEGIN, (float)0.03 * 3.141593, PSYS_SRC_ANGLE_END, (float)0 * 3.141593, 8, ZERO_VECTOR, PSYS_PART_FLAGS, (integer)( 0 | 1 | PSYS_PART_EMISSIVE_MASK ) ] ); state configure; } } state configure { state_entry() { if(llGetInventoryType("configuration") != INVENTORY_NOTECARD) { exception = "No \"configuration\" notecard."; state fault; } line = 0; tuples = []; llGetNotecardLine("configuration", line); } dataserver(key id, string data) { if(data == EOF) { // invariant, length(tuples) % 2 == 0 if(llGetListLength(tuples) % 2 != 0) { exception = "Configuration notecard broken."; state fault; } integer j = llGetListLength(BASIC_EMOTIONS) - 1; do { integer i = llGetListLength(tuples) - 1; do { string n = llList2String(tuples, i); string e = llList2String(BASIC_EMOTIONS, j); if(llSubStringIndex(n, e + "_") != -1) { list l = llParseString2List(n, ["_"], []); if(llList2String(l, 0) == e) { string word = llToLower( llList2String( tuples, llListFindList( tuples, [ e + "_" + llList2String(l, 1) ] ) + 1 ) ); string store = wasKeyValueGet( e, emotions ); list rem = wasCSVToList(store); if(llListFindList(rem, (list)e) == -1) { list s = wasCSVToList(word); integer k = llGetListLength(s) - 1; do { string sig = llList2String(s, k); if(llListFindList(rem, (list)sig) == -1) { rem += llList2String(s, k); } } while(--k > -1); } store = wasListToCSV(rem); emotions = wasKeyValueSet( e, store, emotions ); } } } while(--i > -1); } while(--j > -1); state hearing; } if(data == "") jump continue; integer i = llSubStringIndex(data, "#"); if(i != -1) data = llDeleteSubString(data, i, -1); list o = llParseString2List(data, ["="], []); // get rid of starting and ending quotes string k = llDumpList2String( llParseString2List( llStringTrim( llList2String( o, 0 ), STRING_TRIM), ["\""], [] ), "\""); string v = llDumpList2String( llParseString2List( llStringTrim( llList2String( o, 1 ), STRING_TRIM), ["\""], [] ), "\""); if(k == "" || v == "") jump continue; tuples += k; tuples += v; @continue; llGetNotecardLine("configuration", ++line); } on_rez(integer num) { llResetScript(); } changed(integer change) { if(change & CHANGED_INVENTORY) { llResetScript(); } } } state hearing { state_entry() { channel = llListen(0, "", "", ""); llParticleSystem( [ PSYS_SRC_TEXTURE, ".listen", PSYS_PART_START_SCALE, < .7, .7, 0 >, 6, < .7, .7, 0 >, PSYS_PART_START_COLOR, <1, 1, 1>, PSYS_PART_END_COLOR, <1, 1, 1>, PSYS_PART_START_ALPHA, .1, PSYS_PART_END_ALPHA, .002, PSYS_SRC_BURST_PART_COUNT, 0x7FFFFFFF, PSYS_PART_MAX_AGE, 0.2, PSYS_SRC_MAX_AGE, 0, PSYS_SRC_PATTERN, (integer)4, PSYS_SRC_BURST_SPEED_MIN, 0, PSYS_SRC_BURST_SPEED_MAX, 0, PSYS_SRC_ANGLE_BEGIN, (float)0.03 * 3.141593, PSYS_SRC_ANGLE_END, (float)0 * 3.141593, 8, ZERO_VECTOR, PSYS_PART_FLAGS, (integer)( 0 | 1 | PSYS_PART_EMISSIVE_MASK ) ] ); } listen(integer channel, string name, key id, string message) { llSetTimerEvent(0); words = llParseString2List( message, [ " ", ",", "|", "\"", "'", "!", "?", ";", "-", ".", "\n", "\r" ], [""] ); state compute; } timer() { llSetTimerEvent(0); llParticleSystem( [ PSYS_SRC_TEXTURE, ".listen", PSYS_PART_START_SCALE, < .7, .7, 0 >, 6, < .7, .7, 0 >, PSYS_PART_START_COLOR, <1, 1, 1>, PSYS_PART_END_COLOR, <1, 1, 1>, PSYS_PART_START_ALPHA, .1, PSYS_PART_END_ALPHA, .002, PSYS_SRC_BURST_PART_COUNT, 0x7FFFFFFF, PSYS_PART_MAX_AGE, 0.2, PSYS_SRC_MAX_AGE, 0, PSYS_SRC_PATTERN, (integer)4, PSYS_SRC_BURST_SPEED_MIN, 0, PSYS_SRC_BURST_SPEED_MAX, 0, PSYS_SRC_ANGLE_BEGIN, (float)0.03 * 3.141593, PSYS_SRC_ANGLE_END, (float)0 * 3.141593, 8, ZERO_VECTOR, PSYS_PART_FLAGS, (integer)( 0 | 1 | PSYS_PART_EMISSIVE_MASK ) ] ); } on_rez(integer num) { llResetScript(); } changed(integer change) { if(change & CHANGED_INVENTORY) { llResetScript(); } } state_exit() { llSetTimerEvent(0); llListenRemove(channel); } } state compute { state_entry() { llParticleSystem( [ PSYS_SRC_TEXTURE, ".compute", PSYS_PART_START_SCALE, < .7, .7, 0 >, 6, < .7, .7, 0 >, PSYS_PART_START_COLOR, <1, 1, 1>, PSYS_PART_END_COLOR, <1, 1, 1>, PSYS_PART_START_ALPHA, .1, PSYS_PART_END_ALPHA, .002, PSYS_SRC_BURST_PART_COUNT, 0x7FFFFFFF, PSYS_PART_MAX_AGE, 0.2, PSYS_SRC_MAX_AGE, 0, PSYS_SRC_PATTERN, (integer)4, PSYS_SRC_BURST_SPEED_MIN, 0, PSYS_SRC_BURST_SPEED_MAX, 0, PSYS_SRC_ANGLE_BEGIN, (float)0.03 * 3.141593, PSYS_SRC_ANGLE_END, (float)0 * 3.141593, 8, ZERO_VECTOR, PSYS_PART_FLAGS, (integer)( 0 | 1 | PSYS_PART_EMISSIVE_MASK ) ] ); list score = [ 0, 0, 0, 0, 0, 0 ]; // loop over local chat words integer i = llGetListLength(words) - 1; do { string word = llToLower( llList2String( words, i ) ); // loop over all emotions integer j = llGetListLength(BASIC_EMOTIONS) - 1; do { string emotion = llList2String( BASIC_EMOTIONS, j ); list emotive = wasCSVToList( wasKeyValueGet( emotion, emotions ) ); integer v = llListFindList(emotive, (list)word); if(v != -1) { integer x = llListFindList( BASIC_EMOTIONS, [ emotion ] ); integer c = llList2Integer( score, x ); score = llListReplaceList( score, [ c + 1 ], x, x ); } } while(--j > -1); } while(--i > -1); // DEBUG //llOwnerSay(llDumpList2String(score, "|")); if(llListStatistics(LIST_STAT_SUM, score) == 0) { llParticleSystem( [ PSYS_SRC_TEXTURE, ".listen", PSYS_PART_START_SCALE, < .7, .7, 0 >, 6, < .7, .7, 0 >, PSYS_PART_START_COLOR, <1, 1, 1>, PSYS_PART_END_COLOR, <1, 1, 1>, PSYS_PART_START_ALPHA, .1, PSYS_PART_END_ALPHA, .002, PSYS_SRC_BURST_PART_COUNT, 0x7FFFFFFF, PSYS_PART_MAX_AGE, 0.2, PSYS_SRC_MAX_AGE, 0, PSYS_SRC_PATTERN, (integer)4, PSYS_SRC_BURST_SPEED_MIN, 0, PSYS_SRC_BURST_SPEED_MAX, 0, PSYS_SRC_ANGLE_BEGIN, (float)0.03 * 3.141593, PSYS_SRC_ANGLE_END, (float)0 * 3.141593, 8, ZERO_VECTOR, PSYS_PART_FLAGS, (integer)( 0 | 1 | PSYS_PART_EMISSIVE_MASK ) ] ); state hearing; } // look for the most dominant emotion i = llGetListLength(score) - 1; integer x = 0; integer k = 0; do { integer j = llList2Integer( score, i ); if(j > x) { x = j; k = i; } } while(--i > -1); string dominant = llList2String( BASIC_EMOTIONS, k ); llParticleSystem( [ PSYS_SRC_TEXTURE, dominant, PSYS_PART_START_SCALE, < .7, .7, 0 >, 6, < .7, .7, 0 >, PSYS_PART_START_COLOR, <1, 1, 1>, PSYS_PART_END_COLOR, <1, 1, 1>, PSYS_PART_START_ALPHA, .1, PSYS_PART_END_ALPHA, .002, PSYS_SRC_BURST_PART_COUNT, 0x7FFFFFFF, PSYS_PART_MAX_AGE, 0.2, PSYS_SRC_MAX_AGE, 0, PSYS_SRC_PATTERN, (integer)4, PSYS_SRC_BURST_SPEED_MIN, 0, PSYS_SRC_BURST_SPEED_MAX, 0, PSYS_SRC_ANGLE_BEGIN, (float)0.03 * 3.141593, PSYS_SRC_ANGLE_END, (float)0 * 3.141593, 8, ZERO_VECTOR, PSYS_PART_FLAGS, (integer)( 0 | 1 | PSYS_PART_EMISSIVE_MASK ) ] ); llSetTimerEvent(7); } timer() { state hearing; } on_rez(integer num) { llResetScript(); } changed(integer change) { if(change & CHANGED_INVENTORY) { llResetScript(); } } state_exit() { llSetTimerEvent(0); } } state fault { state_entry() { llSetText(exception, <1,1,1>, 1.0); llParticleSystem( [ PSYS_SRC_TEXTURE, ".missing", PSYS_PART_START_SCALE,<0.2, 0.2, 0>, PSYS_PART_END_SCALE,<0.2, 0.2, 0>, PSYS_PART_START_COLOR,<1, 1, 1>, PSYS_PART_END_COLOR,<1,1,1>, PSYS_PART_START_ALPHA,1, PSYS_PART_END_ALPHA, 1, PSYS_SRC_BURST_PART_COUNT, 1, 13, 0.5, PSYS_PART_MAX_AGE,.3, PSYS_SRC_MAX_AGE, 0.0, PSYS_SRC_PATTERN, 4, PSYS_SRC_BURST_SPEED_MIN, 0.0, 18, 0.0, 22, 0.03*3.141593, PSYS_SRC_ANGLE_END, 0*3.141593, 8,<0.0,0.0,0>, 0,(0|1|PSYS_PART_EMISSIVE_MASK) ] ); } on_rez(integer num) { state default; } attach(key id) { state default; } changed(integer change) { state default; } state_exit() { llSetText("", <0, 0, 0>, 0.0); } }
There are six textures included inside the prism, one for each sentiment plus three other control textures: for thinking .compute
, for listening .listen
and to indicate a fault .missing
.
There is one single notecard included inside the prism named configuration
with the following default contents:
anger_1 = fury,hate,hostile,loathe,resent,scorn,spite,vengeful,wrath,annoy,bit,hit,bite,wrath,blame,angry,anger,beat anger_2 = rage,kill,nerves,crime,disgust,revulsion,bitter,mad,insult,mean,fight,brawl,fuck,cunt,damn,break,no disgust_1 = yuck,eww,icky,ugly,disgust,dislike,revulsion,smelly,mud,slime,garbage,trash,sticky,shit,piss disgust_2 = crap,stupid,terrible,sick,horror,nasty,crazy,hell fear_1 = danger,alert,alarm,fear,fright,horror,hysteria,panic,shock,terror,nervous,anxious,scare,panic,stress fear_2 = help,run,dead,afraid,die,death,hot,burning,lie,murder,ow,prison,torment happiness_1 = yay,happy,joy,cool,like,pleasure,amuse,pride,awe,excite,great,care,friend,fun,glad,funny,love happiness_2 = laugh,chuckle,smile,grin,cheer,good,well,okay,nice,heaven,hope,heart,safe,light,calm,ok,yes sadness_1 = sad,unhappy,sigh,sorrow,depression,despair,gloom,grief,hopeless,misery,woe,cry,guilt sadness_2 = regret,remorse,lonely,sorry,hurt,trouble,worry,upset,dark,bad,broken surprise_1 = surprise,magic,trick,amaze,gawk,suddenly,lucky,greet,pop,shock,slip,hoax,candid,bang,exclaim,boo surprise_2 = greet,hello,happen,hi,wow,amazing,amazed,concern,surprised
Words can be mapped to different sentiments just by adding them to the various sentiment list. In order to work around Linden Lab limitations of maximal notecard lines, each of the sentiment lists can be extended by following the naming convention. For instance, in order to extend the surprise
list of words, the following pattern should be used:
surprise_1
,surprise_2
,surprise_3
,