HSDollyCam/HS_CamMarkers.lsl
2026-05-20 06:03:40 +02:00

210 lines
5.7 KiB
Plaintext

/*
HS_DollyCam - Marker helper (separate script to save Controller memory)
- Receives link_message MC_CMD:
"SHOW|N" -> rez markers for first N presets found
"HIDE" -> cleanup markers
- Listens MARKER_CH for HELLO/CLICK
- On CLICK sends MC_EVT_CLICK with payload idx to Controller
*/
integer MC_CMD = 5100;
integer MC_EVT_CLICK = 5101;
string MARKER_OBJECT = "HS_CamMarker";
integer MARKER_CH = -880088;
key gOwner;
integer gShowToken = 0;
// [key objKey, integer idx, vector pos, rotation rot] repeating
list gMarkers;
string PRE_KEY(integer idx) { return "P" + (string)idx; }
vector gTmpPos;
vector gTmpFoc;
rotation gTmpRot;
say(string s) { llOwnerSay(s); }
integer isValidIdx(integer idx) { return (idx > 0); }
integer loadPreset(integer idx)
{
string data = llLinksetDataRead(PRE_KEY(idx));
if (data == "") return FALSE;
list p = llParseString2List(data, ["|"], []);
if (llGetListLength(p) < 10) return FALSE;
gTmpPos = <(float)llList2String(p,0),(float)llList2String(p,1),(float)llList2String(p,2)>;
gTmpFoc = <(float)llList2String(p,3),(float)llList2String(p,4),(float)llList2String(p,5)>;
gTmpRot = <(float)llList2String(p,6),(float)llList2String(p,7),(float)llList2String(p,8),(float)llList2String(p,9)>;
return TRUE;
}
rotation markerRotFromPosFocus(vector pos, vector focus)
{
vector fwd = llVecNorm(focus - pos);
vector up = <0,0,1>;
vector left = up % fwd;
if (llVecMag(left) < 0.0001) left = <1,0,0>;
else left = llVecNorm(left);
vector up2 = llVecNorm(fwd % left);
return llAxes2Rot(left, up2, fwd);
}
markersClearLocal()
{
gMarkers = [];
}
integer markersFind(key obj)
{
integer i;
for (i = 0; i < llGetListLength(gMarkers); i += 4) {
if (llList2Key(gMarkers, i) == obj) return i;
}
return -1;
}
markersHide()
{
integer i;
for (i = 0; i < llGetListLength(gMarkers); i += 4) {
key obj = llList2Key(gMarkers, i);
if (obj != NULL_KEY)
llRegionSayTo(obj, MARKER_CH, "DIE|" + (string)gShowToken);
}
markersClearLocal();
say("Markers cleaned up.");
}
showCams(integer want)
{
if (llGetInventoryType(MARKER_OBJECT) != INVENTORY_OBJECT) {
say("Missing marker object in HUD contents: " + MARKER_OBJECT);
return;
}
markersHide();
gShowToken = (integer)llFrand(2147483647.0);
vector aPos = llList2Vector(llGetObjectDetails(gOwner, [OBJECT_POS]), 0);
vector rezPos = aPos + <0,0,1>;
integer found = 0;
integer idx;
for (idx = 1; idx <= 999 && found < want; ++idx) {
if (!loadPreset(idx)) jump cont;
vector pos = gTmpPos;
vector foc = gTmpFoc;
rotation mrot = markerRotFromPosFocus(pos, foc);
llRezObject(MARKER_OBJECT, rezPos, ZERO_VECTOR, ZERO_ROTATION, idx);
gMarkers += [NULL_KEY, idx, pos, mrot];
found++;
@cont;
}
say("Showing cams: " + (string)found + " (token " + (string)gShowToken + ")");
}
default
{
state_entry()
{
gOwner = llGetOwner();
llListen(MARKER_CH, "", "", "");
}
attach(key id)
{
if (id == NULL_KEY) {
markersHide();
} else {
gOwner = llGetOwner();
}
}
link_message(integer sender, integer num, string str, key id)
{
if (num != MC_CMD) return;
if (id != gOwner) return;
str = llStringTrim(str, STRING_TRIM);
if (str == "") return;
list p = llParseString2List(str, ["|"], []);
string cmd = llToUpper(llList2String(p, 0));
if (cmd == "HIDE") {
markersHide();
return;
}
if (cmd == "SHOW") {
integer want = 12;
if (llGetListLength(p) >= 2) want = (integer)llList2String(p, 1);
if (want < 1) want = 1;
if (want > 30) want = 30;
showCams(want);
return;
}
}
object_rez(key id)
{
integer i;
for (i = 0; i < llGetListLength(gMarkers); i += 4) {
if (llList2Key(gMarkers, i) == NULL_KEY) {
integer idx = llList2Integer(gMarkers, i+1);
vector pos = llList2Vector(gMarkers, i+2);
rotation rot = llList2Rot(gMarkers, i+3);
gMarkers = llListReplaceList(gMarkers, [id], i, i);
llRegionSayTo(id, MARKER_CH,
"SET|" + (string)gShowToken + "|" + (string)idx + "|" + (string)pos + "|" + (string)rot
);
return;
}
}
}
listen(integer channel, string name, key id, string msg)
{
if (channel != MARKER_CH) return;
list p = llParseString2List(msg, ["|"], []);
if (llGetListLength(p) < 2) return;
string typ = llToUpper(llList2String(p,0));
integer tok = (integer)llList2String(p,1);
if (tok != gShowToken) return;
if (typ == "HELLO") {
integer at = markersFind(id);
if (at >= 0) {
integer idx = llList2Integer(gMarkers, at+1);
vector pos = llList2Vector(gMarkers, at+2);
rotation rot = llList2Rot(gMarkers, at+3);
llRegionSayTo(id, MARKER_CH,
"SET|" + (string)gShowToken + "|" + (string)idx + "|" + (string)pos + "|" + (string)rot
);
}
return;
}
if (typ == "CLICK" && llGetListLength(p) >= 3) {
integer idx2 = (integer)llList2String(p,2);
if (!isValidIdx(idx2)) return;
// Inform Controller (it will stop playlist + move camera)
llMessageLinked(LINK_SET, MC_EVT_CLICK, (string)idx2, gOwner);
return;
}
}
}