// Copyright 2025 by Fiona Sweet // Free to use for any purpose // Two-Prim Flip Book (controller in Book_Right) // Closed: Left hidden, Right shows FrontCover. // Open: Left=InsideFrontCover, Right=Page_01, then flip spreads. // Click Right => NEXT / open; Click Left => PREV; // Prev from first or Next from last => close to FrontCover. string TEX_COVER = "FrontCover"; list ORDER = [ "InsideFrontCover","Page_01", "Page_02","Page_03", "Page_04","Page_05", "Page_06","Page_07", "Page_08","Page_09", "Page_10","Page_11", "Page_12","Page_13", "Page_14","InsideBackCover" ]; // left,right pairs (spreads) string NAME_LEFT = "Book_Left"; string NAME_RIGHT = "Notes From Saturn"; integer LINK_LEFT = -1; integer LINK_RIGHT = -1; integer gOpen = FALSE; integer gSpread = 0; integer gLastSpread = -1; integer findLink(string pname){ integer n = llGetNumberOfPrims(); for (integer i = 1; i <= n; ++i) if (llGetLinkName(i) == pname) return i; return -1; } integer texExists(string name){ return (llGetInventoryType(name) == INVENTORY_TEXTURE); } showCover(){ // Left transparent (hidden), Right shows front cover llSetLinkPrimitiveParamsFast(LINK_LEFT, [PRIM_COLOR, ALL_SIDES, <1,1,1>, 0.0]); llSetLinkPrimitiveParamsFast(LINK_RIGHT, [PRIM_TEXTURE, ALL_SIDES, TEX_COVER, <1,1,0>, <0,0,0>, 0.0, PRIM_COLOR, ALL_SIDES, <1,1,1>, 1.0]); gOpen = FALSE; gSpread = 0; } applySpread(integer spread){ integer idx = spread * 2; string leftTex = llList2String(ORDER, idx); string rightTex = llList2String(ORDER, idx + 1); llSetLinkPrimitiveParamsFast(LINK_LEFT, [PRIM_TEXTURE, ALL_SIDES, leftTex, <1,1,0>, <0,0,0>, 0.0, PRIM_COLOR, ALL_SIDES, <1,1,1>, 1.0]); llSetLinkPrimitiveParamsFast(LINK_RIGHT, [PRIM_TEXTURE, ALL_SIDES, rightTex, <1,1,0>, <0,0,0>, 0.0, PRIM_COLOR, ALL_SIDES, <1,1,1>, 1.0]); } openTo(integer spread){ gOpen = TRUE; gSpread = spread; applySpread(gSpread); } default { state_entry() { LINK_LEFT = findLink(NAME_LEFT); LINK_RIGHT = findLink(NAME_RIGHT); if (LINK_LEFT < 0 || LINK_RIGHT < 0){ llOwnerSay("Name your prims exactly: 'Book_Left' and 'Book_Right' (make Book_Right the ROOT)."); return; } // sanity check textures (warn only) integer missing = FALSE; if (!texExists(TEX_COVER)) { llOwnerSay("Missing: " + TEX_COVER); missing = TRUE; } integer L = llGetListLength(ORDER); for (integer i = 0; i < L; ++i){ string t = llList2String(ORDER,i); if (!texExists(t)) { llOwnerSay("Missing: " + t); missing = TRUE; } } if (missing) llOwnerSay("Some textures missing. the book will still try to run."); gLastSpread = (llGetListLength(ORDER) / 2) - 1; // 16 items -> 8 spreads -> last=7 showCover(); llOwnerSay("Ready: click RIGHT page to open/advance; click LEFT page to go back."); } // Clicks on Book_Right (this prim) open/advance touch_start(integer n) { if (!gOpen) { openTo(0); return; } // open on first click if (gSpread < gLastSpread) { gSpread++; applySpread(gSpread); } else { showCover(); } // last spread -> close } // Left prim sends PREV here link_message(integer sender, integer num, string msg, key id) { if (msg == "PREV"){ if (!gOpen) return; // ignore when closed if (gSpread > 0) { gSpread--; applySpread(gSpread); } else { showCover(); } // first spread -> close } } }