// ===================================================================== // Texture Changer // skimi3d script library // https://grid.skimi3d.com/scripts/texture-changer // // Put several textures in a prim and click through them. The wall // colour of a house you are selling, the poster in a frame, the // painting over the fireplace, the sign outside a shop that changes // with the season. // // It reads the textures out of the prim's own Contents, so adding one // more is dropping one more in. Nothing to edit. // // Plain LSL. // ===================================================================== // --------------------------------------------------------------------- // Settings // --------------------------------------------------------------------- // Which face changes. -1 means every face of the prim. Give a single // face number to change only the front of a picture frame and leave the // wood alone. integer FACE = -1; // How it is chosen: // 0 = one click, next texture // 1 = a menu, so people can pick by name integer MODE = 0; // Change every prim in the linkset rather than just this one. Useful // for a wall built from six prims that should redecorate together. integer WHOLE_LINKSET = FALSE; // Which texture it starts on, counting from 0. Contents is kept in // alphabetical order, so naming them 1 Oak, 2 Pine, 3 Ash puts them in // the order you meant. integer START_AT = 0; // Say the name of each texture as it comes up. Handy while you are // setting up, noisy afterwards. integer ANNOUNCE = FALSE; // Who may change it. 0 = everyone, 1 = only the owner, 2 = same group. integer WHO_MAY_CHANGE = 0; // --------------------------------------------------------------------- // Everything below here is the machinery // --------------------------------------------------------------------- float PATIENCE = 60.0; // how long a menu waits for an answer integer PER_PAGE = 9; // a dialog holds nine buttons and no more list gTextures = []; integer gAt = 0; integer gChannel = 0; integer gListen = 0; integer gPage = 0; list findTextures() { list out = []; integer n = llGetInventoryNumber(INVENTORY_TEXTURE); integer i; for (i = 0; i < n; ++i) { out += [llGetInventoryName(INVENTORY_TEXTURE, i)]; } return out; } show(integer at) { integer n = llGetListLength(gTextures); if (n == 0) return; // Wrap both ways, so a click past the end comes back to the start. while (at < 0) at += n; while (at >= n) at -= n; gAt = at; string tex = llList2String(gTextures, at); integer link = LINK_THIS; if (WHOLE_LINKSET) link = LINK_SET; llSetLinkPrimitiveParamsFast(link, [PRIM_TEXTURE, FACE, tex, <1.0, 1.0, 0.0>, ZERO_VECTOR, 0.0]); if (ANNOUNCE) llOwnerSay("Now showing: " + tex); } integer privateChannel(key who) { return -1 - (integer)("0x" + llGetSubString((string)who, 0, 6)); } list page(integer n) { integer total = llGetListLength(gTextures); if (total <= PER_PAGE) return gTextures; integer room = PER_PAGE - 2; integer pages = (total + room - 1) / room; if (n < 0) n = pages - 1; if (n >= pages) n = 0; gPage = n; integer from = n * room; integer to = from + room - 1; if (to > total - 1) to = total - 1; return llList2List(gTextures, from, to) + ["< Back", "Next >"]; } menu(key who, integer n) { if (gListen) llListenRemove(gListen); gChannel = privateChannel(who); gListen = llListen(gChannel, "", who, ""); llDialog(who, "Which one?", page(n), gChannel); llSetTimerEvent(PATIENCE); } shut() { if (gListen) llListenRemove(gListen); gListen = 0; gPage = 0; llSetTimerEvent(0.0); } integer mayChange(key who) { if (WHO_MAY_CHANGE == 1) return who == llGetOwner(); if (WHO_MAY_CHANGE == 2) return llSameGroup(who); return TRUE; } default { state_entry() { shut(); gTextures = findTextures(); if (llGetListLength(gTextures) == 0) { llOwnerSay("I have no textures in my Contents. Drop some in and I will start working."); return; } show(START_AT); } touch_start(integer total) { key who = llDetectedKey(0); if (!mayChange(who)) { llRegionSayTo(who, 0, "This one is not yours to change."); return; } if (llGetListLength(gTextures) == 0) { llRegionSayTo(who, 0, "There is nothing here to show yet."); return; } if (MODE == 1) { menu(who, 0); return; } show(gAt + 1); } listen(integer channel, string name, key who, string message) { if (message == "Next >") { menu(who, gPage + 1); return; } if (message == "< Back") { menu(who, gPage - 1); return; } shut(); integer at = llListFindList(gTextures, [message]); if (at != -1) show(at); } timer() { shut(); } changed(integer what) { // Dropping another texture in should be all it takes. Holding // the current one by NAME rather than by number means the // picture on the wall does not jump when a new texture sorts // itself in ahead of it. if (what & CHANGED_INVENTORY) { string was = llList2String(gTextures, gAt); gTextures = findTextures(); integer at = llListFindList(gTextures, [was]); if (at == -1) at = 0; gAt = at; } } on_rez(integer start) { llResetScript(); } }