Myriad Lite Character Designer

INCOMPLETE

// Myriad_Lite_Character_Designer-v0.0.0-20131219.lsl
// Copyright (c) 2013 by Allen Kerensky (OSG/SL) All Rights Reserved.
// This work is dual-licensed under
// Creative Commons Attribution (CC BY) 3.0 Unported
// http://creativecommons.org/licenses/by/3.0/
// - or -
// Modified BSD License (3-clause)
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright notice, 
//   this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
// * Neither the name of Myriad Lite nor the names of its contributors may be
//   used to endorse or promote products derived from this software without
//   specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
// NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// The Myriad RPG System was designed, written, and illustrated by Ashok Desai
// Myriad RPG System licensed under:
// Creative Commons Attribution (CC BY) 2.0 UK: England and Wales
// http://creativecommons.org/licenses/by/2.0/uk/
 
// CONSTANTS - DO NOT CHANGE DURING RUN
string BASENAME = "Myriad Lite Character Designer"; // base name of this script without version or date
string VERSION = "0.0.1"; // Allen Kerensky's script version
string VERSIONDATE = "20131219"; // Allen Kerensky's script yyyymmdd
 
// CHARACTER DESIGNER STORAGE
list PRIMNAMES;
list CATEGORIES = [ "NAMES","NIKCNAMES","TITLES","FACTIONS","SPECIES","BACKGROUNDS","CAREERS",
"STATISTICS","RESILIENCES","BOONS","FLAWS","SKILLS","EFFECTS","STUNTS","QUOTES","ITEMS" ];
integer NUMCAT; // number of category in CATEGORIES list
string CURCAT; // name of current category
integer NUMITEM; // number of item in current REGION_LIST 
string CURITEM; // name of current item in current category list
integer MY_DYN; // the character designer dynamic channel
integer MY_HAND; // the character designer dynamic channel handle
integer MENU_DYN; // the character designer dialogs dynamic channel
integer MENU_HAND; // the character designer dialogs dynamic channel handle
string REQUEST; // current request to dispatch
 
// REGION SETTING SERVER STORAGE
integer REGION_DYN; // the region server dynamic channel
integer REGION_HAND; // the region server dynamic channel handle
list REGION_LIST; // CSV list of items in current category - requested from region setting server
 
// PLAYER STORAGE
integer PLAYER_DYN; // the player's HUD dynamic channel
integer PLAYER_HAND; // the player HUD dynamic channel handle
key WHO; // who is using the setup
list PLAYER_LIST; // list of player attributes in current aspect/category
 
BUY_ITEM() {
}
 
COMMAND(string in) {
    if ( in == "BUTTON_NEW" ) {
        if ( REQUEST == "NAMES" ) { SET_NAME(); return; }
        if ( REQUEST == "NICKNAMES" ) { SET_NICKNAME(); return; }
        if ( REQUEST == "TITLES" ) { SET_TITLE(); return; }
        if ( REQUEST == "FACTIONS" ) { SET_FACTION(); return; }
    }
 
    REQUEST=in;
    if ( in == "NAMES" ) { GET_NAME(WHO); return; }
    if ( in == "NICKNAMES" ) { GET_NICKNAME(WHO); return; }
    if ( in == "TITLES" ) { GET_TITLE(WHO); return; }
    if ( in == "FACTIONS" ) { GET_FACTION(WHO); return; }
    // locate category name from list
    if ( llListFindList(CATEGORIES,[in]) != -1 ) {
        CURCAT = in;
        NUMITEM = 0;
        UPDATE();
        llRegionSay(REGION_DYN,"LIST_"+CURCAT);
        return;
    }
    if ( in == "FIRST_CATEGORY") { FIRST_CATEGORY(); return;}
    if ( in == "FIRST_ITEM" ) { FIRST_ITEM(); return; }
    if ( in == "PREV_CATEGORY" ) { PREV_CATEGORY(); return; }
    if ( in == "PREV_ITEM" ) { PREV_ITEM(); return; }
    if ( in == "NEXT_CATEGORY" ) { NEXT_CATEGORY(); return; }
    if ( in == "NEXT_ITEM" ) { NEXT_ITEM(); return; }
    if ( in == "LAST_CATEGORY" ) { LAST_CATEGORY(); return; }
    if ( in == "LAST_ITEM" ) { LAST_ITEM(); return; }
    if ( in == "BUY ITEM" ) { BUY_ITEM(); return; }
    if ( in == "SELL ITEM" ) { SELL_ITEM(); return; }
    if ( in == "RESET" ) { RESET(); return; }
    if ( in == "SAVE" ) { SAVE(); return; }
}
 
FIRST_CATEGORY() {
    NUMCAT = 0;
    CURCAT = llList2String(CATEGORIES,NUMCAT);
    NUMITEM = 0;
    llRegionSay(REGION_DYN,"LIST_"+CURCAT);
}
 
FIRST_ITEM() {
    NUMITEM = 0;
    CURITEM = llList2String(REGION_LIST,NUMITEM);
    UPDATE();
}
 
GET_FACTION(key id) {
    integer chan = (integer)("0x" + llGetSubString(id,0,6));
    llRegionSay(chan,"GET_FACTION");
}
 
GET_NAME(key id) {
    integer chan = (integer)("0x" + llGetSubString(id,0,6));
    llRegionSay(chan,"GET_NAME");
}
 
GET_NICKNAME(key id) {
    integer chan = (integer)("0x" + llGetSubString(id,0,6));
    llRegionSay(chan,"GET_NICKNAME");
}
 
GET_TITLE(key id) {
    integer chan = (integer)("0x" + llGetSubString(id,0,6));
    llRegionSay(chan,"GET_TITLE");
}
 
LAST_CATEGORY() {
    NUMCAT = llGetListLength(CATEGORIES) - 1;
    CURCAT = llList2String(CATEGORIES,NUMCAT);
    NUMITEM = 0;
    llRegionSay(REGION_DYN,"LIST_"+CURCAT);
}
 
LAST_ITEM() {
    NUMITEM = llGetListLength(REGION_LIST) - 1;
    CURITEM = llList2String(REGION_LIST,NUMITEM);
    UPDATE();
}
 
NEXT_CATEGORY() {
    NUMCAT++;
    if ( NUMCAT >= llGetListLength(CATEGORIES) ) NUMCAT = 0;
    CURCAT = llList2String(CATEGORIES,NUMCAT);
    NUMITEM = 0;
    llRegionSay(REGION_DYN,"LIST_"+CURCAT);
}
 
NEXT_ITEM() {
    NUMITEM++;
    if ( NUMITEM >= llGetListLength(REGION_LIST) ) NUMITEM = 0;
    CURITEM = llList2String(REGION_LIST,NUMITEM);
    UPDATE();
}
 
PREV_CATEGORY() {
    NUMCAT--;
    if ( NUMCAT < 0 ) NUMCAT = llGetListLength(CATEGORIES) - 1;
    CURCAT = llList2String(CATEGORIES,NUMCAT);
    NUMITEM = 0;
    llRegionSay(REGION_DYN,"LIST_"+CURCAT);
}
 
PREV_ITEM() {
    NUMITEM--;
    if ( NUMITEM < 0 ) NUMITEM = llGetListLength(REGION_LIST) - 1;
    CURITEM = llList2String(REGION_LIST,NUMITEM);
    UPDATE();
}
 
RESET() {
    // do things
    llStopAnimation("turn_180");
    llUnSit(llAvatarOnSitTarget());
}
 
SAVE() {
}
 
SELL_ITEM() {
}
 
SET_FACTION() {
    if ( MENU_HAND == 0 ) {
        MENU_DYN = 1+(integer)llFrand(9999.0);
        MENU_HAND = llListen(MENU_DYN,"",NULL_KEY,"");
        llTextBox(llDetectedKey(0),"(Optional) What Is Your Character's Faction?\rYou have 60 seconds to enter a name.",MENU_DYN);
        llSetTimerEvent(60.0);
    } else {
        llSay(PUBLIC_CHANNEL,"Tool is already in use, please wait.");
    }
}
 
SET_NAME() {
    if ( MENU_HAND == 0 ) {
        MENU_DYN = 1+(integer)llFrand(9999.0);
        MENU_HAND = llListen(MENU_DYN,"",NULL_KEY,"");
        llTextBox(llDetectedKey(0),"What Is Your Character's First and Last Name?\rYou have 60 seconds to enter a name.",MENU_DYN);
        llSetTimerEvent(60.0);
    } else {
        llSay(PUBLIC_CHANNEL,"Tool is already in use, please wait.");
    }
}
 
SET_NICKNAME() {
    if ( MENU_HAND == 0 ) {
        MENU_DYN = 1+(integer)llFrand(9999.0);
        MENU_HAND = llListen(MENU_DYN,"",NULL_KEY,"");
        llTextBox(llDetectedKey(0),"(Optional) What Is Your Character's Nickname?\rYou have 60 seconds to enter a name.",MENU_DYN);
        llSetTimerEvent(60.0);
    } else {
        llSay(PUBLIC_CHANNEL,"Tool is already in use, please wait.");
    }
}
 
SET_TITLE() {
    if ( MENU_HAND == 0 ) {
        MENU_DYN = 1+(integer)llFrand(9999.0);
        MENU_HAND = llListen(MENU_DYN,"",NULL_KEY,"");
        llTextBox(llDetectedKey(0),"What Is Your Character's Title?\rExamples: Doctor, Reverend, etc.\rYou have 60 seconds to enter a name.",MENU_DYN);
        llSetTimerEvent(60.0);
    } else {
        llSay(PUBLIC_CHANNEL,"Tool is already in use, please wait.");
    }
}
 
SETUP() {
    // llSetText("Myriad Lite Character Editorder (Prototype)\nSit Here To Begin",<1,0,0>,1);
    vector OFFSET = <0,0,1.0>;
    llSitTarget(OFFSET,ZERO_ROTATION);
    llSetSitText("> EDIT <");
 
    // put prim number/name pairs into list for UPDATE function to write text on prims
    integer i;
    string name;
    for (i = 0; i <= llGetNumberOfPrims(); i++) {
        name = llList2String(llGetLinkPrimitiveParams(i,[PRIM_NAME]),0);
        PRIMNAMES = PRIMNAMES + [name];
        llSetLinkPrimitiveParamsFast(i,[PRIM_TEXT,"",<0,0,0>,0]);
        if ( llListFindList(CATEGORIES,[name]) != -1 ) {
            llSetLinkPrimitiveParamsFast(i,[PRIM_COLOR,ALL_SIDES,<1,0,0>,1]);
        }
    }
 
    // SETUP RENDEZVOUS1 MENU_DYN (STATIC) - backward compatible for Preview 6 and earlier
    //if ( MENU_HAND1 != 0 ) llListenRemove(MENU_HAND1);
    //MENU_HAND1 = llListen(RENDEZVOUS1,"",NULL_KEY,"");
    //llSay(PUBLIC_CHANNEL,"Rendezvous1 channel is "+(string)RENDEZVOUS1);
 
    // SETUP REGION_DYN MENU_DYN (DYNAMIC) - new for Preview 7 and later
    list details = llGetParcelDetails(<0,0,0>,[PARCEL_DETAILS_ID]);
    string parcelid = llList2String(details,0);
    REGION_DYN = (integer)("0x"+llGetSubString(parcelid,0,7));
    if ( REGION_HAND != 0 ) llListenRemove(REGION_HAND);
    REGION_HAND = llListen(REGION_DYN,"",NULL_KEY,"");
    llSay(PUBLIC_CHANNEL,"Rendezvous2 channel is "+(string)REGION_DYN);    
 
    // start listener last
    MY_DYN = (integer)("0x"+llGetSubString(llGetKey(),0,6));
    if ( MY_HAND != 0 ) llListenRemove(MY_HAND);
    MY_HAND = llListen(MY_DYN,"",NULL_KEY,"");
 
    // CURCAT = llList2String(CATEGORIES,NUMCAT);
    // llRegionSay(REGION_DYN,"LIST_"+CURCAT); // request first category
}
 
// Utility function to target 1 prim
SHOW_ON_PRIM(string primname,string data) {
    integer prim = llListFindList(PRIMNAMES,[primname]);
    if ( prim != -1 ) {
        llSetLinkPrimitiveParams(prim,[PRIM_TEXT,data,<1,1,1>,1.0]);
    }
}
 
UPDATE() {
    string out;
    integer prim;
    //prim = llListFindList(PRIMNAMES,["SHOW CATEGORY"]);
    //if ( prim != -1 && CURCAT != "" ) {
    //    out = (string)(NUMCAT + 1) + " of " + llGetListLength(CATEGORIES) + ": " + CURCAT;
    //    llSetLinkPrimitiveParams(prim,[PRIM_TEXT,out,<1,1,1>,1.0]);
    //}
 
    prim = llListFindList(PRIMNAMES,["SHOW ITEM"]);
    if ( prim != -1 && CURITEM != "" ) {
        out = CURCAT + (string)(NUMITEM + 1) + " of " + llGetListLength(REGION_LIST) + "\n" + CURITEM;
        llSetLinkPrimitiveParams(prim,[PRIM_TEXT,out,<1,1,1>,1.0]);
    }
 
    // update item cost
    // update character point pool left
    // update name
    // update faction
    // update species
    // update background
    // update career
}
 
default {
 
    changed(integer change) {
        if ( change & CHANGED_LINK ) { // someone sits or stands up
            WHO = llAvatarOnSitTarget();
            if ( WHO == NULL_KEY ) RESET(); // stood up - reset
            if ( WHO != NULL_KEY ) {
                llRequestPermissions(WHO,PERMISSION_TRIGGER_ANIMATION);
            }
        }
    }
 
    listen(integer channel, string name, key id, string message) {
        if ( channel == MENU_DYN ) {
            integer chan = (integer)("0x"+llGetSubString((string)id,0,6));
            if ( REQUEST == "NAMES" ) llRegionSay(chan,"SET_NAME|NAME="+message);
            if ( REQUEST == "NICKNAMES" ) llRegionSay(chan,"SET_NICKNAME|NICKNAME="+message);
            if ( REQUEST == "TITLES" ) llRegionSay(chan,"SET_TITLE|TITLE="+message);
            if ( REQUEST == "FACTIONS" ) llRegionSay(chan,"SET_FACTION|FACTION="+message);
            if ( MENU_HAND != 0 ) llListenRemove(MENU_HAND);
            llSetTimerEvent(0.0);
            MENU_HAND = 0;
            return;
        }
 
        // OBJECT DYNAMIC CHANNEL
 
        // Handle incoming LIST_ messages
 
        // Break down message into command and first attrib=data pair
        list tokens = llParseString2List(message,["|"],[]);
        string cmd = llList2String(tokens,0); // get the field before the first |
        string data = llList2String(tokens,1);
        list subtokens = llParseString2List(data,["="],[]);
        string attrib = llList2String(subtokens,0);
        string sdata = llList2String(subtokens,1);
        integer idata = llList2Integer(subtokens,1);        
 
        if ( cmd == "CHARACTER" ) {
            if ( attrib == "NAME" ) {
                SHOW_ON_PRIM("TEXT1","Adventurer Name");
                SHOW_ON_PRIM("TEXT2",sdata);
                return;
            }
            if ( attrib == "NICKNAME" ) {
                SHOW_ON_PRIM("TEXT1","Nickname");
                SHOW_ON_PRIM("TEXT2",sdata);
                return;
            }
            if ( attrib == "TITLE" ) {
                SHOW_ON_PRIM("TEXT1","Title");
                SHOW_ON_PRIM("TEXT2",sdata);
                return;
            }
            if ( attrib == "FACTION" ) {
                SHOW_ON_PRIM("TEXT1","Faction");
                SHOW_ON_PRIM("TEXT2",sdata);
                return;
            }
            return;
        }
 
        if ( llListFindList(CATEGORIES,[cmd]) != -1 ) { // if that field is a category name, this is a reply to a LIST_ request
            REGION_LIST = llCSV2List( llList2String( llParseString2List(message,["|"],[]) ,1) ); // get the CSV list from response
            llSay(0,llList2CSV(REGION_LIST));
            CURITEM = llList2String(REGION_LIST,NUMITEM);
            UPDATE();
            return;
        }
    }
 
    run_time_permissions(integer perm) {
        if ( perm & PERMISSION_TRIGGER_ANIMATION ) {
            llStartAnimation("turn_180");
            NUMCAT = 0;
            NUMITEM = 0;
            CURCAT = llList2String(CATEGORIES,NUMCAT);
            llRegionSay(REGION_DYN,"LIST_"+CURCAT);
        }
    }
 
    state_entry() {
        SETUP();
    }
 
    timer() {
        if ( MENU_HAND != 0 ) llListenRemove(MENU_HAND);
        llSay(PUBLIC_CHANNEL,"Time expired. Please try again when ready.");
        MENU_HAND = 0;
        llSetTimerEvent(0.0);
    }
 
    touch_start(integer num_detected) {
        if ( WHO == NULL_KEY) return; // if no one on sit target, ignore clicks
        string action = llGetLinkName(llDetectedLinkNumber(0)); // get name of prim clicked in link set
        if ( action != "" && action != llGetObjectName() ) { // someone clicked a named button prim on this linkset
            COMMAND(action); // try that prim name as a command
            return;
        }
    }    
}