@name User Turret
@inputs  Num:wirelink
@outputs Fire Latch
@persist Time Self:entity InertiaConstant Inertia:angle RS Enemy:entity 
@persist Record Buttons:array Pos:array XYZ:vector Button
#Prefix for save and load
Prefix="UT - "+map()+" "
Txt=".txt"
O=owner()
Home=entity():pos()+vec(0,0,50)
runOnChat(1)
Chat=owner():lastSaid()
Com="UT"  #Contraption name, always say this to address the contraption
Rec="rec" #say this plus On1 or On0 to use record function
On1="on" #say this plus a toggled function to enable
On0="off" #say this with a toggled function to disable
Save="save" #say this then Break and then unique name to save
Load="load" #say this and then Break and then unique name that you saved to to load
Clear="clear" #say this to delete all recorded button locations
Remove="rem" #removes last button recorded
Break="<"  #this is used to separate the commands from string or numeric inputs
Show="show" #places a hologram where buttons and press locations were recorded at
Press="!"

#checks that the user said the various command words
COM=Chat:find(Com)
REC=Chat:find(Rec)
ON1=Chat:find(On1)
ON0=Chat:find(On0)
SAVE=Chat:find(Save)
LOAD=Chat:find(Load)
CLEAR=Chat:find(Clear)
REMOVE=Chat:find(Remove)
BRK=Chat:find(Break)
SHOW=Chat:find(Show)
PRESS=Chat:find(Press)

if(COM&chatClk()){
    if(REC){
        if(ON1){
            print("Button record mode enabled")
            Record=1
            timer(Rec,1)
        }elseif(ON0){
            print("Button recorde mode disable")
            Record=0
            stoptimer(Rec)
        }
    }
    if(PRESS){
        Button=Chat:explode(Press)[2,string]:toNumber()
        Holo=1
    }
    if(BRK){
        if(SAVE){
            Name=Chat:explode(Break)[2,string]
            Dump=array()
            Dump[1,string]=glonEncode(Pos)
            Dump[2,string]=glonEncode(Buttons)
            Pile=glonEncode(Dump)
            fileWrite(Prefix+Name+Txt,Pile)
        }
        if(LOAD){
            Name=Chat:explode(Break)[2,string]
            if(fileRead(Prefix+Name+Txt)){
                Pile=fileRead(Prefix+Name+Txt)
                Dump=glonDecode(Pile)
                Pos=glonDecode(Dump[1,string])
                Buttons=glonDecode(Dump[2,string])
                Count=Pos:count()
                print("File Loaded! "+Count+" button locations found!")
            }else{
            print("File Loading Please wait 10 seconds")
            fileLoad(Prefix+Name+Txt)
            timer("load",10000)
            }
        }
    }
    if(REMOVE){
        print("The last recorded button location "+Buttons:count()+" has been removed.") 
        Buttons:popVector()
        Pos:popVector()
        
    }
    if(CLEAR){
        print("deleting all stored button locations")
        Buttons=array()
        Pos=array()
    }    
}
if(Holo){
    for(C=1,Pos:count()){
        holoCreate(C,Pos[C,vector])
        holoCreate(C+1,Buttons[C,vector])
        holoColor(C,vec(0,255,0))
        holoColor(C+1,vec(0,0,255))
    }
    Holo=0
}else{
    if(holoEntity(1)){
        for(C=1,Pos:count()){
            holoDelete(C)
        }
    }
}

if(Record&clk(Rec)){
timer(Rec,500)
    if(O:keyUse()&O:shootPos():distance(O:aimPos())<100){
        Buttons:pushVector(O:aimPos())
        Pos:pushVector(O:shootPos())
        print("Button "+Pos:count()+" was recorded!")
    }
}
Fire=0
if(Button){
    Latch=0
    XYZ=Pos[Button,vector]
    AttackPosition=Buttons[Button,vector]
    rangerFlags("EZ")
    if(!rangerOffset(Pos[Button,vector],Buttons[Button,vector]):hit()){
        Fire=1
        XYZ=vec()
        AttackPosition=vec()
        Button=0
    }
}
if(Self:pos():distance(Home)<1){
    Latch=1
}

if(!AttackPosition){AttackPosition=entity():pos()}
if(duped()){reset()}
if (tickClk()) {

if (Enemy:isPlayer()|Enemy:isNPC()) {
    EnemyPosition = Enemy:pos()
    EnemyPosition += vec(0,0,Enemy:height()/2)
} else {
    EnemyPosition = Enemy:massCenter()
}
EnemyVelocity = Enemy:vel()

#######################################
#rotates to local for points
Point=1 #toggles this behavior 1=vector aimed 0=target entity aimed
if(Point){
    #AttackPosition=owner():aimPos() #aim here
    RelativePosition = Self:toLocal(AttackPosition-
    (Self:massCenter() - Self:pos())) #this line adjusts for center of mass
    
}else{
    #rotates to local for entities
    RelativePosition = Self:toLocal(EnemyPosition-
    (Self:massCenter() - Self:pos())+ #this line adjusts for center of mass
    EnemyVelocity*Time-Self:vel()*Time+#this line adjusts for player and self velocity
    Enemy:isPlayer()*EnemyVelocity*Time)#lead for players only
}
#inertia needs to be recalculated incase weight change
Inertia = ang(Self:inertia():y(),Self:inertia():z(),Self:inertia():x())

#Takes a vector representing distance from target relative to turret 
#(this rotates the turret rightside up and prevents the 179 to -179 jitters
RelativeAngles = angnorm(RelativePosition:toAngle():setRoll( -Self:angles():roll()))
#RelativeAngles = angnorm(RelativePosition:toAngle():setYaw(Self:angles():yaw()+Yaw))
#finds the correct impulse and applies it
AngularImpulse = Inertia*InertiaConstant*(RelativeAngles*RS-Self:angVel())
Self:applyAngForce(AngularImpulse)#this function applies impulse, not force
#######################################

} elseif (first()) {

    Time = 0.015 #time for a game tick
    InertiaConstant = 27.053079273838 #Universal inertia constant
    RS = 1/Time #Rotational speed #Theoritically optimal speed (1 tick to aim)
    
    timer("startup1",300)
    Enemy = entity(147)
    
} elseif (clk("startup1")) {

    if (findCanQuery()) {
        #findByClass("gmod_wire_user")
        findByClass("gmod_wire_turret")
        Self = find()
        runOnTick(1)
    } else {
        timer("startup1",300)
    }
}

if(!XYZ){XYZ=Home}

Speed=200
if(!Latch){
    Self:applyForce(Speed*(XYZ-Self:pos())-Self:vel()*Self:mass())
}
#Fire=O:keyUse()

