@name HoloGravSimu_NBody
@outputs [E]:entity B:table Count

if(first())
{
    runOnKeys(owner(), 1)
    
    E = entity()
    E["radius", number] = 300
    
    Count = 5
    
    function createNBody(Index, Base:entity)
    {
        local Offset = (randvec(-1, 1):normalized() * Base["radius", number])
        local H = holoCreate(Index, Base:pos() + Offset)
        holoModel(Index, "hq_sphere")
        holoColor(Index, vec(255, 150, 150))
        
        H["mass", number] = random(300, 3000)
        
        holoScale(Index, vec(H["mass", number] / 500))
        
        H:setTrails(H["mass", number] / 40, 0, 3, "effects/beam_generic01", vec(255), 255)
        
        B[Index, entity] = H
    }
    
    function entity:bodyGravity(ForeignBody:entity, Gravity)
    {
        local GravF = (Gravity / (ForeignBody:pos():distance(This:pos()) ^ 2)) / This["mass", number]
        local GravD = (ForeignBody:pos() - This:pos()):normalized()
        
        This["vel", vector] = This["vel", vector] + (GravD * GravF)
        
        #Collision detection hacked in
        if(This:pos():distance(ForeignBody:pos()) < (This["mass", number] + ForeignBody["mass", number]) / (500 / 6))
        {
            while(perf() & (This:pos():distance(ForeignBody:pos()) < (This["mass", number] + ForeignBody["mass", number]) / (500 / 6)))
            {
                holoPos(holoIndex(This), This:pos() + (This:pos() - ForeignBody:pos()):normalized() * 5)
                holoPos(holoIndex(ForeignBody), ForeignBody:pos() + (ForeignBody:pos() - This:pos()):normalized() * 5)
            }
        }
    }
    
    function handleNBody(Index, Base:entity, Gravity, Count)
    {
        local H = holoEntity(Index)
        
        for(I = 1, Count)
        {
            if(I != Index)
            {
                H:bodyGravity(holoEntity(I), Gravity)
            }
        }
        
        holoPos(Index, H:pos() + H["vel", vector])
    }
    
    for(I = 1, Count)
    {
        createNBody(I, E)
    }
    
    timer("bodies", 100)
}

if(clk("bodies"))
{
    for(I = 1, Count)
    {
        handleNBody(I, E, 1200000, Count)
    }
    
    timer("bodies", 100)
}

if(keyClk(owner()))
{
    if(owner():keyWalk())
    {
        Count++
        createNBody(Count, E)
        
        print(4, toString(Count))
    }
    elseif(owner():keyUse())
    {
        if(Count > 0)
        {
            holoDelete(Count)
            Count--
        }
        
        print(4, toString(Count))
    }
}
