//Offsets und Werte der Child-Prims (Aufbau):
integer iLinknumberPart1 = 2;
vector vOffsetAvatar = <0.0, 0.0, 0.5>; //Avatar-Offset.
integer iLinknumberPart2 = 3;
float fWinkelMinimum = -30.0; //° Grad.
float fWinkelMaximum = 45.0; //° Grad.
rotation rRotationDefault1 = <0.0, 0.0, 0.0, 0.0>; //Ausgangsstellung
rotation rRotationDefault2 = <0.0, 0.0, 0.0, 0.0>;
float fSCAN_INTERVAL = 0.2; //Scannt alle 0.2 Sekunden nach dem nächsten Avatar.
float fSCAN_RANGE = 5.0; //Sucht im Radius von 10 Metern nach Avataren.
key scan()
{ //Scannt nach dem nächsten Avatar und gibt dessen UUID zurück, andernfalls NULL_KEY.
integer iCounter = 0;
vector vPosition;
float fDistance;
key kAvatar;
key kNearestAvatar = NULL_KEY;
float fNearestAvatarsDistance = fSCAN_RANGE; //Mit fSCAN_RANGE initialisieren für den Vergleich der Distanz.
list lAvatarsInRegion = llGetAgentList(AGENT_LIST_REGION, []);
integer iNumOfAvatars = llGetListLength(lAvatarsInRegion);
for (iCounter = 0; iCounter < iNumOfAvatars; iCounter++)
{
kAvatar = llList2Key(lAvatarsInRegion, iCounter);
vPosition = llList2Vector(llGetObjectDetails(kAvatar, [OBJECT_POS]), 0);
fDistance = llVecDist(llGetPos(), vPosition); //Distanz jedes Avatars.
if (fDistance < fNearestAvatarsDistance)
{ //Dieser Avatar ist näher als alle anderen.
kNearestAvatar = kAvatar;
fNearestAvatarsDistance = fDistance; //Distanz und Avatar speichern.
}
}
return kNearestAvatar;
}
start_scan()
{ //Starte Scan.
llSetTimerEvent(fSCAN_INTERVAL);
}
stop_scan()
{ //Stoppe Scan.
llSetTimerEvent(0.0);
}
integer iListIndexPos = 0;
integer iListIndexRot = 1;
list lGetRegionCoordsOfLinkPrim(integer iLinknumber)
{ //Erzeugt eine Liste mit Regions-Koordinaten und -Rotation des Childprims "iLinknumber".
list lReturn = [0,0]; //Liste für die Rückgabewerte.
//Lese lokale Koordinaten des Childprims aus.
vector vPosCHILDPRIM = llList2Vector(llGetLinkPrimitiveParams(iLinknumber, [PRIM_POS_LOCAL]), 0);
rotation rRotCHILDPRIM = llList2Rot(llGetLinkPrimitiveParams(iLinknumber, [PRIM_ROT_LOCAL]), 0);
//Fall beachten, wenn iLinknumber das RootPrim ist.
if (iLinknumber <= 1)
{
vPosCHILDPRIM = ZERO_VECTOR;
rRotCHILDPRIM = ZERO_ROTATION;
}
//Position und Rotation von Root-Prim auslesen.
vector vPosROOT = llGetRootPosition();
rotation rRotROOT = llGetRootRotation();
//Konvertieren.
vector vRegionPosCHILDPRIM = vPosCHILDPRIM * rRotROOT + vPosROOT;
rotation rRegionRotCHILDPRIM = rRotCHILDPRIM * rRotROOT;
//Rückgabeliste füllen und zurückgeben.
lReturn = llListReplaceList(lReturn, [vRegionPosCHILDPRIM], iListIndexPos, iListIndexPos);
lReturn = llListReplaceList(lReturn, [rRegionRotCHILDPRIM], iListIndexRot, iListIndexRot);
return lReturn;
}
aim(key kTarget)
{ //Ziele/schieße auf den Avatar kTarget.
vector vPosition;
vPosition = llList2Vector(llGetObjectDetails(kTarget, [OBJECT_POS]), 0) + vOffsetAvatar;
//Debug: //llSetText(llKey2Name(kTarget), <1.0, 1.0, 1.0>, 1.0);
//Childprim 1:
list lCoordsChildprim1 = lGetRegionCoordsOfLinkPrim(iLinknumberPart1); //Regionskoordinaten der Childprims ermitteln.
vector vRegionPosChildprim1 = llList2Vector(lCoordsChildprim1, iListIndexPos);
rotation rRegionRotChildprim1 = llList2Rot(lCoordsChildprim1, iListIndexRot);
//Debug: //llOwnerSay("Region coords: " + (string)vRegionPosChildprim1 + " / " + (string) rRegionRotChildprim1);
//Target-Z-Position an die des Childprims anpassen:
vector vPosHelper = <vPosition.x, vPosition.y, vRegionPosChildprim1.z>;
//Neue Rotation von Childprim1 ausrechnen:
rotation rRotChildprim1 = llRotBetween( <1.0,0.0,0.0>, llVecNorm( vPosHelper - vRegionPosChildprim1 ) );
//Debug: //llOwnerSay((string)rRotChildprim1);
llSetLinkPrimitiveParamsFast(iLinknumberPart1, [PRIM_ROT_LOCAL, rRotChildprim1]);
//Childprim 2:
list lCoordsChildprim2 = lGetRegionCoordsOfLinkPrim(iLinknumberPart2); //Regionskoordinaten der Childprims ermitteln.
vector vRegionPosChildprim2 = llList2Vector(lCoordsChildprim2, iListIndexPos);
rotation rRegionRotChildprim2 = llList2Rot(lCoordsChildprim2, iListIndexRot);
//Debug: //llOwnerSay("Region coords: " + (string)vRegionPosChildprim2 + " / " + (string) rRegionRotChildprim2);
//Target auf X-Achse projizieren für die weitere Berechnung:
vector vPosHelper_PointA1 = <vRegionPosChildprim2.x + llVecDist(<vPosition.x, vPosition.y, vRegionPosChildprim2.z>, vRegionPosChildprim2), vRegionPosChildprim2.y, vRegionPosChildprim2.z>;
vector vPosHelper_PointB1 = <vPosHelper_PointA1.x, vPosHelper_PointA1.y, vPosition.z>;
//Z-Winkel zwischen Childprim2 und Target ausrechnen:
vector vPosHelper_A = vPosHelper_PointA1 - vRegionPosChildprim2;
vector vPosHelper_B = vPosHelper_PointB1 - vRegionPosChildprim2;
float fAngle = llAtan2(llVecMag(vPosHelper_A % vPosHelper_B), vPosHelper_A * vPosHelper_B);
//Debug: //llOwnerSay((string)llAxisAngle2Rot(<1.0, 0.0, 0.0>, fAngle));return;
//Herausfinden, ob der Winkel positiv oder negativ ist:
integer iPositiveAngle = TRUE;
if (vPosition.z < vRegionPosChildprim2.z)
{ //Winkel ist negativ.
iPositiveAngle = FALSE;
}
//Winkel umrechnen:
vector vDegrees = llRot2Euler(llAxisAngle2Rot(<-1.0, 0.0, 0.0>, fAngle)) * RAD_TO_DEG;
float fDegrees = vDegrees.x;
if (!iPositiveAngle)
{
fDegrees = -fDegrees;
}
//Minimum und Maximum anwenden.
if (fDegrees < fWinkelMinimum)
{
fDegrees = fWinkelMinimum;
}
if (fDegrees > fWinkelMaximum)
{
fDegrees = fWinkelMaximum;
}
//Debug: //llOwnerSay((string)fDegrees);
//Target-Z-Position an die des Childprims anpassen:
vPosHelper = <vPosition.x, vPosition.y, vRegionPosChildprim2.z>;
//Neue Rotation von Childprim2 ausrechnen:
rotation rRotChildprim2 = llRotBetween( <1.0,0.0,0.0>, llVecNorm( vPosHelper - vRegionPosChildprim2 ) );
//Debug: //llOwnerSay((string)rRotChildprim2);
llSetLinkPrimitiveParamsFast(iLinknumberPart2, [PRIM_ROT_LOCAL, llEuler2Rot(<0.0, fDegrees, 0.0>*DEG_TO_RAD)*rRotChildprim2]);
}
stop_aim()
{ //Kein Avatar in Reichweite, höre auf zu zielen.
//Debug: //llSetText("Niemand hier", <1.0, 1.0, 1.0>, 1.0);
llSetLinkPrimitiveParamsFast(iLinknumberPart1, [PRIM_ROT_LOCAL, rRotationDefault1]);
llSetLinkPrimitiveParamsFast(iLinknumberPart2, [PRIM_ROT_LOCAL, rRotationDefault2]);
}
fire()
{
llWhisper(0, "Bam!");
}
default
{
state_entry()
{
start_scan();
}
timer()
{
key kAvatar = scan();
if (kAvatar != NULL_KEY)
{ //Avatar gefunden.
aim(kAvatar); //Zielen
fire(); //Schießen.
}
else
{
stop_aim();
}
}
}