@name DeCerialize
@persist [Owner Entity CurProp]:entity 
@persist [CannisterStart CannisterEnd]:vector 
@persist Objects:table MaxObjects File:string Current Finished Iteration
@persist Props:table IsGlobal Speed PropsSpawned:array
@persist CannisterAng:angle Holos:array ReadyToSpawn RespawnTime
@persist DTimer

runOnFile(1)

if(first()) {
    Entity=entity()
    Owner=owner()
    
    File="cereal_lakehouse.txt"
    
    Speed=0.05
    RespawnTime=1
    
    timer("DoLoad",0)
    
    timer("Cannister",0)
    CannisterStart=Entity:pos():setZ(5000)+randvec(vec(-500,-500,0),vec(-500,-500,0))
    CannisterEnd=Entity:pos()+vec(0,0,15)
    CannisterAng=(CannisterEnd-CannisterStart):toAngle()+ang(-180,0,0)
    
    holoCreate(1,CannisterStart,vec(1),CannisterAng)
    
    holoModel(1,"models/props_combine/headcrabcannister01b.mdl")
    holoEntity(1):setTrails(45,15,3,"trails/smoke",vec(255),255)
    Entity:soundPlay("Incoming",0,"HeadcrabCanister.IncomingSound")
    Iteration=0
    
    Entity:setAlpha(0)
    ReadyToSpawn=1
    for(I=2,100) {holoCreate(I,vec(),vec(),ang()) Holos:pushNumber(I)}
    
    function number smoothStep(Min,Max,X) {
        X=clamp((X-Min)/(Max-Min),0,1)
        return X*X*X*(X*(X*6-15)+10)
    }
    
    function vector smoothStep(Min:vector,Max:vector,Xa) {
        X=vec(Xa)
        X=clamp((X-Min)/(Max-Min),0,1)
        return X*X*X*(X*(X*6-15)+10)
    }
    
    
}

if(fileClk(File)) {
    switch(fileStatus()) {
        case _FILE_OK,
            printColor(vec(0,255,255),"[Cereal] ",vec(255),"Status: File OK")
        break
        case _FILE_UNKNOWN,
            printColor(vec(0,255,255),"[Cereal] ",vec(255),"Status: Unknown file")
        break
        case _FILE_TIMEOUT,
            printColor(vec(0,255,255),"[Cereal] ",vec(255),"Status: Timed out")
        break
        case _FILE_404,
            printColor(vec(0,255,255),"[Cereal] ",vec(255),"Status: 404 Not found")
        break
        case _FILE_TRANSFER_ERROR,
            printColor(vec(0,255,255),"[Cereal] ",vec(255),"Status: Transfer error")
        break
    }
    
    local MetaData=vonDecodeTable(fileRead())
    IsGlobal=MetaData["Global",number]
    Objects=MetaData["Objects",table]
    MaxObjects=Objects:count()
    printColor(vec(0,255,255),"[Cereal] ",vec(255),"Loaded ",vec(0,255,0),MaxObjects:toString(),vec(255)," props.")
}

if(clk("DoLoad")) {
    if(fileCanLoad()) {
        printColor(vec(0,255,255),"[Cereal] ",vec(255),"Loading...")
        fileLoad(File)
    } else {
        timer("DoLoad",1000)
    }
}

if(clk("Cannister")) {
    Iteration=clamp(Iteration+0.12,0,1)
    local Offset=Iteration*(CannisterEnd-CannisterStart)+CannisterStart
    holoPos(1,Offset)
    if(Iteration!=1) {
        timer("Cannister",100)
    } else {
        Iteration=0
        holoEntity(1):soundPlay("Explode",0,"HeadcrabCanister.SkyboxExplosion")
        timer("Open",2000)
        timer("Spawn",4000)
    }
}

if(clk("Open")) {
    holoEntity(1):soundPlay("Open",0,"HeadcrabCanister.Open")
    holoAnim(1,"open")
    # "garrysmod/balloon_pop_cute.wav"
}

if(clk("Respawn")) {ReadyToSpawn=1}

if(clk("Spawn")) {
    if(MaxObjects==0) {
        timer("Spawn",10)
    } else {
        if(Current<MaxObjects & ReadyToSpawn) {
            timer("Respawn",RespawnTime)
            ReadyToSpawn=0
            Current++
            local FinAng=IsGlobal ? Objects[Current,table]["ang",angle] : Entity:toWorld(Objects[Current,table]["ang",angle])
            local Start=holoEntity(1):toWorld(vec(30,0,0))
            local End=IsGlobal ? Objects[Current,table]["pos",vector] : Entity:toWorld(Objects[Current,table]["pos",vector])
            local Mid=(Start+End/2)
                Mid=Start+randvec(vec(-200,-200,1200),vec(200,200,2400)) #:setZ(5000)
            local CurProp=propSpawn(Objects[Current,table]["mdl",string],Start,1)
            PropsSpawned:pushEntity(CurProp)
            CurProp:propNotSolid(1)
            CurProp:setMaterial(Objects[Current,table]["mat",string])
            CurProp:setColor(Objects[Current,table]["col",vector])
            CurProp:setAlpha(0)
            HoloID=Holos:shiftNumber()
            
            local MaxAlpha=Objects[Current,table]["alpha",number]
            local MaxAlpha=255 # old
            
            holoPos(HoloID,CurProp:pos())
            holoAng(HoloID,CurProp:angles())
            holoModel(HoloID,CurProp:model())
            holoMaterial(HoloID,CurProp:getMaterial())
            holoColor(HoloID,CurProp:getColor())
            holoParent(HoloID,CurProp)
            holoAlpha(HoloID,MaxAlpha)
            
            local AngOffset=vec(randint(360),randint(360),randint(360))
            holoEntity(1):soundPlay("Eject",0,"garrysmod/balloon_pop_cute.wav")
            soundPitch("Eject",randint(50,125))
            Props["Prop_"+Current,table]=table(
                "ent"=CurProp,
                "start"=Start,
                "mid"=Mid,
                "end"=End,
                "diff"=End-Start,
                "ang"=FinAng,
                "angoff"=AngOffset,
                "i"=0,
                "holo"=HoloID,
                "alpha"=MaxAlpha
            )
        }
            
        foreach(I,V:table=Props) {
            #print(I)
            local Iteration=clamp(V["i",number]+Speed,0,1)
            if(Iteration!=1) {
                Props[I,table]["i",number]=Iteration
                local CurPos=bezier(V["start",vector],V["mid",vector],V["end",vector],Iteration)
                V["ent",entity]:setPos(CurPos)
                V["ent",entity]:setAng(V["ang",angle]+ang(V["angoff",vector]*smoothStep(1,0.2,Iteration)))
                holoScale(V["holo",number],vec(clamp(smoothStep(0,1,Iteration),0.2,1)))
            } else {
                V["ent",entity]:setPos(V["end",vector])
                V["ent",entity]:setAng(V["ang",angle])
                holoAlpha(V["holo",number],0)
                holoPos(V["holo",number],V["start",vector])
                holoScale(V["holo",number],vec())
                Holos:pushNumber(V["holo",number])
                V["ent",entity]:setAlpha(V["alpha",number])
                V["ent",entity]:propNotSolid(0)
                Finished++
                Props:removeTable(I)
            }
        }
        
        if(Finished<MaxObjects) {
            timer("Spawn",100)
        } else {
            printColor(vec(0,255,255),"[Cereal] ",vec(255),"Done.")
            #foreach(I,V:entity=PropsSpawned) {V:propFreeze(0)}
            timer("Despawn",1000)
        }
    }
}

if(clk("Despawn")) {
    DTimer=clamp(DTimer+0.02,0,1)
    holoAlpha(1,255-(DTimer*255))
    if(DTimer==1) {
        selfDestruct()
    }
    timer("Despawn",100)
}



