// // The line above should be left blank to avoid script errors in OpenSim. /* * Part of the Sloodle project (www.sloodle.org) * * Copyright (c) 2011-06 contributors (see below) * Released under the GNU GPL v3 * ------------------------------------------- * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * All scripts must maintain this copyrite information, including the contributer information listed * * Developer: * Paul Preibisch * ******************************* * Description * ******************************* * * This buzzer script is free for use, and was designed for educators using virtual worlds * It has now become part of the SLOODLE project, and the AVATARCLASSROOM and licensed under GPL 3.0 * Basically, that means, you are free to use the script, commercially etc, but if you include * it in your objects, you must make the source viewable to the person you are distributuing it to - * ie: it can not be closed source - GPL 3.0 means - you must make it open! * * This is so that others can modify it and contribute back to the community. * The SLOODLE github can be found here: https://github.com/sloodle * Enjoy! * * This buzzer can be used for games which require contestants to "hit a buzzer" before * they can answer a question. To turn the buzzer ON, click on the green ON cylindar at the * base of the buzzer. A large mechanical arm with a big green click me button will appear. * Up to three contestants can hit the green cylindar by touching it. When they do * their names will be listed in order below, in 3 mechanical drawers which pop down * ******************************* * The Red Off Button * ******************************* * * The large Red Cylindar that says "Off" is used to deactivate clicking - so no user will be able * to click the buzzer. Click the "Off" button in between questions. When you have asked your question * you can click the green "On" button, so contestants can click it indicating that they want to answer the question * * ******************************** * The Green On Button * ******************************** * * Once you have asked your question, the teacher presses the green "on" button which * will automatically display a mechanical arm with a large green button attached that says * "Click Me" when a user clicks the green "Click Me" button, their name will be displayed * in a large rectangular drawer below the timer. Up to three students can click the green button * ******************************* * Using the Count Down Timer * ******************************* * * This buzzer also comes with a count down timer. * The teacher can press the green "start" button to start the count down, and the red "stop" button * to stop the countdown. This is useful in cases where the teacher wants to give the contestant a time limit in answering * a question. When the countdown reaches 5 seconds, there will be an audible beeping sound * and a big buzzer sound at when the buzzer reaches zero. * * ********************** * Setting the Timer * ********************** * * The teacher can set the timer by pressing the orange "Set Timer" button at the base of the buzzer, then * using the iphone like keypad to enter a new time. Press "Set Timer" once more when finished. Each time the user * presses a keypad, a new digit will be displayed on the surface of the timer, so it is * easy to see the digits that are being typed in. Note, if you make a mistake, there is a backspace key on the keypad * which you can press to erase the last digit. The number sign icon does nothing. * ******************* * HIDE BUTTON * ******************* * * Lastly, there is a large yellow cylindar that says "Hide" - use this to hide the large mechanical arm * in cases where a game is finished, or you simply want to use this buzzer as a count down timer. * When teacher is ready, they click the ball, it turns green indicating it is ready to be clicked, count down timer displays * ******************* * Sound Licenses.* ******************* * All sounds were sourced from the http://freesound.org website * please view their licences below * * Kodak Printer sound: http://www.freesound.org/samplesViewSingle.php?id=48667 * http://creativecommons.org/licenses/sampling+/1.0/ * nice.wav visit: http://www.freesound.org/samplesViewSingle.php?id=51488 * beepbeep.wav beep: http://www.freesound.org/samplesViewSingle.php?id=32683 */ key gSetupQueryId; //used for reading settings notecards list gInventoryList;//used for reading settings notecards string gSetupNotecardName="config";//used for reading settings notecards integer gSetupNotecardLine;//used for reading settings notecards integer SETTEXT_CHANNEL= -8882; integer SET_COLOR_CHANNEL=-889; integer SOUND_CHANNEL = -34000;//sound requests integer TIME_S = 0; integer TIME_M=1; integer TIME_H=0; integer keyPressCount; integer MAX_TIME; string editNum=""; integer SETTIMER=FALSE; string SHOWARM="HIDE"; string editM; string editS; string editH; string SLOODLE_EOF = "sloodleeof"; integer eof= FALSE; list winners; list winnerKeys; list sitters; list booths; string myName; integer buzzerButton;//to identify which link is the buzzerButton key myKey; list facilitators;//list of people who can control the buzzer integer PLUGIN_RESPONSE_CHANNEL =998822; //sloodle_api.lsl responses integer PLUGIN_CHANNEL =998821;//sloodle_api requests integer UI_CHANNEL =89997;//UI Channel - main channel integer ROW_CHANNEL; // *************************************************** HOVER TEXT COLORS vector RED = <0.77278, 0.04391, 0.00000>;//RED vector YELLOW = <0.82192, 0.86066, 0.00000>;//YELLOW vector GREEN = <0.12616, 0.77712, 0.00000>;//GREEN vector PINK = <0.83635, 0.00000, 0.88019>;//INDIGO vector WHITE = <1.000, 1.000, 1.000>;//WHITE integer MENU_CHANNEL; integer XY_1= -999821; integer XY_2= -999822; integer XY_3= -999823; integer XY_TIMER= -999824; integer XY_AWARD_NAME= -999825; integer counter; list modButs = ["+10","+30","-10","-30","+60","-60","+300","-300"]; list pointMods=["-5","-10","-100","-500","-1000","+5","+10","+100","+500","+1000","~~ SAVE ~~"]; //this is a list of values an owner can modify a users points to //["-5","-10","-100","-500","-1000","+5","+10","+100","+500","+1000", list modifyPointList; //this is a temp list that is used to store point modifications in. When Save is pressed on a menu, these points are applied to the users point bank integer modPoints; integer currentAwardId; string currentAwardName; list primNames; //deletes an item from a list list ListItemDelete(list mylist,string element_old) { integer placeinlist = llListFindList(mylist, [element_old]); if (placeinlist != -1){ return llDeleteSubList(mylist, placeinlist, placeinlist); } return mylist; }//listitemdelete //clear the timer screen clear(){ llMessageLinked(LINK_SET, XY_1," ", NULL_KEY); llMessageLinked(LINK_SET, XY_2," ", NULL_KEY); llMessageLinked(LINK_SET, XY_3," ", NULL_KEY); } //center the xy text s, which is of length len, and listens to channel center(string s,integer len,integer channel){ integer marginLen= (integer)(len-llStringLength((string)s))/2; integer j; string spaces=""; for (j=0;j"]); vector output= ; return output; }//end getVector rotation getRot(string vStr){ vStr=llGetSubString(vStr, 1, llStringLength(vStr)-2); list vStrList= llParseString2List(vStr, [","], ["<",">"]); rotation output= ; return output; }//end getRot /*********************************************************************************************** * s() k() i() and v() are used so that sending messages is more readable by humans. * Ie: instead of sending a linked message as * GETDATA|50091bcd-d86d-3749-c8a2-055842b33484 * Context is added with a tag: COMMAND:GETDATA|PLAYERUUID:50091bcd-d86d-3749-c8a2-055842b33484 * All these functions do is strip off the text before the ":" char and return a string ***********************************************************************************************/ string s (string ss){ return llList2String(llParseString2List(ss, [":"], []),1); }//end function key k (string kk){ return llList2Key(llParseString2List(kk, [":"], []),1); }//end function integer i (string ii){ return llList2Integer(llParseString2List(ii, [":"], []),1); }//end function vector v (string vv){ integer p = llSubStringIndex(vv, ":"); string vString = llGetSubString(vv, p+1, llStringLength(vv)); return getVector(vString); }//end function rotation r (string rr){ integer p = llSubStringIndex(rr, ":"); string rString = llGetSubString(rr, p+1, llStringLength(rr)); return getRot(rString); }//end function preloadSounds(){ key buzzer = "SND_BUZZER"; llPreloadSound(buzzer); key tick = "SND_TICK"; llPreloadSound(tick); key beepbeep = "SND_BEEPBEEP"; llPreloadSound(beepbeep); key onetype = "SND_TYPE"; llPreloadSound(onetype ); key ipress = "SND_IPRESS"; llPreloadSound(ipress ); key pd = "SND_POWER_DOWN"; llPreloadSound(pd ); key iopen = "cf218344-0251-6bfd-acba-fdd5534861b1"; llPreloadSound(iopen ); } /*********************************************** * isFacilitator() * |-->is this person's name in the access notecard ***********************************************/ integer isFacilitator(string avName){ if (llListFindList(facilitators, [llToLower(avName)])==-1) return FALSE; else return TRUE; } /*********************************************** * getMaxTime(integer seconds,integer minutes,integer hours) * |-->gets thenumber of seconds ***********************************************/ integer getSeconds(string seconds,string minutes,string hours){ integer timeLeft = i(seconds)+60*i(minutes)+3600*i(hours); return timeLeft; } /*********************************************** * getMaxTime(integer seconds,integer minutes,integer hours) * |-->gets thenumber of seconds and returns a formated list 00:00:00 ***********************************************/ string getTime(integer seconds){ integer hours = (integer)(seconds/3600); integer minutes = (integer)((seconds/60)- (hours*60)); integer s = (integer)(seconds%60); if (s ==60) { minutes+=1; s = 0; } if (minutes==60){ hours+=1; minutes=0; } string sString; string mString; string hString; if (llStringLength((string)s)==1) { sString= "0"+(string)s; }else sString = (string)s; if (llStringLength((string)minutes)==1) { mString= "0"+(string)minutes; }else mString = (string)minutes; if (llStringLength((string)hours)==1) { hString= "0"+(string)hours; }else hString = (string)hours; return hString+":"+mString+":"+sString; } /*********************************************** * random_integer() * |-->Produces a random integer ***********************************************/ integer random_integer( integer min, integer max ) { return min + (integer)( llFrand( max - min + 1 ) ); } string setTime; integer isconfigured=FALSE; integer newChannel; integer SLOODLE_CHANNEL_OBJECT_DIALOG = -3857343; // an arbitrary channel the sloodle scripts will use to talk to each other. Doesn't atter what it is, as long as the same thing is set in the sloodle_slave script. string time="00:00:00"; integer sloodle_handle_command(string str) { list bits = llParseString2List(str,["|"],[]); integer numbits = llGetListLength(bits); string name = llList2String(bits,0); string value1 = ""; string value2 = ""; if (numbits > 1) value1 = llList2String(bits,1); if (numbits > 2) value2 = llList2String(bits,2); if (name == "set:facilitator"){ facilitators+=llToLower(value1); }else if (name == "set:time"){ time= (string)value1; center(time,10,XY_TIMER); } else if (name == SLOODLE_EOF){ eof = TRUE; return (time != "00:00:00"); } return FALSE; } default { state_entry() { facilitators+=llToLower(llKey2Name(llGetOwner())); llTriggerSound("SND_STARTING_UP",1.0);//starting up MAX_TIME = TIME_S + TIME_M*60+TIME_H*3600; //get number of linked prims integer numPrims = llGetNumberOfPrims(); //find out which one is buzzer prim integer j; for (j=0;j<=numPrims;j++){ primNames +=llGetLinkName(j); }//endfor llMessageLinked(LINK_SET, 1, "p0",NULL_KEY); myName = llGetObjectName(); myKey = llGetKey(); MENU_CHANNEL = random_integer(2000,3000); ROW_CHANNEL=random_integer(2483000,3483000); state ready; }//end state_entry on_rez(integer start_param) { llResetScript(); } link_message( integer sender_num, integer num, string str, key id) { // Check the channel if (num == SLOODLE_CHANNEL_OBJECT_DIALOG) { // Split the message into lines list lines = llParseString2List(str, ["\n"], []); integer numlines = llGetListLength(lines); integer i = 0; for (i=0; i < numlines; i++) { isconfigured = sloodle_handle_command(llList2String(lines, i)); }if (isconfigured){ state ready; } } } changed(integer change) { // something changed if (change ==CHANGED_INVENTORY){ llResetScript(); }//endif } }//end default //waiting for teacher to touch it state ready{ on_rez(integer start_param) { llResetScript(); } state_entry() { llTriggerSound("SND_LOADING_COMPLETE", 1.0);//loading complete llOwnerSay("Ready! Click the green cylindar to engage the buzzer!\nPress the red cylindar to disengage the buzzer, and the yellow cylindar to hide it!"); integer j=0; integer len = llGetListLength(booths); /**************************************** * INITIALIZE *****************************************/ llSetTimerEvent(0); //move arm to waiting position llMessageLinked(LINK_SET, 1, "p1",NULL_KEY); winners=[]; winnerKeys=[]; modifyPointList=[0,0,0]; /**************************************** * PLAY SOUNDS *****************************************/ llTriggerSound("SND_FAST_KODAK", 1.0); /**************************************** * INIT DISPLAY *****************************************/ //center text //set hover text llMessageLinked(LINK_SET,SETTEXT_CHANNEL,"DISPLAY::top display|STRING::Ready:|COLOR::"+(string)RED+"|ALPHA::1.0",NULL_KEY); //clear text clear(); //set red llMessageLinked(LINK_SET,SET_COLOR_CHANNEL,"COMMAND:SET COLOR|PRIM:buzzer_button|COLOR:RED",NULL_KEY); }//end state_entry touch_start(integer num_detected) { //each prim that has a blink.lsl script in it, will set its glow to .90 for 1 second when this message is received integer j; for (j=0;j, <0.0, 0.0, 0.0>, 0.0 ]); llTriggerSound("SND_POWER_DOWN", 1.0);//power down llMessageLinked(LINK_SET, 1, "p1",NULL_KEY); SHOWARM="HIDE"; return; // }//SHOWARM }//endifndif else if (butName=="show_arm"){ SHOWARM="SHOW"; llMessageLinked(LINK_SET, UI_CHANNEL, "COMMAND:BLINK|PRIM:timer", NULL_KEY); llTriggerSound("SND_POWER_UP", 1.0); llSetLinkPrimitiveParams(getLink("buzzer_button"), [PRIM_COLOR, ALL_SIDES, GREEN, 1.0, PRIM_TEXTURE, 0, "click",<1.0, 1.0, 0.0>, <0.0, 0.0, 0.0>, 0.0 ]); llMessageLinked(LINK_SET, 1, "p2",NULL_KEY); llTriggerSound("SND_FAST_KODAK", 1.0);//fastkodak winners=[]; return; }//endif else if (butName=="hide_arm_button"){ SHOWARM="HIDE"; }//endif else if (butName=="stopwatch_button"){ llTriggerSound("SND_SPACE_CODE", 1.0);//SPACCODE buzzer button press llSetTimerEvent(0); SETTIMER=FALSE; return; }//endif else if (butName=="resetwatch_button"){ llTriggerSound("SND_SPACE_CODE", 1.0);//SPACCODE buzzer button press llSetTimerEvent(0); counter=0; MAX_TIME= TIME_S + TIME_M*60+TIME_H*3600; SETTIMER=FALSE; integer timeLeft = MAX_TIME-counter; string printTime = getTime(timeLeft); center(printTime,10,XY_TIMER); return; }//endif else if (butName=="startwatch_button"){ if (SETTIMER==TRUE){ TIME_S = (integer)llGetSubString(editNum, 6,7); TIME_M =(integer)llGetSubString(editNum, 3,4); TIME_H = (integer)llGetSubString(editNum, 0,1); SETTIMER==FALSE; } MAX_TIME= TIME_S + TIME_M*60+TIME_H*3600; llTriggerSound("SND_SPACE_CODE", 1.0);//SPACCODE buzzer button press llSetTimerEvent(1); return; }//endif else if (butName=="set_timer"){ llTriggerSound("SND_INTERFACE_PRESS", 1.0);//interface press llSetTimerEvent(0); keyPressCount=0; if (SETTIMER==TRUE){ //Sound source: http://www.freesound.org/samplesViewSingle.php?id=2329 //license: http://creativecommons.org/licenses/sampling+/1.0/ llTriggerSound("SND_CONFIRMED", 1.0);//confirmed TIME_S = (integer)llGetSubString(editNum, 6,7); TIME_M =(integer)llGetSubString(editNum, 3,4); TIME_H = (integer)llGetSubString(editNum, 0,1); MAX_TIME= TIME_S + TIME_M*60+TIME_H*3600; SETTIMER=FALSE; integer timeLeft = MAX_TIME-counter; string printTime = getTime(timeLeft); center(printTime,10,XY_TIMER); }else { editNum="00:00:00"; SETTIMER=TRUE; } return; }//endif else if (butName=="backspace"){ if (SETTIMER==TRUE){ if (llStringLength(editNum)==1) editNum=""; else editNum= llGetSubString(editNum,0,llStringLength(editNum)-2); llTriggerSound("SND_TYPE", 1.0);//one type center(editNum,10,XY_TIMER); }//SETTIMER return; }//backspace else if (llListFindList(["b1","b2","b3","b4","b5","b6","b7","b8","b9","b0"],[butName])!=-1){ if (SETTIMER==TRUE){ counter=0; keyPressCount++; string printTime =""; string num = llGetSubString(butName,1,1); if (keyPressCount==1) editNum =llGetSubString(editNum, 0, 6)+num; else if (keyPressCount==2) editNum =llGetSubString(editNum, 0, 5) +llGetSubString(editNum, 7, 7) + num; else if (keyPressCount==3) editNum =llGetSubString(editNum, 0, 3) +llGetSubString(editNum, 6, 6) +":" +llGetSubString(editNum, 7, 7) + num; else if (keyPressCount==4) editNum =llGetSubString(editNum, 0, 2) +llGetSubString(editNum, 4, 4) +llGetSubString(editNum, 6, 6) + ":" +llGetSubString(editNum, 7, 7) + num; else if (keyPressCount==5) editNum ="0"+llGetSubString(editNum, 3, 3) +":"+llGetSubString(editNum, 4, 4) +llGetSubString(editNum, 6, 6) + ":" +llGetSubString(editNum, 7, 7) + num; else if (keyPressCount==6) editNum =llGetSubString(editNum, 1, 1) +llGetSubString(editNum, 3, 3)+":" +llGetSubString(editNum, 4, 4) +llGetSubString(editNum, 6, 6) + ":" +llGetSubString(editNum, 7, 7) + num; setTime = editNum; center(editNum,10,XY_TIMER); llTriggerSound("SND_TYPE", 1.0);//one type }//SETTIMER==TRUE return; }//end if llListFind }//end if facilitator else if (butName!="buzzer_button") llSay(0,"Sorry, you need to be a facilitator to use this function. Facilitators are: "+(string)llList2CSV(facilitators)); /******************************************************** * Player clicks *********************************************************/ if (butName=="buzzer_button"){ // llSay(0,(string)llList2CSV(sitters)+"**********"+(string)llDetectedKey(0)); // if (llListFindList(sitters, [llDetectedKey(0)])!=-1){ //llMessageLinked(LINK_SET,SOUND_CHANNEL, "COMMAND:PLAYSOUND|SOUND:beep|SCRIPT_NAME:soundPlayer 1|VOLUME:1.0",NULL_KEY); integer printChannel; string userName=llDetectedName(j); key userKey = llDetectedKey(j); if (SHOWARM=="SHOW"){ // if (llListFindList(sitters, [llDetectedKey(0)])!=-1){ llMessageLinked(LINK_SET, UI_CHANNEL, "COMMAND:BLINK|PRIM:"+butName, NULL_KEY); //only 3 people are allowed to click if (llListFindList(winners, [userName])==-1){ //if hasnt been added, add to winners winners+=userName; winnerKeys+=userKey; //get number of winners integer numWinners = llGetListLength(winners); string anim="p3"; if (numWinners<4){ //play buzzer sound if one of the first 3 to click llTriggerSound("SND_GAME_BUZZER_HIT", 1.0);//game_show_buzzer_hit if (numWinners ==1){ printChannel=XY_1; anim = "p3"; }else if (numWinners ==2){ printChannel=XY_2; anim ="p4"; }else if (numWinners ==3){ printChannel=XY_3; anim ="p5"; } //only print username on scoreboard if one of the first 3 to click llMessageLinked(LINK_SET, printChannel,userName, NULL_KEY); //play animation llMessageLinked(LINK_SET, 1, anim,NULL_KEY); return; }//endif numWinners < 4 }//findlist winners // }//findlist sitters } //showarm // }//findlist sitters }//end if buttname } }//end touch timer() { //gets thenumber of seconds and returns a formated list 00:00:00 integer timeLeft = MAX_TIME-counter; string printTime = getTime(timeLeft); center(printTime,10,XY_TIMER); ++counter; if (timeLeft<5){ llTriggerSound("SND_BEEPBEEP", 1.0);//beep beepbeep beep }else llTriggerSound("SND_TICK", 1.0);//tick if (counter>MAX_TIME){ llSetTimerEvent(0.0); llMessageLinked(LINK_SET, 1, "bp0",NULL_KEY); counter=0; center("00:00:00",10,XY_TIMER); llTriggerSound("SND_BUZZER", 1.0);//buzzer } }//end timer changed(integer change) { // something changed if (change ==CHANGED_INVENTORY){ llResetScript(); }//endif } }//end state // Please leave the following line intact to show where the script lives in Git: // SLOODLE LSL Script Git Location: mod/gaming-1.0/objects/gamebuzzer/assets/game_buzzer.lslp