Table of Contents

Change Log

1 November 2014

  • Rewrote the script to use multiple notecards and include a configuration notecard.

Introduction

This is a simple town crier, probably best suited for role-play SIMs however it could be used for any location where updates and news have to be broadcasted on the SIM. The script uses a configuration file such that different parameters can be configured.

Setup

To set it up, you will need to create a notecard called configuration and drop it along with the script inside the same primitive. An example documented configuration notecard is the following:

########################### START CONFIGURATION ##############################

# the amount of time in seconds between the shout-outs
interval = 60
# whether to randomize the interval so that a speak can occur between [0.045, interval] seconds.
randomize = true

# list of avatars that are able to toggle the town crier on and off
access = Morgan LeFay, Frank Black

# sound level can be region, shout, say or whisper
level = say

# channel to say the message on (0 is local chat)
# note that if you set level to region, then the channel cannot be 0
channel = 0

########################### END CONFIGURATION ###############################

After that, you can create any number of notecards named sequentially, something like:

crier_1
crier_2

and inside those notecards you can add lines that the town crier will speak.

Code

town_crier.lsl
///////////////////////////////////////////////////////////////////////////
//  Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3      //
//  Please see: http://www.gnu.org/licenses/gpl.html for legal details,  //
//  rights of fair usage, the disclaimer and warranty conditions.        //
///////////////////////////////////////////////////////////////////////////
 
// for notecard reading
integer line = 0;
key request = NULL_KEY;
 
// key-value data will be read into this list
list tuples = [];
 
// town cries
list cards = [];
integer size = 0;
string card = "";
 
default {
    state_entry() {
        if(llGetInventoryType("configuration") != INVENTORY_NOTECARD) {
            llSay(DEBUG_CHANNEL, "Sorry, could not find a configuration notecard in the inventory.");
            return;
        }
        request = llGetNotecardLine("configuration", line);
    }
    dataserver(key id, string data) {
        if(id != request) return;
        if(data == EOF) state read; // invariant, length(tuples) % 2 == 0
        if(data == "") jump continue;
        integer i = llSubStringIndex(data, "#");
        if(i != -1) data = llDeleteSubString(data, i, -1);
        list o = llParseString2List(data, ["="], []);
        string k = llStringTrim(llList2String(o, 0), STRING_TRIM);
        string v = llStringTrim(llList2String(o, 1), STRING_TRIM);
        if(k == "" || v == "") jump continue;
        tuples += k;
        tuples += v;
@continue;
        request = llGetNotecardLine("configuration", ++line);
    }
    on_rez(integer num) {
        llResetScript();
    }
    changed(integer change) {
        if(change & CHANGED_INVENTORY)
            llResetScript();
    }
}
 
state read {
    state_entry() {
        integer i = llGetInventoryNumber(INVENTORY_NOTECARD)-1;
        do {
            string name = llGetInventoryName(INVENTORY_NOTECARD, i);
            if(llList2String(llParseString2List(name, ["_"], []), 0) != "cries")
                jump continue;
            cards += name;
@continue;
        } while(--i>-1);
        if(llGetListLength(cards) == 0) {
            llSay(DEBUG_CHANNEL, "No cries notecards in the inventory.");
            return;
        }
        state sleep;
    }
    on_rez(integer num) {
        llResetScript();
    }
    changed(integer change) {
        if(change & CHANGED_INVENTORY)
            llResetScript();
    }
}
 
state sleep {
    state_entry() {
        integer time = llList2Integer(
            tuples, 
            llListFindList(
                tuples, 
                (list)"interval"
            ) + 1
        );
        if(
            llToLower(
                llList2String(
                    tuples, 
                    llListFindList(
                        tuples, 
                        (list)"randomize"
                    ) + 1
                )
            ) == "true") {
            llSetTimerEvent(0.045 + llFrand(time));
            return;
        }
        llSetTimerEvent(time);
    }
    timer() {
        llSetTimerEvent(0);
        state select;
    }
    touch_start(integer num) {
        string name = llToLower(llDetectedName(0));
        list access = llParseString2List(
            llList2String(
                tuples, 
                llListFindList(
                    tuples, 
                    (list)"access"
                )+1
            ), [","], []
        );
        do {
            if(llToLower(llStringTrim(llList2String(access, 0), STRING_TRIM)) == name) {
                // authorized
                jump menu;
            }
            access = llDeleteSubList(access, 0, 0);
        } while(llGetListLength(access) != 0);
        return;
@menu;
        key id = llDetectedKey(0);
        integer channel = (integer)("0x8" + llGetSubString(llGetKey(), 0, 6));
        llListen(channel, "", id, "");
        llDialog(id, "\n                            Town Crier.\n\nCreated in 2014 by Wizardry and Steamworks\n            1 November 2014: Version: 1.1", [  "◉ ON" ], channel);
    }
    listen(integer channel, string name, key id, string message) {
        if(message == "◉ ON") {
            llSay(0, "The Town Crier is now switched OFF.");
            state pause;
        }
    }
    on_rez(integer num) {
        llResetScript();
    }
    changed(integer change) {
        if(change & CHANGED_INVENTORY)
            llResetScript();
    }
}
 
state select {
    state_entry() {
        card = llList2String(
            cards, 
            (integer)llFrand(
                llGetListLength(
                    cards
                )
            )
        );
        request = llGetNumberOfNotecardLines(card);
    }
    dataserver(key id, string data) {
        if(id != request) return;
        if(data == "") state sleep;
        size = (integer)data;
        state cry;
    }
    on_rez(integer num) {
        llResetScript();
    }
    changed(integer change) {
        if(change & CHANGED_INVENTORY)
            llResetScript();
    }
}
 
state cry {
    state_entry() {
        request = llGetNotecardLine(card, (integer)llFrand(size));
    }
    dataserver(key id, string data) {
        if(id != request) return;
        if(data == "") state sleep;
        string level = llToLower(
            llList2String(
                tuples, 
                llListFindList(
                    tuples, 
                    (list)"level"
                )+1
            )
        );
        integer channel = llList2Integer(
            tuples, 
            llListFindList(
                tuples, 
                (list)"channel"
            )+1
        );
        if(level == "region") {
            if(channel != 0) {
                llRegionSay(channel, data);
                jump done;
            }
            llSay(DEBUG_CHANNEL, "Channel cannot be zero for region say.");
            jump done;
        }
        if(level == "shout") {
            llShout(0, data);
            jump done;
        }
        if(level == "say") {
            llSay(0, data);
            jump done;
        }
        if(level == "whisper") {
            llWhisper(0, data);
            jump done;
        }
@done;
        state sleep;
    }
    on_rez(integer num) {
        llResetScript();
    }
    changed(integer change) {
        if(change & CHANGED_INVENTORY)
            llResetScript();
    }
}
 
state pause {
    touch_start(integer num) {
        string name = llToLower(llDetectedName(0));
        list access = llParseString2List(
            llList2String(
                tuples, 
                llListFindList(
                    tuples, 
                    (list)"access"
                )+1
            ), [","], []
        );
        do {
            if(llToLower(llStringTrim(llList2String(access, 0), STRING_TRIM)) == name) {
                // authorized
                jump menu;
            }
            access = llDeleteSubList(access, 0, 0);
        } while(llGetListLength(access) != 0);
        return;
@menu;
        key id = llDetectedKey(0);
        integer channel = (integer)("0x8" + llGetSubString(llGetKey(), 0, 6));
        llListen(channel, "", id, "");
        llDialog(id, "\n                            Town Crier.\n\nCreated in 2014 by Wizardry and Steamworks\n            1 November 2014: Version: 1.1", [  "◯ OFF" ], channel);
    }
    listen(integer channel, string name, key id, string message) {
        if(message == "◯ OFF") {
            llSay(0, "The Town Crier is now switched ON.");
            state pause;
        }
    }
    on_rez(integer num) {
        llResetScript();
    }
    changed(integer change) {
        if(change & CHANGED_INVENTORY)
            llResetScript();
    }
}

secondlife/town_crier.txt · Last modified: 2022/11/24 07:46 by 127.0.0.1

Access website using Tor Access website using i2p Wizardry and Steamworks PGP Key


For the contact, copyright, license, warranty and privacy terms for the usage of this website please see the contact, license, privacy, copyright.