@name Suicidal Removal Robot
@inputs Grabber:wirelink
@outputs F:entity Grab GotIt Scan:entity [Target]:array Master Self  Down Up Object:string
@persist [S E O F]:entity Ro:ranger [Safe]:array SAFE:string
@persist Self Master #use this number for all your networking needs
@persist Object:string
@model models/jaanus/thruster_flat.mdl
@trigger 
if(duped()){reset()}
runOnChat(1)
#O=owner()
Chat=owner():lastSaid()
if(chatClk()&(Self==Master)){
    if(Chat=="get this"&O:aimEntity()){
        Object=O:aimEntity():type() 
        gSetStr("object",Object)
        print("Suicidal Hived Remover Drones have targeted: "+Object)
    }
    if(Chat=="clear it"){
        Object=""
        gSetStr("object","")
        print("Suicidal Hived Remover Drones have cleared their targets")
    }
}
if(first()){Object=gGetStr("object")}

#suicidal object destruct code
GotIt=Grabber["Grabbed Entity",entity]==F
if(Grabber:entity()&F&GotIt){timer("suicide",500)}

if(Master==Self){Object=gGetStr("object")}
#D-Link Network Code Copy and paste this into your contraption
#by Captain Maim
gSetGroup("Remover Robot")
if(duped()){reset()}
runOnLast(1)
Diag=0 #this prints network reports to chat
NetMax=20 #this is the maximum number of networked units, surplus units are removed automatically.
ID="ID"
Erase=0 #set this to 1 to erase the entire unit network, (diagnostic only)
MasterInterval=500 #frequency units check for updates on who is the master unit.
HiveMind=1 #1 enables a client/server AKA master/slave mode (used for hiveminds.) 0 limits use to simple network ID generation.
Brk="<" #separation or "break" character, used to create a unique string to help mass search the network table with.
if(!Self){
    EID=entity():id()
    EIDS=toString(EID)
    ScanN=gGetStr(ID) 
    NetT=glonDecodeTable(ScanN) 
    for(C=1,NetMax){if(!ScanN:find(Brk+C)){Self=C break}} #locate a hole and take that slot
    if(HiveMind){
        for(C=1,NetMax){if(ScanN:find(Brk+C)){Master=C break}} #locate first unit and mark that unit
        if(!Master){Master=Self}
    }
    if(!Self){
        if(Diag){print("Self Destructing Excess Clones!")} 
        selfDestructAll()
    }
    NetT[Brk+Self,number]=EID
    if(Self==Master&HiveMind){gSetNum("master",Self)}
    gSetStr(ID,glonEncode(NetT))
    if(Diag){print("Self="+Self)} #you can remove this if you want it's diagnostic
}
if(last()){
    NetT=glonDecodeTable(gGetStr(ID))
    NetT:remove(Brk+Self)
    if(Self==Master&HiveMind){ #passing the torch
        for(C=1,NetMax){
            if(NetT[Brk+C,number]){
                gSetNum("master",C)
                Master=0
                if(Diag){print("Unit "+Self+" is passing leadership to "+C)}
                break
            }
        }
        if(Master){ #if there is no unit to pass the torch to
            gSetNum("master",0) 
            if(Diag){print("Unit "+Self+" was unable to pass leadership.")}
        }
    }
    gSetStr(ID,glonEncode(NetT))
    if(Diag){print("Unit "+Self+" Deleted")} #diagnostic non critical
}
if(Erase){gSetStr(ID,"") gSetStr("master","") gSetStr("robots","")}
#periodically checks to see if the master has passed the torch
if(HiveMind){
    timer("master",MasterInterval)
    if(clk("master")){Master=gGetNum("master")}
    
    #Add your own targeting code below
    if(findCanQuery()){
        #This collpases the unit spread and organizes their orders.        
        NetT=glonDecodeTable(gGetStr(ID))
        Units=array() 
        Orders=table()
        for(C=1,NetMax){if(NetT[Brk+C,number]){Units:pushNumber(C)}} #collapse the spread of units on the network 
        Orders=invert(Units) #we want the collapsed units indexed by self ID
        
        if(Master==Self){ #actions for the network master
############your find functions here################
            SAFETY=gGetStr("robots"):explode("<")
            Safety=array()
            for(C=1,SAFETY:count()){
                Safety:pushEntity(entity(SAFETY[C,string]:toNumber()))
            }
            if(Object){
                findInSphere(entity():pos(),20000)
                findSortByDistance(entity():pos())
                findIncludeClass(Object)
                findExcludeEntities(Safety)
                findExcludeEntities(Safe)
            }
#############then let this command the hive#########
            Target=findToArray()
            gSetStr("Target",glonEncode(Target)) #issues orders to slaves
        }else{Target=glonDecode(gGetStr("Target"))} #all slaves take orders
    F=Target[Orders[toString(Self),number],entity] #if there are more units than targets the surplus units are idle.
    }
}
#End of D-Link Network Code
if(last()|clk("suicide")){
    Robots=gGetStr("robots")
    if(clk("suicide")){selfDestructAll()}
    gSetStr("robots",Robots:replace(SAFE,""))
}
#these little bit identifies the master network ID as the lowest existing ID.
#ScanN=gGetStr(ID)
#NetT=glonDecodeTable(ScanN) 
#for(C=1,NetMax){if(ScanN:find(Brk+C+Brk)){Master=C break}} 

#End of D-Link Network Code


#LFire=owner():keyUse()
S=Grabber:entity()
#Self=Grabber:entity()
HH=50 #hover height
Up=Down=0
#####ranger trances and attack behavior######
if(!F){
    XYZ=entity():pos()+vec(0,0,HH)
}else{ #GO GET IT
    Safe1=Safe:clone()
    Safe1:pushEntity(F)
    rangerFilter(Safe1)
    Up=rangerOffset(F:radius()+HH,F:pos(),vec(0,0,1)):hit()
    rangerFilter(Safe1)
    Down=rangerOffset(F:radius()+HH,F:pos(),vec(0,0,-1)):hit()
    if(Down){XYZ=F:pos()+vec(0,0,F:radius()+HH)}
    elseif(Up){XYZ=F:pos()+vec(0,0,F:radius()-HH)}
#        else{
#        rangerFilter(Safe1)
#        Left=rangerOffset(F:radius()+HH,F:pos(),vec(0,-1,0)):hit()
#        rangerFilter(Safe1)
#        Right=rangerOffset(F:radius()+HH,F:pos(),vec(0,1,0)):hit()
#        rangerFilter(Safe1)
#        For=rangerOffset(F:radius()+HH,F:pos(),vec(1,0,0)):hit()
#        rangerFilter(Safe1)
#        Aft=rangerOffset(F:radius()+HH,F:pos(),vec(-1,0,0)):hit()
#        if(Left){XYZ=F:pos()+vec(0,F:radius()+HH,0)}
#        elseif(Right){XYZ=F:pos()+vec(0,F:radius()-HH,0)}
#        elseif(For){XYZ=F:pos()+vec(F:radius()-HH,0,0)}
#        elseif(Aft){XYZ=F:pos()+vec(F:radius()+HH,0,0)}
#        else{XYZ=entity():pos()+vec(0,0,HH)}
#        }
    rangerFilter(Safe)
    Scan=rangerOffset(1000,S:pos(),S:up()):entity()
    if(Scan==F){
        Grab=1
    }else{Grab=0}
}
Strength=1000
Grabber["Grab",number]=Grab
Grabber["Strength",number]=Strength

Speed=100*(S:mass()/4)
S:applyForce(Speed*(XYZ-S:pos())-(S:vel()/2)*S:mass())



if(first()|dupefinished()){
    
    runOnTick(1)
    O = owner()
    E = entity()
    #S = Self
    #G = Grab:entity()
    #G:setMass(50000)
    Safe=array(S,Grabber:entity(),entity())
    Robots=gGetStr("robots")
    SAFE=S:id()+"<"+Grabber:entity():id()+"<"+entity():id()+"<"
    Robots=Robots+SAFE
    #print(Robots)
    #rangerFilter(Safe)
    rangerPersist(0)
    gSetStr("robots",Robots)
}
#if(last()|clk("suicide")){ #my robot arm is being removed from the network
#    gSetStr("robots",gGetStr("robots"):replace(SAFE,""))
#}

#if(findCanQuery()){
#    if(Master==Self){
#        SAFETY=gGetStr("robots"):explode("<")
#        
#        Safety=array()
#        for(C=1,SAFETY:count()){
#            Safety:pushEntity(entity(SAFETY[C,string]:toNumber()))
#        }
#        if(Object){
#            findInSphere(entity():pos(),20000)
#            findSortByDistance(entity():pos())
#            findIncludeClass(Object)
#            findExcludeEntities(Safety)
#            findExcludeEntities(Safe)
#            #findExcludePlayerProps(O)
#        }
#        gSetStr("Target",glonEncode(findToArray())) #issues orders to slaves
#        F = find() #takes self order
#    }else{
#        Target=glonDecode(gGetStr("Target"))
#        F=Target[Self,entity]
#    }
#}

Pos = E:toWorld(vec(0,0,40))

Dir = S:pos()-(F:pos()+F:vel()/(10))

AltAng = E:angles()
Q = quat(Dir:toAngle())*qRotation(vec(0,1,0),-90)
S:applyTorque((150*S:toLocal(rotationVector(Q/quat(S))+S:pos()) - 12*S:angVelVector())*S:inertia())


