main
rhetorica 2026-01-30 18:47:22 -08:00
parent 5fb3ac714e
commit 2097267b9a
2 changed files with 400 additions and 0 deletions

View File

@ -0,0 +1,199 @@
/* =========================================================================
*
* Nanite Systems Advanced Research Encapsulation System
*
* Copyright (c) 20252026 Nanite Systems Corporation
*
* =========================================================================
*
* Instructor Application
*
* This program is covered under the terms of the ARES Software Copyright
* License, Section 3 (ASCL-iii). It may be redistributed or used as the
* basis of commercial, closed-source products so long as steps are taken
* to ensure proper attribution as defined in the text of the license.
*
* To see the full text of the ASCL, type 'help license' on any standard
* ARES distribution, or visit http://nanite-systems.com/ASCL for the
* current version.
*
* DISCLAIMER
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS '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 COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
* DAMAGES HOWEVER CAUSED ON ANY THEORY OF LIABILITY ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* =========================================================================
*
*/
#include <ARES/a>
#include <ARES/api/interface.consts.h.lsl>
#define CLIENT_VERSION "1.0.0"
#define CLIENT_VERSION_TAGS "release"
#define DEFAULT_INTERVAL 30
#define DEFAULT_ANCHOR CLADDING_BACKDROP
integer enabled = FALSE;
integer interval = DEFAULT_INTERVAL;
string section = "instruction";
integer random = FALSE;
integer anchor = DEFAULT_ANCHOR;
integer offset = 0;
main(integer src, integer n, string m, key outs, key ins, key user) {
if(n == SIGNAL_INVOKE) {
list argv = split(m, " ");
integer argc = count(argv);
string msg = "";
string action = gets(argv, 1);
if(argc == 1 || action == "help") {
msg = "Usage: " + PROGRAM_NAME + " ...\n\n "
+ PROGRAM_NAME + " help: this message\n "
+ PROGRAM_NAME + " anchor <n>: set anchor prim (currently: " + (string)anchor + "); 0 for chat\n "
+ PROGRAM_NAME + " on|off|toggle: enable/disable/toggle instructor (currently: " + gets(["off", "on"], enabled) + ")\n "
+ PROGRAM_NAME + " interval <n>: set interval to <n> sec (currently: " + (string)interval + " sec)\n "
+ PROGRAM_NAME + " random|sequential: set random message selection on/off (currently: " + gets(["off", "on"], random) + ")\n "
+ PROGRAM_NAME + " from <section>: use LSD:<section> as input (currently: " + section + ")"
;
} else if(action == "anchor") {
setdbl("instructor", ["anchor"], (string)(anchor = (integer)gets(argv, 2)));
if(anchor < 0)
anchor = 0;
} else if(action == "on") {
setdbl("instructor", ["enabled"], (string)(enabled = TRUE));
set_timer("instruct", interval);
} else if(action == "off") {
setdbl("instructor", ["enabled"], (string)(enabled = FALSE));
set_timer("instruct", 0);
} else if(action == "toggle") {
setdbl("instructor", ["enabled"], (string)(enabled = !enabled));
if(enabled)
set_timer("instruct", interval);
else
set_timer("instruct", 0);
} else if(action == "interval") {
integer new_interval = (integer)gets(argv, 2);
if(new_interval >= 6) {
setdbl("instructor", ["interval"], (string)(interval = new_interval));
if(enabled)
set_timer("instruct", interval);
} else {
msg = "Interval must be at least 6 sec. Use '@" + PROGRAM_NAME + " off' to disable instruction.";
}
} else if(action == "random") {
setdbl("instructor", ["random"], (string)(random = TRUE));
} else if(action == "sequential") {
setdbl("instructor", ["random"], (string)(random = FALSE));
} else if(action == "from") {
string new_section = gets(argv, 2);
if(llOrd(llLinksetDataRead(new_section), 0) == 0x5b) { // '['
setdbl("instructor", ["section"], section = new_section);
} else {
msg = "Section '" + new_section + "' does not contain a JSON array.";
}
}
if(msg != "")
print(outs, user, msg);
} else if(n == SIGNAL_INIT) {
#ifdef DEBUG
echo("[" + PROGRAM_NAME + "] init event");
#endif
enabled = (integer)getdbl("instructor", ["enabled"]);
random = (integer)getdbl("instructor", ["random"]);
interval = (integer)getdbl("instructor", ["interval"]);
string raw_anchor = getdbl("instructor", ["anchor"]);
if(raw_anchor == JSON_INVALID) {
setdbl("instructor", ["anchor"], (string)(anchor = DEFAULT_ANCHOR));
} else {
anchor = (integer)raw_anchor;
}
if(anchor < 0)
anchor = 0;
section = getdbl("instructor", ["section"]);
if(interval == 0)
setdbl("instructor", ["interval"], (string)(interval = DEFAULT_INTERVAL));
if(enabled)
set_timer("instruct", interval);
} else if(n == SIGNAL_TIMER) {
if(enabled) {
integer line_count = count(js2list(llLinksetDataRead(section)));
if(!line_count) {
echo("[" + PROGRAM_NAME + "] no usable data in " + section + "; please fix");
return;
}
if(random)
offset = (integer)llFrand(0x7fffffff) % line_count;
else
offset = (offset + 1) % line_count;
string message = getdbl(section, [offset]);
if(!anchor) {
echo(getdbl(section, [offset]));
} else {
vector color = getv(getp(2, [PRIM_COLOR, 1]), 0);
float fade = 0;
while(fade < 1.0) {
if(fade >= 0.9375)
fade = 1.0;
setp(anchor, [
PRIM_TEXT, message + "\n \n \n ", color, fade
]);
fade += 0.0625;
llSleep(0.022);
}
fade = 1.0;
llSleep(interval * 0.5 - 2);
while(fade > 0.0) {
if(fade < 0.0625)
fade = 0.0;
setp(anchor, [
PRIM_TEXT, message + "\n \n \n ", color, fade
]);
fade -= 0.0625;
llSleep(0.022);
}
setp(anchor, [
PRIM_TEXT, "", ZV, 0
]);
}
} else {
set_timer("instruct", 0);
}
} else if(n == SIGNAL_UNKNOWN_SCRIPT) {
echo("[" + PROGRAM_NAME + "] failed to run '" + m + "' (kernel could not find the program specified)");
} else {
echo("[" + PROGRAM_NAME + "] unimplemented signal " + (string)n + ": " + m);
}
}
#include <ARES/program>

View File

@ -0,0 +1,201 @@
/* =========================================================================
*
* Nanite Systems Advanced Research Encapsulation System
*
* Copyright (c) 20252026 Nanite Systems Corporation
*
* =========================================================================
*
* Salvage Utility
*
* This program is covered under the terms of the ARES Software Copyright
* License, Section 3 (ASCL-iii). It may be redistributed or used as the
* basis of commercial, closed-source products so long as steps are taken
* to ensure proper attribution as defined in the text of the license.
*
* To see the full text of the ASCL, type 'help license' on any standard
* ARES distribution, or visit http://nanite-systems.com/ASCL for the
* current version.
*
* DISCLAIMER
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS '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 COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
* DAMAGES HOWEVER CAUSED ON ANY THEORY OF LIABILITY ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* =========================================================================
*
*/
#include <ARES/a>
#define CLIENT_VERSION "1.0"
#define CLIENT_VERSION_TAGS "release"
main(integer src, integer n, string m, key outs, key ins, key user) {
if(n == SIGNAL_INVOKE) {
list argv = splitnulls(m, " ");
integer argc = count(argv);
string msg = "";
string action = gets(argv, 1);
if(argc == 1 || action == "help") {
msg = PROGRAM_NAME + " version " + CLIENT_VERSION + " (" + CLIENT_VERSION_TAGS + ")"
+ "\nUsage: " + PROGRAM_NAME + " <action> [<arguments>]"
+ "\nSupported actions:"
+ "\n help: this message"
+ "\n dbread <entry>: read from LSD storage"
+ "\n dbwrite <entry> <value>: write to LSD storage (self only)"
+ "\n dbdelete <entry>: delete from LSD storage (self only)"
+ "\n dbdrop <section>: delete a whole section from LSD storage (self only)"
+ "\n dblist: list all LSD entries"
+ "\n invdrop on|off: enable/disable inventory drop (self only)"
;
} else if(action == "dbread") {
string path = gets(argv, 2);
list ks = splitnulls(path, ".");
msg = getdbl(gets(ks, 0), delitem(ks, 0));
if(msg == "")
msg = "(empty)";
else if(msg == JSON_INVALID)
msg = "(undefined)";
} else if(action == "dbwrite") {
if(user != avatar) {
msg = "Only " + (string)avatar + " may issue the " + action + " command.";
} else {
string path = gets(argv, 2);
list ks = splitnulls(path, ".");
string h = gets(ks, 0);
ks = delitem(ks, 0);
string old = getdbl(h, ks);
string new = concat(delrange(argv, 0, 2), " ");
string ksname = concat(ks, ".");
if(ksname == "")
ksname = "<root>";
tell(user, 0, "Writing database entry at (" + h + ", " + ksname + "):");
string test = llLinksetDataRead(h);
if(test != JSON_INVALID && setjs(test, ks, new) == JSON_INVALID) {
tell(user, 0, " !!! Cannot write database entry: result would be invalid JSON. Check for unbalanced {} and [] characters.");
} else {
setdbl(h, ks, new);
if(old == "")
old = "(empty)";
else if(old == JSON_INVALID)
old = "(undefined)";
tell(user, 0, " --- old value: " + old);
if(new == "")
new = "(empty)";
else if(new == JSON_INVALID)
new = "(undefined)";
tell(user, 0, " --- new value: " + new);
}
}
} else if(action == "dbdelete") {
if(user != avatar) {
msg = "Only " + (string)avatar + " may issue the " + action + " command.";
} else {
string path = gets(argv, 2);
list ks = splitnulls(path, ".");
string h = gets(ks, 0);
ks = delitem(ks, 0);
string old = getdbl(h, ks);
string ksname = concat(ks, ".");
if(ksname == "")
ksname = "<root>";
if(old == JSON_INVALID) {
msg = "Cannot delete (" + h + ", " + ksname + "): it does not exist.";
} else {
tell(user, 0, "Deleting database entry at (" + h + ", " + ksname + "):");
string test = llLinksetDataRead(h);
if(test != JSON_INVALID && setjs(test, ks, JSON_DELETE) == JSON_INVALID) {
tell(user, 0, " !!! Cannot write database entry: result would be invalid JSON. Check for unbalanced {} and [] characters.");
} else {
setdbl(h, ks, JSON_DELETE);
if(old == "")
old = "(empty)";
tell(user, 0, " --- old value: " + old);
tell(user, 0, " --- deleted successfully.");
}
}
}
} else if(action == "dbdrop") {
if(user != avatar) {
msg = "Only " + (string)avatar + " may issue the " + action + " command.";
} else {
string k = gets(argv, 2);
list candidates = llLinksetDataFindKeys(k, 0, 0);
if(contains(candidates, k) || gets(argv, 3) == "force") {
tell(user, 0, "Deleting key " + k);
tell(user, 0, "Contents were: " + llLinksetDataRead(k));
llLinksetDataDelete(k);
} else {
msg = "No key found: " + k + "\nIs it an accidental regex? If so, try: @" + PROGRAM_NAME + " dbdrop " + k + " force";
}
}
} else if(action == "dblist") {
integer lsmax = llLinksetDataCountKeys();
integer li = 0;
while(li < lsmax) {
string k = gets(llLinksetDataListKeys(li, 1), 0);
tell(user, 0, " - " + k + " (" + (string)strlen(llLinksetDataRead(k)) + " bytes)");
++li;
llSleep(0.044);
}
tell(user, 0, (string)lsmax + " key(s), " + (string)llLinksetDataAvailable() + " byte(s) free");
} else if(action == "invdrop") {
if(user != avatar) {
msg = "Only " + (string)avatar + " may issue the " + action + " command.";
} else {
integer new = index((["off", "on"]), gets(argv, 2));
if(new == 1) {
inventory_drop(TRUE);
msg = "Inventory drop enabled.";
} else if(new == 0) {
inventory_drop(FALSE);
msg = "Inventory drop disabled.";
} else {
msg = "Invalid option. Syntax must be: @" + PROGRAM_NAME + " invdrop on|off";
}
}
} else {
msg = "Unknown action: " + action + ". For usage, see: @" + PROGRAM_NAME + " help";
}
if(msg != "")
tell(user, 0, msg);
} else if(n == SIGNAL_INIT) {
#ifdef DEBUG
echo("[" + PROGRAM_NAME + "] init event");
#endif
} else if(n == SIGNAL_UNKNOWN_SCRIPT) {
echo("[" + PROGRAM_NAME + "] failed to run '" + m + "' (kernel could not find the program specified)");
} else {
echo("[" + PROGRAM_NAME + "] unimplemented signal " + (string)n + ": " + m);
}
}
#include <ARES/program>