diff --git a/GLBA-Slim.lsl b/GLBA/GLBA-Slim.lsl similarity index 100% rename from GLBA-Slim.lsl rename to GLBA/GLBA-Slim.lsl diff --git a/GLBA-Vehicles.lsl b/GLBA/GLBA-Vehicles.lsl similarity index 100% rename from GLBA-Vehicles.lsl rename to GLBA/GLBA-Vehicles.lsl diff --git a/LBH Slim v1.2.5.lsl b/LBH Slim v1.2.5.lsl new file mode 100644 index 0000000..de4a3e7 --- /dev/null +++ b/LBH Slim v1.2.5.lsl @@ -0,0 +1,106 @@ +//A slim and simplified version of the LBA parser. +integer mhp=100;//Maximum HP +integer hp=mhp;//Current HP +//Positive Numbers Deal Damage +//Negative Numbers Restore Health +integer atcap=50; +//Damage Processor +damage(integer amt, key id) +{ + if(amt>atcap)amt=atcap; + if(amt<0)//Allows the object to be healed/repaired + { + if(llGetTime()>1.0)//Optional healing cooldown + { + amt*=-1; + if(amt>(float)hp*0.1)amt=llRound((float)hp*0.1);//Optional healing cap + hp+=amt; + if(hp>mhp)hp=mhp;//Used to prevent overhealing + llResetTime(); + } + //Be sure to update the listen event code block to allow negative damage values through. + } + /*else if(amt<6)return; //Blocks micro-LBA*/ + else if(amt) + { + if(amt>atcap)amt=atcap; + hp-=amt; + } + else return; + if(hp<1)die(); + else update(); +} + +update()//SetText +{ + llSetLinkPrimitiveParamsFast(-4,[PRIM_TEXT,"[LBHS]\n "+(string)hp+" / "+(string)mhp+" HP",<1.0,1.0,1.0>,1.0, + PRIM_DESC,"LBA.v.HS,"+(string)hp+","+(string)mhp+","+(string)atcap+",666"]); + //In order: Current HP, Max HP, Max AT accepted, Max healing accepted (Not implemented) +} +die() +{ + //Add extra shit here + //llResetScript();//Debug + llDie();//Otherwise, use this +} +vector tar(key id) +{ + vector av=(vector)((string)llGetObjectDetails(id,[OBJECT_POS])); + return av; +} +key user; +key gen;//Object rezzer +key me; +integer hear; +boot() +{ + user=llGetOwner(); + me=llGetKey(); + gen=(string)llGetObjectDetails(me,[OBJECT_REZZER_KEY]); + if(hear)llListenRemove(hear); + integer hex=(integer)("0x" + llGetSubString(llMD5String((string)me,0), 0, 3)); + hear=llListen(hex,"","",""); + llSetTimerEvent(5.0);//Used for auto-delete. + update(); +} +default +{ + state_entry() + { + boot(); + } + on_rez(integer p) + { + if(p>1)//Allows HUD/Objects to set HP value when rezzed with a param, otherwise uses default + { + mhp=p; + hp=p; + } + boot(); + } + listen(integer chan, string name, key id, string message) + { + //[ALWAYS] USE llRegionSayTo(). Do not flood the channel with useless garbage that'll poll every object in listening range. + list parse=llParseString2List(message,[","],[" "]); + if(llList2Key(parse,0)==me)//targetcheck + { + float amt=llList2Float(parse,-1); + if(llFabs(amt)<666.0)damage((integer)amt,id);//Use this code to allow object healing, Blocks overflow attempts + //if(amt>0)damage((integer)amt,id);//Use this code if you do not wish to support healing + } + } + collision_start(integer c)//Enable this block if you want to support legacy collisions. + { + if(llVecMag(llDetectedVel(0))>40.0) + { + hp-=c; + if(hp<1)die();//llDie(); + else update(); + } + } + timer()//Auto-deleter. Will kill object if avatar leaves the region or spawning object is removed. + { + if(tar(gen))return; + llDie(); + } +} diff --git a/LBH-AG v1.2.5.lsl b/LBH-AG v1.2.5.lsl new file mode 100644 index 0000000..6f44189 --- /dev/null +++ b/LBH-AG v1.2.5.lsl @@ -0,0 +1,171 @@ +//AG Variant includes a built-in anti-grief and blacklisting system. See line 49+ for details. +integer mhp=100;//Maximum HP +integer hp=mhp;//Current HP +//Positive Numbers Deal Damage +//Negative Numbers Restore Health +integer atcap=50; +//Damage Processor +damage(integer amt, key id) +{ + if(amt>atcap)amt=atcap; + if(amt<0)//Allows the object to be healed/repaired + { + if(llGetTime()>1.0)//Optional healing cooldown + { + amt*=-1; + if(amt>(float)hp*0.1)amt=llRound((float)hp*0.1);//Optional healing cap + hp+=amt; + if(hp>mhp)hp=mhp;//Used to prevent overhealing + llResetTime(); + } + //Be sure to update the listen event code block to allow negative damage values through. + } + /*else if(amt<6)return; //Blocks micro-LBA*/ + else if(amt) + { + if(amt>atcap)amt=atcap; + hp-=amt; + } + else return; + if(hp<1)die(); + else update(); +} + +update()//SetText +{ + llSetLinkPrimitiveParamsFast(-4,[PRIM_TEXT,"[LBH-AG]\n "+(string)hp+" / "+(string)mhp+" HP",<1.0,1.0,1.0>,1.0, + PRIM_DESC,"LBA.v.HAG,"+(string)hp+","+(string)mhp+","+(string)atcap+",666"]); + //In order: Current HP, Max HP, Max AT accepted, Max healing accepted (Not implemented) +} +die() +{ + //Add extra shit here + //llResetScript();//Debug + llDie();//Otherwise, use this +} +vector tar(key id) +{ + vector av=(vector)((string)llGetObjectDetails(id,[OBJECT_POS])); + return av; +} +//Anti-Grief +float interval=2.0;//How many seconds before the threshold is cleared. Recommended 2 seconds. +integer banthresh=80;//How much HP within the interval is considered ban worth, this affects single-hits as well as ATCAP is used only during damage calculations. Note that exceeding the ATCAP will still count against the user as the difference is not factored with the tracker. +//With a 2s interval at 80 damage, it will require a single owner to deal more than 40 DPS in order to get blacklisted. +list banlist; +//Tracker stores information like so: OWNER_UUID,DMG_TRACKED +list tracker; +integer checkdmg(string source, key owner, integer amt)//0 = Do not take damage, 1 = Take damage +{ + if(llListFindList(banlist,[owner])>-1)return 0;//Checks for previously banned source + else + { + integer param=llListFindList(banlist,[owner]); + if(param>-1)//Owner damage is already in tracker. + { + integer totalamt=llList2Integer(tracker,param+1); + if(totalamtmhp)hp=mhp; + return 0; + } + } + else + { + if(amt>banthresh) + { + banlist+=owner; + llOwnerSay("Banned "+llKey2Name(owner)+" for dealing "+(string)amt+" damage + Last source: ["+source+"] for "+(string)amt+" damage"); + llRegionSayTo(owner,0,"Blacklisted for dealing too much damage too quickly"); + return 0; + //No need to refund damage since they were not already in tracker + } + else + { + tracker+=[owner,amt]; + return 1; + } + } + } +} +// +key user; +key gen;//Object rezzer +key me; +integer hear; +boot() +{ + user=llGetOwner(); + me=llGetKey(); + gen=(string)llGetObjectDetails(me,[OBJECT_REZZER_KEY]); + if(hear)llListenRemove(hear); + integer hex=(integer)("0x" + llGetSubString(llMD5String((string)me,0), 0, 3)); + hear=llListen(hex,"","",""); + llSetTimerEvent(interval); + update(); +} +default +{ + state_entry() + { + boot(); + } + on_rez(integer p) + { + if(p>1)//Allows HUD/Objects to set HP value when rezzed with a param, otherwise uses default + { + mhp=p; + hp=p; + } + boot(); + } + listen(integer chan, string name, key id, string message) + { + //[ALWAYS] USE llRegionSayTo(). Do not flood the channel with useless garbage that'll poll every object in listening range. + list parse=llParseString2List(message,[","],[" "]); + if(llList2Key(parse,0)==me)//targetcheck + { + integer amt=llList2Integer(parse,-1); + if(llFabs(amt)<666.0)//Overflow check + { + if(amt>0.0) + { + if(checkdmg(name,llGetOwnerKey(id),amt)) + { + llSetTimerEvent(interval);//Reset interval on new damage update + damage(amt,id); + } + } + else damage(amt,id); + } + } + } + collision_start(integer c)//Enable this block if you want to support legacy collisions. + { + if(llVecMag(llDetectedVel(0))>40.0) + { + hp-=c; + if(hp<1)die();//llDie(); + else update(); + } + } + timer() + { + tracker=[];//Clear tracker + //Auto-Deleter + if(tar(gen))return; + llDie(); + } +} diff --git a/LBHD+AG, Directional Armor v1.4.3.lsl b/LBHD+AG, Directional Armor v1.4.3.lsl new file mode 100644 index 0000000..08361d7 --- /dev/null +++ b/LBHD+AG, Directional Armor v1.4.3.lsl @@ -0,0 +1,248 @@ +string ver="DHAGv1.4.3";//LBA Version +integer mhp=200;//Maximum HP +integer hp=mhp;//Current HP +//Anti-Grief +float interval=1.0;//How many seconds before the threshold is cleared. +integer banthresh=250;//How much HP within the interval is considered ban worth, this affects single-hits as well as ATCAP is used only during damage calculations. Note that exceeding the ATCAP will still count against the user as the difference is not factored with the tracker. +//With a 2s interval at 80 damage, it will require a single owner to deal more than 40 DPS in order to get blacklisted. +list banlist; +//Tracker stores information like so: OWNER_UUID,DMG_TRACKED +list bantracker; +integer checkdmg(string source, key owner, integer amt)//0 = Do not take damage, 1 = Take damage +{ + if(llListFindList(banlist,[owner])>-1)return 0;//Checks for previously banned source + else + { + integer param=llListFindList(banlist,[owner]); + if(param>-1)//Owner damage is already in tracker. + { + integer totalamt=llList2Integer(tracker,param+1); + if(totalamtmhp)hp=mhp; + return 0; + } + } + else + { + bantracker+=[owner,amt]; + return 1; + } + } +} +//Positive Numbers Deal Damage +//Negative Numbers Restore Health +//Damage Multipliers: 0 = Invulnerable, 1.0 = 100% Damage, High numbers = Higher Damage +//The total between all values should be around 5.0 for balancing purposes. +integer atcap=200; +float front=0.5; +float side=1.0; +float back=1.5; +float middle=0.1; +//Note that following modifiers multiply the final damage. So it stacks multiplicatively with the previous modifiers +float top=1.2; +float bottom=1.2; +//Directional Processor +float front_threshold=25.0;//Use positive floats, determines forward range +float back_threshold=155.0;//Use positive floats, determines backward range +float top_threshold=0.75;//How far up the Z axis should the source be to registered a top. (Positive Number) +float bottom_threshold=-0.75;//How far down the Z axis should the source be to registered a bottom hit. (Negative Number) +float collisionmod(vector pos, vector targetPos) +{ + if(targetPos) + { + float dist=llVecDist(pos,targetPos); + if(dist<1.0)return middle;//This catches explosions which rezzes AT in the object's root position. + else + { + vector fpos=(targetPos-pos)/llGetRot(); + float mod=fpos.z; + if(mod>=top_threshold)mod=top;//Top check + else if(mod<=bottom_threshold)mod=bottom;//Bottom check + else mod=1.0;//Else reset it to 1.0 + vector angle=<1.0,0.0,0.0>*llGetRot(); + angle.z=0.0; + rotation targetRot=llRotBetween(llVecNorm(angle),llVecNorm(-pos)); + vector targetRotVec=llRot2Euler(targetRot)*RAD_TO_DEG; + if(targetRotVec.z>-front_threshold&&targetRotVec.zback_threshold)//Back + return back*mod; + else //If it didn't hit any previous angles, the only thing left to hit is the sides. + return side*mod; + } + } + else return 0.0; +} +//Damage Processor +damage(integer amt, key id,vector pos, vector targetPos, float tmod,string name) +{ + if(amt>atcap)amt=atcap; + if(amt<0)//Allows the object to be healed/repaired + { + if(llGetTime()>1.0)//Optional healing cooldown + { + amt*=-1.0; + if(amt>(float)hp*0.1)amt=llRound(hp*0.1);//Optional healing cap + hp+=amt; + if(hp>mhp)hp=mhp;//Used to prevent overhealing + llResetTime(); + } + //Be sure to update the listen event code block to allow negative damage values through. + } + /*else if(amt<6)return; //Blocks micro-LBA*/ + else + { + integer directional_amt; + if(tmod)directional_amt=llFloor(amt*tmod); + else directional_amt=llFloor(collisionmod(pos,targetPos)*(float)amt); + if(directional_amt)hp-=directional_amt; + else //Failed to do damage + { + llOwnerSay("Damage Blocked by Armor"); + llRegionSayTo(llGetOwnerKey(id),0,"Attack was stopped by armor."); + return; + } + llOwnerSay("/me took "+(string)directional_amt+" ("+(string)amt+") damage from "+name+" by "+llKey2Name(llGetOwnerKey(id)));//Used to debug output. + llRegionSayTo(llGetOwnerKey(id),0,"/me took "+(string)directional_amt+" ("+(string)amt+") damage"); + } + if(hp<1)die(); + else update(); +} +string modifierstring;//This is visible so moderators can confirm vehicle attributes are within regulation. +update()//SetText +{ + llSetLinkPrimitiveParamsFast(-4,[PRIM_TEXT,"[LBHD]\n "+(string)hp+" / "+(string)mhp+" HP",<0.0,0.75,1.0>,1.0, + PRIM_DESC,"LBA.v."+ver+","+(string)hp+","+(string)mhp+","+(string)atcap+",999"+modifierstring]); + //In order: Current HP, Max HP, Max AT accepted, Max healing accepted (Not implemented) +} +die() +{ + //Add extra shit here + //llResetScript();//Debug + llDie();//Otherwise, use this +} +integer los(vector start, vector target)//1=LoS,0=Obstructed +{ + list ray=llCastRay(start,target,[RC_REJECT_TYPES,RC_REJECT_AGENTS,RC_DATA_FLAGS,RC_GET_ROOT_KEY,RC_MAX_HITS,1]); + if(llList2Vector(ray,1)==ZERO_VECTOR)return 1; + else return 0; +} +vector tar(key id)//Deprecated +{ + vector av=(vector)((string)llGetObjectDetails(id,[OBJECT_POS])); + return av; +} +key user; +key gen;//Object rezzer +key me; +integer hear; +list tracker; +boot() +{ + modifierstring=",F-"+llGetSubString((string)front,0,2)+//Frontal modifier + ",S-"+llGetSubString((string)side,0,2)+//Side modifier + ",R-"+llGetSubString((string)back,0,2)+//Rear modifier + ",T-"+llGetSubString((string)top,0,2)+//Top modifier + ",B-"+llGetSubString((string)bottom,0,2)+//Bottom modifier + ",M-"+llGetSubString((string)middle,0,2);//Middle Modifier + user=llGetOwner(); + me=llGetKey(); + gen=(string)llGetObjectDetails(me,[OBJECT_REZZER_KEY]); + if(hear)llListenRemove(hear); + integer hex=(integer)("0x" + llGetSubString(llMD5String((string)me,0), 0, 3)); + hear=llListen(hex,"","",""); + llSetTimerEvent(interval); + update(); +} +default +{ + state_entry() + { + boot(); + } + on_rez(integer p) + { + if(p>1)//Allows HUD/Objects to set HP value when rezzed with a param, otherwise uses default + { + mhp=p; + hp=p; + } + boot(); + } + listen(integer chan, string name, key id, string message) + { + //[ALWAYS] USE llRegionSayTo(). Do not flood the channel with useless garbage that'll poll every object in listening range. + list parse=llParseString2List(message,[","],[" "]); + if(llList2Key(parse,0)==me)//targetcheck + { + list data=llGetObjectDetails(id,[OBJECT_POS,OBJECT_ATTACHED_POINT,OBJECT_ROT,OBJECT_REZZER_KEY]); + vector pos=llGetPos(); + vector targetPos=llList2Vector(data,0); + float amt=llList2Float(parse,-1); + if(llFabs(amt)<666)//Use this code to allow object healing, Blocks overflow attempts + { + if(amt>0) + { + if(checkdmg(name,llGetOwnerKey(id),(integer)amt)) + { + float tmod; + integer f=llListFindList(tracker,[name]); + if(f>-1)tmod=llList2Float(tracker,f+1); + else //Rezzer rezzer's rezzer rezzer + { + f=llListFindList(tracker,[llList2Key(data,4)]); + if(f>-1)tmod=llList2Float(tracker,f+1); + } + llSetTimerEvent(interval);//Reset interval on new damage update + if(llList2Integer(data,1)) + { + float dist=llVecDist(targetPos,pos)-2.0; + vector posfix=targetPos+*llList2Rot(data,2); + if(los(pos,posfix))damage((integer)amt,id,pos,posfix,0.0,name); + else damage((integer)amt,id,pos,targetPos,0.0,name); + } + else damage((integer)amt,id,pos,targetPos,tmod,name); + } + } + else damage((integer)amt,id,pos,targetPos,0.0,name); + } + } + } + collision_start(integer c) + { + if(llVecMag(llDetectedVel(0))>40.0) + { + vector gpos=llGetPos(); + if(tracker==[])llSetTimerEvent(1.0); + string name=llDetectedName(0); + integer f=llListFindList(tracker,[name]); + if(f>-1)tracker=llListReplaceList(tracker,[collisionmod(gpos,llDetectedPos(0))],f+1,f+1); + else + { + if(llGetListLength(tracker)>10)tracker=llDeleteSubList(tracker,0,1);//Delete eldest entry to prevent stack-heap + tracker+=[name,collisionmod(gpos,llDetectedPos(0))]; + } + //Stores data as follows: OBJECT_NAME,OBJECT_MODIFIER + //Updates objects of the same name to the most recent. + } + } + timer() + { + bantracker=[]; + tracker=[];//Reset tracker + if(tar(gen))return;//Auto-deleter + llDie(); + } +} diff --git a/LBHD, Directional Armor v1.4.3.lsl b/LBHD, Directional Armor v1.4.3.lsl new file mode 100644 index 0000000..2254b99 --- /dev/null +++ b/LBHD, Directional Armor v1.4.3.lsl @@ -0,0 +1,199 @@ +string ver="DHv1.4.3";//LBA Version +integer mhp=200;//Maximum HP +integer hp=mhp;//Current HP +//Positive Numbers Deal Damage +//Negative Numbers Restore Health +//Damage Multipliers: 0 = Invulnerable, 1.0 = 100% Damage, High numbers = Higher Damage +//The total between all values should be around 5.0 for balancing purposes. +integer atcap=200; +float front=0.5; +float side=1.0; +float back=1.5; +float middle=0.1; +//Note that following modifiers multiply the final damage. So it stacks multiplicatively with the previous modifiers +float top=1.2; +float bottom=1.5; +//Directional Processor +float front_threshold=25.0;//Use positive floats, determines forward range +float back_threshold=155.0;//Use positive floats, determines backward range +float top_threshold=0.75;//How far up the Z axis should the source be to registered a top. (Positive Number) +float bottom_threshold=-0.75;//How far down the Z axis should the source be to registered a bottom hit. (Negative Number) +float collisionmod(vector pos, vector targetPos) +{ + if(targetPos) + { + float dist=llVecDist(pos,targetPos); + if(dist<1.0)return middle;//This catches explosions which rezzes AT in the object's root position. + else + { + vector fpos=(targetPos-pos)/llGetRot(); + float mod=fpos.z; + if(mod>=top_threshold)mod=top;//Top check + else if(mod<=bottom_threshold)mod=bottom;//Bottom check + else mod=1.0;//Else reset it to 1.0 + vector angle=<1.0,0.0,0.0>*llGetRot(); + angle.z=0.0; + rotation targetRot=llRotBetween(llVecNorm(angle),llVecNorm(-pos)); + vector targetRotVec=llRot2Euler(targetRot)*RAD_TO_DEG; + if(targetRotVec.z>-front_threshold&&targetRotVec.zback_threshold)//Back + return back*mod; + else //If it didn't hit any previous angles, the only thing left to hit is the sides. + return side*mod; + } + } + else return 0.0; +} +//Damage Processor +damage(integer amt, key id,vector pos, vector targetPos, float tmod, string name) +{ + if(amt>atcap)amt=atcap; + if(amt<0)//Allows the object to be healed/repaired + { + if(llGetTime()>1.0)//Optional healing cooldown + { + amt*=-1.0; + if(amt>(float)hp*0.1)amt=llRound(hp*0.1);//Optional healing cap + hp+=amt; + if(hp>mhp)hp=mhp;//Used to prevent overhealing + llResetTime(); + } + //Be sure to update the listen event code block to allow negative damage values through. + } + /*else if(amt<6)return; //Blocks micro-LBA*/ + else + { + integer directional_amt; + if(tmod)directional_amt=llFloor(amt*tmod); + else directional_amt=llFloor(collisionmod(pos,targetPos)*(float)amt); + if(directional_amt)hp-=directional_amt; + else //Failed to do damage + { + llOwnerSay("Damage Blocked by Armor"); + llRegionSayTo(llGetOwnerKey(id),0,"Attack was stopped by armor."); + return; + } + llOwnerSay("/me took "+(string)directional_amt+" ("+(string)amt+") damage from "+name+" by "+llKey2Name(llGetOwnerKey(id)));//Used to debug output. + llRegionSayTo(llGetOwnerKey(id),0,"/me took "+(string)directional_amt+" ("+(string)amt+") damage"); + } + if(hp<1)die(); + else update(); +} +string modifierstring;//This is visible so moderators can confirm vehicle attributes are within regulation. +update()//SetText +{ + llSetLinkPrimitiveParamsFast(-4,[PRIM_TEXT,"[LBHD]\n "+(string)hp+" / "+(string)mhp+" HP",<0.0,0.75,1.0>,1.0, + PRIM_DESC,"LBA.v."+ver+","+(string)hp+","+(string)mhp+","+(string)atcap+",999"+modifierstring]); + //In order: Current HP, Max HP, Max AT accepted, Max healing accepted (Not implemented) +} +die() +{ + //Add extra shit here + //llResetScript();//Debug + llDie();//Otherwise, use this +} +integer los(vector start, vector target)//1=LoS,0=Obstructed +{ + list ray=llCastRay(start,target,[RC_REJECT_TYPES,RC_REJECT_AGENTS,RC_DATA_FLAGS,RC_GET_ROOT_KEY,RC_MAX_HITS,1]); + if(llList2Vector(ray,1)==ZERO_VECTOR)return 1; + else return 0; +} +vector tar(key id)//Deprecated +{ + vector av=(vector)((string)llGetObjectDetails(id,[OBJECT_POS])); + return av; +} +key user; +key gen;//Object rezzer +key me; +integer hear; +list tracker; +boot() +{ + modifierstring=",F-"+llGetSubString((string)front,0,2)+//Frontal modifier + ",S-"+llGetSubString((string)side,0,2)+//Side modifier + ",R-"+llGetSubString((string)back,0,2)+//Rear modifier + ",T-"+llGetSubString((string)top,0,2)+//Top modifier + ",B-"+llGetSubString((string)bottom,0,2)+//Bottom modifier + ",M-"+llGetSubString((string)middle,0,2);//Middle Modifier + user=llGetOwner(); + me=llGetKey(); + gen=(string)llGetObjectDetails(me,[OBJECT_REZZER_KEY]); + if(hear)llListenRemove(hear); + integer hex=(integer)("0x" + llGetSubString(llMD5String((string)me,0), 0, 3)); + hear=llListen(hex,"","",""); + llSetTimerEvent(1.0);//Used for auto-delete. + update(); +} +default +{ + state_entry() + { + boot(); + } + on_rez(integer p) + { + if(p>1)//Allows HUD/Objects to set HP value when rezzed with a param, otherwise uses default + { + mhp=p; + hp=p; + } + boot(); + } + listen(integer chan, string name, key id, string message) + { + //[ALWAYS] USE llRegionSayTo(). Do not flood the channel with useless garbage that'll poll every object in listening range. + list parse=llParseString2List(message,[","],[" "]); + if(llList2Key(parse,0)==me)//targetcheck + { + list data=llGetObjectDetails(id,[OBJECT_POS,OBJECT_ATTACHED_POINT,OBJECT_ROT,OBJECT_REZZER_KEY]); + vector pos=llGetPos(); + vector targetPos=llList2Vector(data,0); + float tmod; + integer f=llListFindList(tracker,[name]); + if(f>-1)tmod=llList2Float(tracker,f+1); + else //Rezzer rezzer's rezzer rezzer + { + f=llListFindList(tracker,[llList2Key(data,4)]); + if(f>-1)tmod=llList2Float(tracker,f+1); + } + float amt=llList2Float(parse,-1); + if(llFabs(amt)<666.0) + { + if(llList2Integer(data,1)) + { + float dist=llVecDist(targetPos,pos)-2.0; + vector posfix=targetPos+*llList2Rot(data,2); + if(los(pos,posfix))damage((integer)amt,id,pos,posfix,0.0,name); + else damage((integer)amt,id,pos,targetPos,0.0,name); + } + else damage((integer)amt,id,pos,targetPos,tmod,name); + } + } + } + collision_start(integer c) + { + if(llVecMag(llDetectedVel(0))>40.0) + { + vector gpos=llGetPos(); + if(tracker==[])llSetTimerEvent(1.0); + string name=llDetectedName(0); + integer f=llListFindList(tracker,[name]); + if(f>-1)tracker=llListReplaceList(tracker,[collisionmod(gpos,llDetectedPos(0))],f+1,f+1); + else + { + if(llGetListLength(tracker)>10)tracker=llDeleteSubList(tracker,0,1);//Delete eldest entry to prevent stack-heap + tracker+=[name,collisionmod(gpos,llDetectedPos(0))]; + } + //Stores data as follows: OBJECT_NAME,OBJECT_MODIFIER + //Updates objects of the same name to the most recent. + } + } + timer()//Auto-deleter. Will kill object if avatar leaves the region or spawning object is removed. + { + tracker=[];//Reset tracker + if(tar(gen))return; + llDie(); + } +} diff --git a/LBHD-Component, v1.4.4.lsl b/LBHD-Component, v1.4.4.lsl new file mode 100644 index 0000000..1ed6d6c --- /dev/null +++ b/LBHD-Component, v1.4.4.lsl @@ -0,0 +1,315 @@ +//MBTLBA was a stupid name +string ver="DHCv1.4.4";//LBA Version +//efx +integer burning;//burning flag +integer repair;//repair timer +integer detrack;//detrack flah +integer layer;//detrack layers +integer ml;//Mouselook tracker +integer emk;//em kit +// +integer mhp=250;//Maximum HP +integer hp=mhp;//Current HP +//Positive Numbers Deal Damage +//Negative Numbers Restore Health +//Damage Multipliers: 0 = Invulnerable, 1.0 = 100% Damage, High numbers = Higher Damage +integer atcap=500; +float front=0.5; +float side=1.0; +float back=1.5; +float middle=0.1; +//Note that following modifiers multiply the final damage. So it stacks multiplicatively with the previous modifiers +float top=1.2; +float bottom=1.2; +//Directional Processor +float front_threshold=20.0;//Use positive floats, determines forward range +float back_threshold=160.0;//Use positive floats, determines backward range +float top_threshold=0.75;//How far up the Z axis should the source be to registered a top. (Positive Number) +float bottom_threshold=-0.75;//How far down the Z axis should the source be to registered a bottom hit. (Negative Number) +vector collisionmod(vector pos, vector targetPos) +{ + if(targetPos) + { + float trak; + float dist=llVecDist(pos,targetPos); + if(dist<1.0)return <0.01,0.0,0.0>;//This catches explosions which rezzes AT in the object's root position. + else + { + vector fpos=(targetPos-pos)/llGetRot(); + float mod=fpos.z; + if(mod>=top_threshold)mod=top;//Top check + else if(mod<=bottom_threshold) + { + ++trak;//Chance to detrack + mod=bottom;//Bottom check + } + else mod=1.0;//Else reset it to 1.0 + vector angle=<1.0,0.0,0.0>*llGetRot(); + angle.z=0.0; + rotation targetRot=llRotBetween(llVecNorm(angle),llVecNorm(-pos)); + vector targetRotVec=llRot2Euler(targetRot)*RAD_TO_DEG; + if(targetRotVec.z>-front_threshold&&targetRotVec.z; + else if(targetRotVec.z<-back_threshold||targetRotVec.z>back_threshold)return ;//chance to burn + else return ; + } + } + else return ZERO_VECTOR; +} +//Damage Processor +damage(integer amt, key id,vector pos, vector targetPos,vector tmod,string name) +{ + //Tmod Dump: Damage modifier, Did I detrack?, Did I burn? + if(amt>atcap)amt=atcap; + if(amt<0)//Allows the object to be healed/repaired + { + if(llGetTime()>1.0)//Optional healing cooldown + { + if(burning||detrack) + { + burning=0; + detrack=0; + llMessageLinked(-4,1,"",""); + llOwnerSay("Status Repaired"); + } + amt*=-1.0; + if(amt>(float)hp*0.1)amt=llRound(hp*0.1);//Optional healing cap + hp+=amt; + if(hp>mhp)hp=mhp;//Used to prevent overhealing + llResetTime(); + } + //Be sure to update the listen event code block to allow negative damage values through. + } + else if(amt<6) + { + llRegionSayTo(llGetOwnerKey(id),0,"*plink*"); + return; //Blocks micro-LBA, stop that shit + } + else + { + key oid=llGetOwnerKey(id); + integer directional_amt; + if(tmod==ZERO_VECTOR)tmod=collisionmod(pos,targetPos); + directional_amt=llFloor(tmod.x*(float)amt); + if(tmod.y>0.0&&!detrack) + { + if(llFrand(100.0)-amt<0.0)//roll for detrack + { + if(layer>1) + { + llTriggerSound("9213b540-c8de-c7a6-a228-fa3569c5c6ae",1.0); + llOwnerSay("Tracks hit!"); + layer=0; + } + else + { + ++detrack; + list sounds=["af44ee43-b6c8-130a-161d-19282010a84e","d6190a72-9221-3b24-4d0a-a206923f63f1"]; + llTriggerSound(llList2String(sounds,llRound(llFrand(1.0))),1.0); + llOwnerSay("De-tracked!"); + if(!burning)llMessageLinked(-4,0,"",""); + repair=0; + } + } + } + if(tmod.z>0.0&&!burning) + { + if(llFrand(100.0)-amt<0.0)//roll for burn + { + ++burning; + list sounds=["f288bc4f-62bd-9ca1-501e-3afb42d23ef5","2caf350b-ecae-2bc4-1c27-8e7c16ab9e11"]; + llTriggerSound(llList2String(sounds,llRound(llFrand(1.0))),1.0); + llMessageLinked(-4,2,"",""); + repair=0; + } + } + if(directional_amt>1.0) + { + list sounds=["a6c864a1-015a-83d1-bc63-d4b2d5df8482","fd462a07-c691-585c-1c2b-63554c0a71eb","91e2c1a7-238d-b7a7-43b2-00a7fe8f371e"]; + llTriggerSound(llList2String(sounds,llRound(llFrand(2.0))),1.0); + hp-=directional_amt; + } + else //Failed to do damage + { + llOwnerSay("Damage Blocked by Armor"); + llRegionSayTo(llGetOwnerKey(id),0,"Attack was stopped by armor."); + return; + } + llOwnerSay("/me took "+(string)directional_amt+" ("+(string)amt+") damage from "+name+" by "+llKey2Name(oid));//Used to debug output. + llRegionSayTo(oid,0,"/me took "+(string)directional_amt+" ("+(string)amt+") damage"); + } + if(hp<1)die(); + else update(); +} +string modifierstring;//This is visible so moderators can confirm vehicle attributes are within regulation. +update()//SetText +{ + string mod="\n"; + if(burning||detrack) + { + if(burning)mod+="[Burning] "; + if(detrack)mod+="[Detracked]"; + if(!ml)mod+="\n Repair-in-Progress \n"+(string)((integer)repair*10)+"/100"; + } + llSetLinkPrimitiveParamsFast(-4,[PRIM_TEXT,"[LBHD]\n "+(string)hp+" / "+(string)mhp+" HP"+mod,<0.0,0.75,1.0>,1.0, + PRIM_DESC,"LBA.v."+ver+","+(string)hp+","+(string)mhp+","+(string)atcap+",666"+modifierstring]); + //In order: Current HP, Max HP, Max AT accepted, Max healing accepted (Not implemented) +} +die() +{ + llRezObject("Explosion",llGetPos(),ZERO_VECTOR,ZERO_ROTATION,1); + //Add extra shit here + //llResetScript();//Debug + llDie();//Otherwise, use this +} +vector tar(key id) +{ + vector av=(vector)((string)llGetObjectDetails(id,[OBJECT_POS])); + return av; +} +key user; +key gen;//Object rezzer +key me; +integer hear; +boot(integer entry) +{ + modifierstring=",F-"+llGetSubString((string)front,0,2)+//Frontal modifier + ",S-"+llGetSubString((string)side,0,2)+//Side modifier + ",R-"+llGetSubString((string)back,0,2)+//Rear modifier + ",T-"+llGetSubString((string)top,0,2)+//Top modifier + ",B-"+llGetSubString((string)bottom,0,2)+//Bottom modifier + ",M-"+llGetSubString((string)middle,0,2);//Middle Modifier + user=llGetOwner(); + me=llGetKey(); + gen=(string)llGetObjectDetails(me,[OBJECT_REZZER_KEY]); + if(hear)llListenRemove(hear); + integer hex=(integer)("0x" + llGetSubString(llMD5String((string)me,0), 0, 3)); + hear=llListen(hex,"","",""); + llSetTimerEvent(1.0);//Used for auto-delete. + update(); + if(entry)return; + emk=(integer)("0x" + llGetSubString(llMD5String(user,0), 1, 4)); + llListen(emk,"","","emk"); +} +list tracker; +default +{ + state_entry() + { + boot(1); + } + on_rez(integer p) + { + boot(0); + } + listen(integer chan, string name, key id, string message) + { + //[ALWAYS] USE llRegionSayTo(). Do not flood the channel with useless garbage that'll poll every object in listening range. + if(chan==emk) + { + if(llGetOwnerKey(id)!=user)return; + if(detrack) + { + list sounds=["62fafb58-f350-632c-c16d-8928514d52d8","47c80392-832f-8212-a42e-00437fa7ff01"]; + llTriggerSound(llList2String(sounds,llRound(llFrand(1.0))),1.0); + detrack=0; + if(!burning)llMessageLinked(-4,1,"",""); + } + else + { + if(layer<1)++layer; + llOwnerSay("Protected "+(string)layer+" track(s)"); + } + } + else + { + list parse=llParseString2List(message,[","],[" "]); + if(llList2Key(parse,0)==me)//targetcheck + { + list data=llGetObjectDetails(id,[OBJECT_POS,OBJECT_ATTACHED_POINT,OBJECT_ROT,OBJECT_REZZER_KEY]); + vector pos=llGetPos(); + vector targetPos=llList2Vector(data,0); + vector tmod; + integer f=llListFindList(tracker,[name]); + if(f>-1)tmod=llList2Vector(tracker,f+1); + else //Rezzer rezzer's rezzer rezzer + { + f=llListFindList(tracker,[llList2Key(data,4)]); + if(f>-1)tmod=llList2Vector(tracker,f+1); + } + float amt=llList2Float(parse,-1); + if(llFabs(amt)<666.0) + { + if(llList2Integer(data,1)) + { + float dist=llVecDist(targetPos,pos)-1.25;//Backtrack so we don't end up triggering the middle filter. + vector posfix=targetPos+*llList2Rot(data,2);//Do math + if(llVecDist(pos,posfix)<5.0)damage((integer)amt,id,pos,posfix,ZERO_VECTOR,name); + //Check offset to prevent camera-related oofs. + //This technically drops damage but w/e, not a huge issue. + } + else + { + if(tmod)damage((integer)amt,id,pos,targetPos,tmod,name); + else damage((integer)amt,id,pos,targetPos,ZERO_VECTOR,name); + } + } + } + } + } + collision_start(integer c) + { + if(llVecMag(llDetectedVel(0))>40.0) + { + vector gpos=llGetPos(); + if(tracker==[])llSetTimerEvent(1.0); + string name=llDetectedName(0); + integer f=llListFindList(tracker,[name]); + if(f>-1)tracker=llListReplaceList(tracker,[collisionmod(gpos,llDetectedPos(0))],f+1,f+1); + else + { + if(llGetListLength(tracker)>10)tracker=llDeleteSubList(tracker,0,1);//Delete eldest entry to prevent stack-heap + vector cmod=collisionmod(gpos,llDetectedPos(0)); + if(cmod)tracker+=[name,cmod]; + } + //Stores data as follows: OBJECT_NAME,OBJECT_MODIFIER + //Updates objects of the same name to the most recent. + } + } + timer() + { + if(burning||detrack) + { + ml=llGetAgentInfo(user)&AGENT_MOUSELOOK; + if(ml)repair=0; + else if(++repair>9) + { + if(burning) + { + list sounds=["ada6486e-81ef-667b-0a92-17f20184a7eb","fa2f0288-f012-6741-948c-da30f5cfff68","c13344d6-a9b1-3541-5f40-f0703ce97b8d","2a4d1e97-24ec-250b-ac1c-8e2e9134be26","f0fc1dc6-b4b3-f7bf-a3ce-6961845afbad"]; + llTriggerSound(llList2String(sounds,llRound(llFrand(4.0))),1.0); + burning=0; + if(!detrack)llMessageLinked(-4,1,"",""); + llOwnerSay("Fire is out"); + } + else if(detrack) + { + list sounds=["62fafb58-f350-632c-c16d-8928514d52d8","47c80392-832f-8212-a42e-00437fa7ff01"]; + llTriggerSound(llList2String(sounds,llRound(llFrand(1.0))),1.0); + detrack=0; + llMessageLinked(-4,1,"",""); + llOwnerSay("Tracks repaired"); + } + repair=0; + update(); + } + if(burning) + { + hp-=5; + if(hp>0)update(); + else die(); + } + } + if(tar(gen))return; + llDie(); + } +} diff --git a/README.md b/README.md index 57f76bd..d8ce5eb 100644 --- a/README.md +++ b/README.md @@ -1,80 +1,21 @@ -# Listen Based Armor (LBA) -Performant listen based armour for the Secondlife Military Community. +# Listen-Based Health +Non-Fork of LBH, ported from https://github.com/MalefactorIX/SLMCLBA/tree/master/LBH -This repository contains the most up-to-date and lag-free scripts for LBA, as well as the documentation provided by upstream. +[IMPORTANT] -# Migrating from Legacy LBA -The version of LBA that is currently distributed is no longer maintained. +This requires vehicles/deployables to be aligned properly down the X-axis in order to function properly. Objects which require a rotational offset to function will need to be adjusted. -Simply delete your old LBA scripts, and follow the instructions below under "Usage." +Some settings may make the system incompatible with certain rulesets and equipment. However, notes and code for switching these features on and off is present for those who wish to use them. -The GLBA scripts to use as a replacement for the legacy scripts is as follows: +Do [not] use LBHD systems as your default LBA parser as it would not be optimized for use in equipment that has no intention of benefitting from directional damage resistances. Use a standard LBA or LBH-Slim/AG core instead. -| Legacy Script Name | GLBA Script | -|--------------------|-------------| -|LBA-Light-Deployable-vX.XX.lsl|Use GLBA-Slim| -|LBA-Light-vX.XX.lsl|Use GLBA-Slim| -|LBA-Slim-v.X.XX.lsl|Use GLBA-Slim| -|LBA-v.2.32.lsl|Use GLBA-Vehicles| -|LBA-D-v2.32-rc3.lsl|Directional GLBA has not yet been released, continue using legacy| +[VERSIONS] -## Compatibility -GLBA is fully compatible with **all** LBA-compliant weaponry, vehicles, and deployables. +Slim - Basic Parser, can support Collision Damage. -# Usage +AG - Anti-Grief System Included -## GLBA-Slim.lsl: Deployable Objects +HD - Directional Armor, does not support Collision Damage. -Create a new script in your deployable and copy/paste the LSL code in `GLBA-Slim.lsl` into it, and hit "Save". +Component - Includes component system -Take the deployable into your inventory and deploy it as needed. - -## GLBA-Vehicles.lsl: Vehicles - -GLBA-Vehicles is meant to be used for vehicles that are meant to be driven, such as tanks, gunships, air ships, boats, cars, golf carts, etc. - -Create a new script in your deployable and copy/paste the LSL code in `GLBA-Vehicles.lsl` into it, and hit "Save". - -Take the vehicle into your inventory and rez it where you want. - -# Contributing - -## Basics -For those new to git, or the open source GitHub experience, I highly recommend you complete the basic [GitHub "Hello World" Tutorial](https://guides.github.com/activities/hello-world/) before contributing. - -Once or if you understand the essentials of git and/or GitHub, follow this tutorial to fork this repository: - -["Forking" a Repository](https://guides.github.com/activities/forking/) - -Once you have created a fork, and modified it, you can submit a pull request by going to [uncertain-string/SLMCA/pulls](https://github.com/uncertain-string/SLMCLBA/pulls) and hitting "New pull request." - -GitHub has provided this tutorial on [How to Collaborate using Pull Requests from a Fork](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork) - -If you need help, contact `frick.teardrop`. - -## Help -If you have any further questions, contact `frick.teardrop` in Second Life. Frick is always happy to help anybody understand open source projects, and how git (and collaborating within GitHub) works. - - -# Performance Results - -The numbers represented in these tables are script time, the average number of seconds (over around a 30 minute window) that each script performs work during a simulator frame. - -The results are sorted by the difference between idle and active states. The lowest difference between states wins, as the difference is the _actual_ amount of active script time that the script uses per frame during combat. - -Idle state is after rezzing and waiting 10 minutes for script time to settle. - -Active state is after being hit with 5,000 collisions & listen events over 5 minutes. - -You will notice that homesteads have higher script time. This is because there is 1/4th of the CPU time normally available per frame as they are homesteads. Thanks to optimizations from the mono project, the realized difference in performance is minimal between homesteads and full sims. - -## Full Sim Hybrid RC Statistics - -![image](https://user-images.githubusercontent.com/28276562/148669447-ed65f290-3571-46c6-9d1b-6e28d6a8462b.png) - -## Homestead Hybrid RC Statistics - -![image](https://user-images.githubusercontent.com/28276562/148669457-07c7ced3-ba6f-4fd0-bf9d-f4077c0c75b1.png) - -## Notes -You will notice that full sims report a higher script time average, this is because full sims have 4 times the capacity of a homestead, so they schedule far more script executions per frame, and allocate far more CPU time for scripts per frame than homesteads.