@name PropSaver2
@persist [O]:entity Data:string [State LoadMode]:string K_Use K_Mode Mode
@persist [V1 V2]:vector [F PInfos]:array SpawnDelay ScanDelay Progress AutoDel FreezeAll

interval(100)

if(first()){
    #INIT
    
        #RUN
        runOnChat( 1 )
        runOnFile( 1 )
        
        #VARS
        O = owner()    
        State = "Idling"
        First = 1
        SpawnDelay = 450
        ScanDelay = 50
        FreezeAll = 1
        
        #FUNC
        function printC(S:string){
            printColor(vec(0), "[", vec(200, 0, 0), "E2", vec(0), "] ", vec(150), S)
        }

        function loadProps(FN:string){
            State = "Loading '" + FN + "'"
            printC(State)
            if(fileCanLoad()){
                fileLoad(FN) 
            } else {
                loadProps(FN)
            }
            State = "Reading"
        }
        function saveProps(FN:string){
            State = "Saving as '" + FN + "'"
            if(fileCanWrite()){
                fileWrite(FN, Data)
                printC("Saved.")
                State = "Idling"
            } else {
                saveProps(FN)
            }
        }

        function scan(){
            State = "Scanning"
            Progress = 0
            if(findCanQuery()){
                findIncludeClass("prop_*")
                findInBox(V1, V2)
                F = findToArray()  
                if(F:count() > 0){ 
                    Data = ""
                    State = "Parsing" 
                    printC(State)
                    timer("scanNext", ScanDelay)
                } else {
                    State = "Idling"
                    printC("No props found in the selected zone.")
                }
            } else {
                scan()
            }
        }
        function create(R:array){
            if(FreezeAll) { Freeze = 1 } else { Freeze = R[7, number] }
            local Prop = propSpawn(R[1, string], R[2, vector], R[3, angle], Freeze)
            Prop:setMaterial(R[4, string])
            Prop:setColor(R[5, vector])
            Prop:setAlpha(R[6, number])
            #Prop:setUnbreakable(R[8, number])
        }

    holoCreate(0)
    holoColor(0, vec(0, 255, 0))
    holoAlpha(0, 0)
    holoAng(0, ang(0))
}

K_Use = O:keyPressed("x")
K_Mode = O:keyPressed("i")
if(changed(State)){ setName("Akimatics - " + State) }

if(clk("scanNext") & State:find("Parsing")){
    Progress++
    State = "Parsing [" + Progress + "/" + F:count() + "]"
    local Prop = F[Progress, entity]
    Data+=Prop:model()+"|"
    Data+=toString(Prop:pos())+"|"
    Data+=toString(Prop:pos() - entity():pos())+"|"
    Data+=toString(Prop:angles())+"|"
    Data+=Prop:getMaterial()+"|"
    Data+=toString(Prop:getColor())+"|"
    Data+=toString(Prop:getAlpha())+"|"
    Data+=toString(Prop:isFrozen())+"|"
    #Data+=toString(Prop:isUnbreakable())
    if(Progress+1<=F:count()){
        Data+="$\n"
        timer("scanNext", ScanDelay)
    } else {
        printC("Done scanning " + F:count() + " props.")
        printC("Type a file name to save the schematic as. (case sensitive)")
        State = "Naming"
    }
}

if(clk("spawnNext") & State:find("Creating")){
    Progress++
    State = "Creating [" + Progress + "/" + PInfos:count() + "]"
    PropInfo = PInfos[Progress, string]:explode("|")
    local PropArr = array()
    PropArr:pushString(PropInfo[1, string])
    local Coords = array("")
    if(LoadMode=="world"){
        Coords = PropInfo[2, string]:replace("[",""):replace("]",""):explode(",")
        PropArr:pushVector(vec(Coords[1, string]:toNumber(), Coords[2, string]:toNumber(), Coords[3, string]:toNumber()))
    } else {
        Coords = PropInfo[3, string]:replace("[",""):replace("]",""):explode(",")
        PropArr:pushVector(entity():pos() + vec(Coords[1, string]:toNumber(), Coords[2, string]:toNumber(), Coords[3, string]:toNumber()))
    }
    local Angs = PropInfo[4, string]:replace("[",""):replace("]",""):explode(",")
    PropArr:pushAngle(ang(Angs[1, string]:toNumber(), Angs[2, string]:toNumber(), Angs[3, string]:toNumber()))
    PropArr:pushString(PropInfo[5, string])
    local Cols = PropInfo[6, string]:replace("[",""):replace("]",""):explode(",")
    PropArr:pushVector(vec(Cols[1, string]:toNumber(), Cols[2, string]:toNumber(), Cols[3, string]:toNumber()))
    local Alpha = PropInfo[7, string]
    PropArr:pushNumber(Alpha:toNumber())
    local IsFrozen = PropInfo[8, string]:toNumber()
    PropArr:pushNumber(IsFrozen)
    local IsUnbreakable = PropInfo[9, string]:toNumber()
    PropArr:pushNumber(IsUnbreakable)
    create(PropArr) 
    if(Progress+1<=PInfos:count()){
        timer("spawnNext", SpawnDelay)
    } else {
        State = "Idling"
        printC("Done.")
        if(AutoDel){ selfDestruct() }
    }
}

if(changed(K_Use) & !First){
    if(K_Use){
        State = "Zoning"
        printC(State)
        V1 = O:aimPos()
    } else {
        V2 = Mode ? O:pos() : O:aimPos()
        scan()
    }
} elseif(changed(K_Mode) & K_Mode){
    Mode = !Mode
    local Txt = Mode ? "Relative to player position." : "Relative to aim position."
    printC(Txt)
}

if(State=="Zoning"){
    holoAlpha(0, 50)
    local Pos = Mode ? O:pos() : O:aimPos()
    local VV = V1 + vec(0,0,5)
    V = (Pos - VV)
    L = VV:distance(Pos)
    holoScaleUnits(0, V)
    holoPos(0, VV + V:normalized()*(L/2))
} else {
    holoAlpha(0, 0)
}

if(fileLoaded() & State=="Reading"){
    G = fileRead()
    PInfos = G:replace("\n", ""):explode("$")
    Progress = 0
    State = "Creating"
    timer("spawnNext", SpawnDelay)
}

if(State=="Naming" & chatClk(O)){ hideChat(1) saveProps(lastSaid():replace(" ", "") + ".txt") }
elseif(chatClk(O)){
    LS = O:lastSaid()
    LSS = LS:sub(2, LS:length()):explode(" ")
    LS0 = LS:index(1)
    LS1 = LSS:string(1)  
    LS2 = LSS:string(2)
    LS3 = LSS:string(3)
    LS4 = LSS:string(4)
    
    if(LS0=="*"){
        if(LS1=="load"){
            hideChat(1)
            if(LS2=="world" || LS2=="local" ){
                LoadMode = LS2
                AutoDel = LS4:toNumber()
                loadProps(LS3 + ".txt")
            } else {
                printC("Invalide mode, or incorrect usage. Available modes: local, world")
                printC("Usage: *load <mode> <dupename>")
            }
        }    
    }
}
