// IF YOU VALUE THIS WORK, PLEASE LEAVE ATTRIBUTION INTACT // // // // _|_| // // _| _| _|_|_|_| _|_| _|_|_| _|_| // // _| _| _| _| _| _| _| _|_|_|_| // // _| _| _| _| _| _| _| _| // // _|_| _|_|_|_| _|_| _| _| _|_|_| // // MiniVerse // //.................._▒▓▒.Ozone.MiniVerse.▒▓▒_.................// //................_▒▓▓▓▒____PRESENTS____▒▓▓▓▓▓▒_..............// //..............░▓▓▓▓▓▓▒___I.M.A.G.E.___▒▓▓▓▓▓▓▓░.............// //.............▒▓▓▓▓▓▓▓▒__IMAGE_MATRIX__▒▓▓▓▓▓▓▓▓▒............// //............▒▓▒▓▓▓▓▒_ACTION_GAME_ENGINE_▒▓▓▓▓▒▓▓▒...........// //..........▒▓▓▓▓░...▒▓▓▒_By_Spax_Orion_▒▓▓▒...░▓▓▓▓▒.........// //.........▒▓▓▓▓░......▒▓_& Dirty Helga_▓▓▒░.....░▒▓▓▓........// //............................................................// // Software RELEASED under [CC BY-NC] // // https://creativecommons.org/licenses/by-nc/4.0/ // // ===========================================================// // Common sense not included and must be supplied by end user // // Read ENTIRE script first and LEARN: KNOW what you're using // // ===========================================================// // IMAGE-ChildGate Height Scanner (FAIR Countdown Kick) // // "Fair warning. Then session termination." // // OpenSim 0.9.2.1 + OSSL expected. // // ===========================================================// // ----------[ CONFIGURATION ]-------------------------------- float MIN_HEIGHT_M = 1.6; // meters (Z size threshold) integer SCAN_INTERVAL = 30; // seconds, scans ONE avatar per tick integer COMPLIANCE_SECONDS = 90; // warning window before kick integer COOLDOWN_SECONDS = 300; // post-kick cooldown per avatar integer ENABLE_30S_REMINDER = TRUE; // send reminder ~30 seconds left integer EXEMPT_NPCS = TRUE; integer ENABLE_LECTURE_DIALOG = TRUE; // llDialog popup in addition to IM integer DIALOG_CHANNEL = -911400; // arbitrary negative channel integer EXEMPT_OWNER_AND_MANAGERS = TRUE; string WARN_MSG = "[ADULT REGION POLICY 1.6m HEIGHT MINIMUM]\n" + "You must be of adult height and adult appearance.\n" + "CHANGE AVATAR NOW.\n" + "You have 90 seconds or your session ends.\n" + "\n" + "Free replacement avatars are beside this gate.\n" + "No excuses.\n" + "System standards expected. Broken mesh can trip this scanner.\n"; string REMINDER_MSG = "[FINAL WARNING]\n" + "30 seconds remain to comply (min height 1.6m).\n" + "Free avatars are beside the gate.\n" + "Fix it or disconnect.\n"; string KICK_REASON = "Non-compliance: avatar below 1.60m after 90s warning window."; // ---------------------------[ CONSTANTS ]------------------------------------ integer IDX = 0; // ---------------------------[ RUNTIME VARIABLES ]---------------------------- // Current agent roster: list gAgents = []; // Flagged entries: [ key id, integer deadlineUnix, integer remindedFlag ] // remindedFlag: 0 = not reminded, 1 = reminder sent list gFlagged = []; // Cooldowns: [ key id, integer cooldownUntilUnix ] list gCooldown = []; // ---------------------------[ HELPERS ]-------------------------------------- // Lists structured as [key, valueA, valueB, key, valueA, valueB, ...] integer listFindKey3(list L, key k) { integer i; integer len = llGetListLength(L); for (i = 0; i < len; i += 3) { if (llList2Key(L, i) == k) return i; } return -1; } // ---- Flag handling ---- integer setFlag(key id, integer deadlineUnix) { integer i = listFindKey3(gFlagged, id); if (i == -1) { // New entry: remindedFlag = 0 gFlagged += [id, deadlineUnix, 0]; } else { // Update deadline, preserve remindedFlag integer reminded = llList2Integer(gFlagged, i + 2); gFlagged = llListReplaceList(gFlagged, [id, deadlineUnix, reminded], i, i + 2); } return FALSE; } // ---- Height detection ---- float getHeightM(key id) { // Core LSL – safe on OpenSim without OSSL permissions vector sz = llGetAgentSize(id); // Defensive: some grids return <0,0,0> transiently if (sz.z <= 0.0) return 0.0; return sz.z; } // ---- Exemption logic ---- integer isExempt(key id) { // Owner exempt only if (id == llGetOwner()) return TRUE; return FALSE; } // ---- Flag handling ---- integer clearFlag(key id) { integer i = listFindKey3(gFlagged, id); if (i != -1) gFlagged = llDeleteSubList(gFlagged, i, i + 2); return FALSE; } integer now() { return llGetUnixTime(); } // Lists structured as [key, value, key, value] integer listFindKey2(list L, key k) { integer i; for (i = 0; i < llGetListLength(L); i += 2) { if (llList2Key(L, i) == k) return i; } return -1; } // ---- Cooldown handling ---- integer isCooldown(key id) { integer i = listFindKey2(gCooldown, id); if (i == -1) return FALSE; integer until = llList2Integer(gCooldown, i + 1); if (now() >= until) { gCooldown = llDeleteSubList(gCooldown, i, i + 1); return FALSE; } return TRUE; } integer setCooldown(key id, integer seconds) { integer i = listFindKey2(gCooldown, id); integer until = now() + seconds; if (i == -1) gCooldown += [id, until]; else gCooldown = llListReplaceList(gCooldown, [id, until], i, i + 1); return TRUE; } // ---- NPC Exemption ---- integer isNPC(key id) { if (!EXEMPT_NPCS) return FALSE; // Comment this line if your build lacks osIsNpc if (osIsNpc(id)) return TRUE; return FALSE; } // ---- Messaging / Lecture ---- integer lectureDialog(key id, string msg) { if (!ENABLE_LECTURE_DIALOG) return FALSE; // Keep dialog short: viewers truncate. IM carries the full lecture. string shortMsg = "CHANGE AVATAR NOW.\n" + "Min height: 1.40m\n" + "Deadline: 90 seconds.\n" + "\n" + "Free avatars are beside the gate.\n" + "No code patches for stolen SL mesh."; llDialog(id, shortMsg, ["Understood"], DIALOG_CHANNEL); return TRUE; } // ---- Flag handling ---- integer markReminded(key id) { integer i = listFindKey3(gFlagged, id); if (i != -1) { integer deadline = llList2Integer(gFlagged, i + 1); // Set remindedFlag = 1, preserve deadline gFlagged = llListReplaceList(gFlagged, [id, deadline, 1], i, i + 2); } return FALSE; } // ---------------------------[ ENFORCEMENT ]---------------------------------- integer handleAvatar(key id, float h) { if (id == NULL_KEY) return FALSE; if (isNPC(id)) return FALSE; if (isExempt(id)) return FALSE; if (isCooldown(id)) return FALSE; // If compliant, forgive and forget. if (h >= MIN_HEIGHT_M || h <= 0.0) { clearFlag(id); return FALSE; } integer fi = listFindKey3(gFlagged, id); // First detection: warn + set deadline. if (fi == -1) { integer deadline = now() + COMPLIANCE_SECONDS; setFlag(id, deadline); llInstantMessage(id, WARN_MSG + "\nDetected height: " + (string)h + "m"); lectureDialog(id, WARN_MSG); return FALSE; } integer deadlineUnix = llList2Integer(gFlagged, fi + 1); integer reminded = llList2Integer(gFlagged, fi + 2); integer t = now(); // Optional reminder if (ENABLE_30S_REMINDER && !reminded) { integer remaining = deadlineUnix - t; if (remaining <= 30 && remaining > 0) { llInstantMessage(id, REMINDER_MSG + "\nDetected height: " + (string)h + "m"); lectureDialog(id, REMINDER_MSG); markReminded(id); } } // Deadline reached: kick if (t >= deadlineUnix) { osKickAvatar(id, KICK_REASON); clearFlag(id); setCooldown(id, COOLDOWN_SECONDS); return TRUE; // something actually happened } return FALSE; } // ---------------------------[ STATE / LOOP ]--------------------------------- default { state_entry() { llSetTimerEvent((float)SCAN_INTERVAL); } timer() { // Update roster each tick. gAgents = llGetAgentList(AGENT_LIST_REGION, []); integer n = llGetListLength(gAgents); if (n == 0) return; if (IDX >= n) IDX = 0; key id = llList2Key(gAgents, IDX); IDX++; // Measure and handle. float h = getHeightM(id); handleAvatar(id, h); } }