@name GiantBullet
@outputs State:string
@inputs Fire Reload AllowUse 
@persist [E Bullet Primer]:entity [OldDir OldPos]:vector GraceTime
@model models/props_phx/facepunch_barrel.mdl

if (first() | dupefinished()) {
    entity():propFreeze(0)
    runOnTick(1)
    runOnLast(1)
    rangerPersist(1)
    
    GraceTime = 0.1
    
    E = entity()
        E:setMass(3000)
        E:setAlpha(0)
        rangerFilter(E)

    State = "Empty"

    holoCreate(0, E:toWorld(E:boxCenter() + vec(0,0,1)), vec(2.5,2.5,3.6), E:toWorld(ang()),  vec(255,223,127), "hq_tube_thin"):setMaterial("sprops/textures/sprops_chrome")
    holoCreate(1, E:toWorld(E:boxCenter() + vec(0,0,-23)), vec(2.5,2.5,0.15), E:toWorld(ang()),  vec(255,223,127), "hq_cylinder"):setMaterial("sprops/textures/sprops_chrome")
    holoCreate(2, E:toWorld(E:boxCenter() + vec(0,0,-21.4)), vec(2.32,2.32,0.15), E:toWorld(ang()),  vec(127,95,0), "hq_tube_thin"):setMaterial("sprops/textures/sprops_chrome")
    holoCreate(3, E:toWorld(E:boxCenter() + vec(0,0,-23.5)), vec(1,1,0.1), E:toWorld(ang()),  vec(127,95,0), "hq_tube_thick"):setMaterial("sprops/textures/sprops_chrome")
    holoCreate(4, E:toWorld(E:boxCenter() + vec(0,0,-23.5)), vec(1,1,0.1), E:toWorld(ang()),  vec(127,95,0), "hq_cylinder"):setMaterial("sprops/textures/sprops_chrome")
        holoParent(0, E)
        holoParent(1, E)
        holoParent(2, E)
        holoParent(3, E)
        holoParent(4, E)
        holoAlpha(3, 0)
        
    
    function bulletSpawn() {
        if (Bullet | State != "Empty" ) { return }
        E:soundPlay("reload", 0, "buttons/button4.wav")
       
        holoAlpha(4, 255)
        holoAlpha(3, 0)
        
        E:setMass(3000)
        
        Bullet = propSpawn("models/props_phx/misc/flakshell_big.mdl", E:toWorld(vec(0,0,45)), E:angles(), 0)
            Bullet:setMass(1000)
            Bullet:setMaterial("phoenix_storms/black_chrome") 
            Bullet:setColor(vec(127,95,0))
        
        rangerFilter(Bullet)
        
        holoCreate(10, Bullet:toWorld(vec(0,0,0)), vec(1,1,1), ang(0,0,0))  
        holoAlpha(10, 0)
        holoParent(10, Bullet)
        
        State = "Ready"
        Bullet:parentTo(E)
    }
    
    function bulletFire() {
        if (!Bullet | State != "Ready") { return }
        if (Primer) { Primer:propBreak() }
        timer("GracePeriod", GraceTime*1000)
        
        E:soundPlay("fire", 0, "ambient/explosions/explode_4.wav")
        E:setMass(50)
        
        holoAlpha(4, 0)
        holoAlpha(3, 255)
        
        Bullet:propFreeze(0)
        Bullet:propGravity(0)
        Bullet:deparent()
        Bullet:setPos(E:toWorld(vec(0,0,45)))
        Bullet:setAng(E:angles())
        Bullet:applyOffsetForce(E:up() * Bullet:mass() * 50000, Bullet:toWorld(vec(0,0,-20)))
        
        E:applyOffsetForce(-E:up() * Bullet:mass() * 50, E:toWorld(vec(0,0,30)))
        
        holoEntity(10):setTrails(38, 0, 2, "trails/tube", vec(255,255,255), 200)
        
        State = "Grace Time"
    }
    
    function primerSpawn() {
        if (Primer | State != "Empty") { return }
        
        Primer = propSpawn("models/props_phx/misc/potato_launcher_explosive.mdl", E:toWorld(E:boxCenter() + vec(0,0,-25)), E:angles(), 0)
            Primer:parentTo(E)
            Primer:setAlpha(0)
    }
        
    function bulletExplode() {
        holoDelete(10)
        
        for (I = 0, 4) {
            NewPos  = toWorld(vec(0,0,150):rotate(ang(0,0,90*I)), ang(), OldPos, OldDir:toAngle())
            T = rangerOffset(OldPos + OldDir, NewPos)

            P = propSpawn("models/props_phx/misc/flakshell_big.mdl", T:pos(), ang(), 1)
            P:propBreak()
        }
        
        Bullet:propBreak()
        State = "Empty"
    }
    
    function reload() {
        primerSpawn()   
        bulletSpawn() 
    }
    
    reload()
}

if (~Fire & Fire) { bulletFire() }
if (~Reload & Reload) { reload() }

if (State == "Grace Time" & clk("GracePeriod")) {
    State = "Flight"
    Bullet:propGravity(1)
}

if (State == "Flight") {
    Trace = rangerOffsetHull(50,Bullet:toWorld(vec(0,0,25)),Bullet:up(),Bullet:boxSize())
    if (Bullet) {
        OldPos = Bullet:pos()
        OldDir = Bullet:vel():normalized()
    }
    if (Trace:hit() | !Bullet) {
        bulletExplode()   
    } else {
        Bullet:applyTorque((150*Bullet:toLocal(rotationVector(quat(Bullet:vel():toAngle() + ang(90,0,0))/quat(Bullet))+Bullet:pos())-12*Bullet:angVelVector())*Bullet:inertia())
    }    
} elseif (State == "Empty" | State == "Ready") {
    if (->AllowUse & AllowUse) {
        foreach (I, P:entity = players()) {
            if (P:shootPos():distance(E:pos()) <= 200) {
                if (P:aimEntity() == E | P:aimEntity() == Bullet) {
                    if (changed(P:keyUse()) & P:keyUse()) { bulletFire() reload() }
                }
            }   
        }
    }
    if (!Primer) { bulletFire() }
    if (!Bullet) { State = "Empty" }
}


if (last()) {
    Bullet:propDelete()  
    Primer:propDelete() 
}
