Don't return anything

Don't return anything

--
-- Copyright (C) 2017 DBot
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
--     http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--

ENABLE_FLASHLIGHT_PASS = CreateConVar('ppm2_flasglight_pass', '0', {FCVAR_ARCHIVE}, 'Enable flashlight render pass. This kills FPS.')

class PonyRenderController
    @AVALIABLE_CONTROLLERS = {}
    @MODELS = {'models/ppm/player_default_base.mdl', 'models/ppm/player_default_base_nj.mdl', 'models/cppm/player_default_base.mdl', 'models/cppm/player_default_base_nj.mdl'}
    @__inherited: (child) =>
        child.MODELS_HASH = {mod, true for mod in *child.MODELS}
        @AVALIABLE_CONTROLLERS[mod] = child for mod in *child.MODELS
    @__inherited(@)
    @NEXT_OBJ_ID = 0

    CompileTextures: => @GetTextureController()\CompileTextures() if @GetTextureController and @GetTextureController()
    new: (data) =>
        @objID = @@NEXT_OBJ_ID
        @@NEXT_OBJ_ID += 1
        @isValid = true
        @networkedData = data
        @ent = data.ent
        @modelCached = data\GetModel()
        @IGNORE_DRAW = false
        @CompileTextures() if @ent
        @CreateLegs() if @ent == LocalPlayer()
        @socksModel = data\GetSocksModel()
        @CreateFlexController() if @ent
    __tostring: => "[#{@@__name}:#{@objID}|#{@GetData()}]"
    GetEntity: => @ent
    GetData: => @networkedData
    GetModel: => @networkedData\GetModel()

    GetLegs: =>
        return NULL if not @isValid
        return NULL if @ent ~= LocalPlayer()
        @CreateLegs() if not IsValid()
        return @legsModel
    CreateLegs: =>
        return NULL if not @isValid
        return NULL if @ent ~= LocalPlayer()
        for ent in *ents.GetAll()
            if ent.isPonyLegsModel
                ent\Remove()
        @legsModel = ClientsideModel(@modelCached)
        with @legsModel
            .isPonyLegsModel = true
            \SetNoDraw(true)
            .__PPM2_PonyData = @GetData()

        @GetData()\GetWeightController()\UpdateWeight(@legsModel)

        @lastLegUpdate = CurTime()
        @legClipPlanePos = Vector(0, 0, 0)
        @legBGSetup = CurTime()
        @legUpdateFrame = 0
        @legClipDot = 0
        @duckOffsetHack = @@LEG_CLIP_OFFSET_STAND
        @legsClipPlane = @@LEG_CLIP_VECTOR
        return @legsModel

    @LEG_SHIFT_CONST = 24
    @LEG_SHIFT_CONST_VEHICLE = 14
    @LEG_Z_CONST = 0
    @LEG_Z_CONST_VEHICLE = 20
    @LEG_ANIM_SPEED_CONST = 1
    @LEG_CLIP_OFFSET_STAND = 28
    @LEG_CLIP_OFFSET_DUCK = 12
    @LEG_CLIP_OFFSET_VEHICLE = 11

    UpdateLegs: =>
        return if not @isValid
        return unless IsValid(@legsModel)
        return if @legUpdateFrame == FrameNumber()
        @legUpdateFrame = FrameNumber()
        ctime = CurTime()
        ply = @ent
        seq = ply\GetSequence()

        if seq ~= @legSeq
            @legSeq = seq
            @legsModel\ResetSequence(seq)

        if @legBGSetup < ctime
            @legBGSetup = ctime + 1
            for group in *ply\GetBodyGroups()
                @legsModel\SetBodygroup(group.id, ply\GetBodygroup(group.id))

        with @legsModel
            \FrameAdvance(ctime - @lastLegUpdate)
            \SetPlaybackRate(@@LEG_ANIM_SPEED_CONST * ply\GetPlaybackRate())
            @lastLegUpdate = ctime
            \SetPoseParameter('move_x',       (ply\GetPoseParameter('move_x')     * 2) - 1)
            \SetPoseParameter('move_y',       (ply\GetPoseParameter('move_y')     * 2) - 1)
            \SetPoseParameter('move_yaw',     (ply\GetPoseParameter('move_yaw')   * 360) - 180)
            \SetPoseParameter('body_yaw',     (ply\GetPoseParameter('body_yaw')   * 180) - 90)
            \SetPoseParameter('spine_yaw',    (ply\GetPoseParameter('spine_yaw')  * 180) - 90)

        if ply\InVehicle()
            veh = ply\GetVehicle()
            vehAng = veh\GetAngles()
            eyepos = EyePos()
            vehAng\RotateAroundAxis(vehAng\Up(), 90)

            clipAng = Angle(vehAng.p, vehAng.y, vehAng.r)
            clipAng\RotateAroundAxis(clipAng\Right(), -90)

            @legsClipPlane = clipAng\Forward()
            @legsModel\SetRenderAngles(vehAng)

            legClipPlanePos = Vector(0, 0, @@LEG_CLIP_OFFSET_VEHICLE)
            legClipPlanePos\Rotate(vehAng)
            @legClipPlanePos = eyepos - legClipPlanePos

            drawPos = Vector(@@LEG_SHIFT_CONST_VEHICLE, 0, @@LEG_Z_CONST_VEHICLE)
            drawPos\Rotate(vehAng)
            @legsModel\SetRenderOrigin(eyepos - drawPos)
        else
            @legsClipPlane = @@LEG_CLIP_VECTOR
            eangles = EyeAngles()
            yaw = eangles.y - ply\GetPoseParameter('head_yaw') * 180 + 90
            newAng = Angle(0, yaw, 0)
            rad = math.rad(yaw)
            sin, cos = math.sin(rad), math.cos(rad)
            pos = ply\GetPos()
            {:x, :y, :z} = pos
            newPos = Vector(x - cos * @@LEG_SHIFT_CONST, y - sin * @@LEG_SHIFT_CONST, z + @@LEG_Z_CONST)
            if ply\Crouching()
                @duckOffsetHack = @@LEG_CLIP_OFFSET_DUCK
            else
                @duckOffsetHack = Lerp(0.1, @duckOffsetHack, @@LEG_CLIP_OFFSET_STAND)

            @legClipPlanePos = Vector(x, y, z + @duckOffsetHack)
            @legsModel\SetRenderAngles(newAng)
            @legsModel\SetRenderOrigin(newPos)
        @legClipDot = @legsClipPlane\Dot(@legClipPlanePos)

    @LEG_CLIP_VECTOR = Vector(0, 0, -1)
    DrawLegs: (start3D = true) =>
        return if not @isValid
        @CreateLegs() unless IsValid(@legsModel)
        return unless IsValid(@legsModel)
        return if @ent\ShouldDrawLocalPlayer()
        @UpdateLegs()

        oldClip = render.EnableClipping(true)
        render.PushCustomClipPlane(@legsClipPlane, @legClipDot)
        cam.Start3D() if start3D

        if ENABLE_FLASHLIGHT_PASS\GetBool()
            render.PushFlashlightMode(true)
            @PreDraw()
            @legsModel\DrawModel()
            @PostDraw()
            render.PopFlashlightMode()
        @PreDraw()
        @legsModel\DrawModel()
        @PostDraw()

        render.PopCustomClipPlane()
        cam.End3D() if start3D
        render.EnableClipping(oldClip)

    IsValid: => IsValid(@ent) and @isValid
    Remove: =>
        @flexes\Remove() if @flexes
        @GetTextureController()\Remove() if @GetTextureController and @GetTextureController()
        @isValid = false

    PlayerRespawn: =>
        return if not @isValid
        @flexes\PlayerRespawn() if @flexes

    PreDraw: (ent = @ent) =>
        return if not @isValid
        return if @IGNORE_DRAW
        @GetTextureController()\PreDraw(ent)
        @flexes\Think() if @flexes
    PostDraw: (ent = @ent) =>
        return if not @isValid
        return if @IGNORE_DRAW
        textures = @GetTextureController()
        textures\PostDraw(ent)

        @IGNORE_DRAW = true
        if @GetData()\IsNetworked()
            @socksModel = @ent\GetNWEntity('PPM2.SocksModel') if not IsValid(@socksModel)

        @socksModel = @GetData()\GetSocksModel() if not IsValid(@socksModel)

        if IsValid(@socksModel)
            @socksModel\SetNoDraw(true)
            if ENABLE_FLASHLIGHT_PASS\GetBool()
                render.PushFlashlightMode(true)
                textures\PreDrawSocks()
                @socksModel\DrawModel()
                textures\PostDrawSocks()
                render.PopFlashlightMode()

            textures\PreDrawSocks()
            @socksModel\DrawModel()
            textures\PostDrawSocks()
        @IGNORE_DRAW = false

    @ARMS_MATERIAL_INDEX = 0
    PreDrawArms: (ent) =>
        return if not @isValid
        if ent and not @armsWeightSetup
            @armsWeightSetup = true
            weight = @GetData()\GetWeight()
            vec = Vector(weight, weight, weight)
            for i = 1, 13
                ent\ManipulateBoneScale(i, vec)
        render.MaterialOverrideByIndex(@@ARMS_MATERIAL_INDEX, @GetTextureController()\GetBody())
    PostDrawArms: (ent) =>
        return if not @isValid
        render.MaterialOverrideByIndex(@@ARMS_MATERIAL_INDEX)

    DataChanges: (state) =>
        return if not @isValid
        return if not @ent
        @GetTextureController()\DataChanges(state)
        @flexes\DataChanges(state) if @flexes
        switch state\GetKey()
            when 'Weight'
                @armsWeightSetup = false
                @GetData()\GetWeightController()\UpdateWeight(@legsModel) if IsValid(@legsModel)
            when 'SocksModel'
                @socksModel = @GetData()\GetSocksModel()
                @socksModel\SetNoDraw(true) if IsValid(@socksModel)
            when 'NoFlex'
                if state\GetValue()
                    @flexes\ResetSequences() if @flexes
                    @flexes = nil
                else
                    @CreateFlexController()
    GetTextureController: =>
        return @renderController if not @isValid
        if not @renderController
            cls = PPM2.GetTextureController(@modelCached)
            @renderController = cls(@)
        @renderController.ent = @ent
        return @renderController
    CreateFlexController: =>
        return if not @isValid
        return if not @ent\IsPlayer()
        return if @GetData()\GetNoFlex()
        if not @flexes
            cls = PPM2.GetFlexController(@modelCached)
            return if not cls
            @flexes = cls(@)
        @flexes.ent = @ent
        return @flexes
    GetFlexController: => @flexes

class NewPonyRenderController extends PonyRenderController
    @MODELS = {'models/ppm/player_default_base_new.mdl'}

    new: (data) =>
        @upperManeModel = data\GetUpperManeModel()
        @lowerManeModel = data\GetLowerManeModel()
        @tailModel = data\GetTailModel()
        @upperManeModel\SetNoDraw(true) if IsValid(@upperManeModel)
        @lowerManeModel\SetNoDraw(true) if IsValid(@lowerManeModel)
        @tailModel\SetNoDraw(true) if IsValid(@tailModel)
        super(data)
    __tostring: => "[#{@@__name}:#{@objID}|#{@GetData()}]"

    DataChanges: (state) =>
        return if not @ent
        return if not @isValid
        switch state\GetKey()
            when 'UpperManeModel'
                @upperManeModel = @GetData()\GetUpperManeModel()
                @upperManeModel\SetNoDraw(true) if IsValid(@upperManeModel)
            when 'LowerManeMode'
                @lowerManeModel = @GetData()\GetLowerManeModel()
                @lowerManeModel\SetNoDraw(true) if IsValid(@lowerManeModel)
            when 'TailModel'
                @tailModel = @GetData()\GetTailModel()
                @tailModel\SetNoDraw(true) if IsValid(@tailModel)
        super(state)

    DrawManeAndTailModels: =>
        return if not @isValid
        textures = @GetTextureController()
        return if not textures
        if IsValid(@upperManeModel)
            @upperManeModel\SetNoDraw(true)
            textures\PreDrawUpperMane()
            @upperManeModel\DrawModel()
            textures\PostDrawUpperMane()

        if IsValid(@lowerManeModel)
            @lowerManeModel\SetNoDraw(true)
            textures\PreDrawLowerMane()
            @lowerManeModel\DrawModel()
            textures\PostDrawLowerMane()

        if IsValid(@tailModel)
            @tailModel\SetNoDraw(true)
            textures\PreDrawTail()
            @tailModel\DrawModel()
            textures\PostDrawTail()

    PostDraw: (ent = @ent) =>
        return if @IGNORE_DRAW
        return if not @isValid
        @IGNORE_DRAW = true

        if @GetData()\IsNetworked()
            @upperManeModel = @ent\GetNWEntity('PPM2.UpperManeModel') if not IsValid(@upperManeModel)
            @lowerManeModel = @ent\GetNWEntity('PPM2.LowerManeModel') if not IsValid(@lowerManeModel)
            @tailModel = @ent\GetNWEntity('PPM2.TailModel') if not IsValid(@tailModel)

        @upperManeModel = @GetData()\GetUpperManeModel() if not IsValid(@upperManeModel)
        @lowerManeModel = @GetData()\GetLowerManeModel() if not IsValid(@lowerManeModel)
        @tailModel = @GetData()\GetTailModel() if not IsValid(@tailModel)

        if ENABLE_FLASHLIGHT_PASS\GetBool()
            render.PushFlashlightMode(true)
            @DrawManeAndTailModels()
            render.PopFlashlightMode()
        @DrawManeAndTailModels()

        @IGNORE_DRAW = false
        super(ent)

PPM2.PonyRenderController = PonyRenderController
PPM2.NewPonyRenderController = NewPonyRenderController
PPM2.GetPonyRenderController = (model = 'models/ppm/player_default_base.mdl') -> PonyRenderController.AVALIABLE_CONTROLLERS[model\lower()] or PonyRenderController
PPM2.GetPonyRendererController = PPM2.GetPonyRenderController
PPM2.GetRenderController = PPM2.GetPonyRenderController
PPM2.GetRendererController = PPM2.GetPonyRenderController

--
-- Copyright (C) 2017 DBot
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
--     http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--

ENABLE_FLASHLIGHT_PASS = CreateConVar('ppm2_flasglight_pass', '0', {FCVAR_ARCHIVE}, 'Enable flashlight render pass. This kills FPS.')

class PonyRenderController
    @AVALIABLE_CONTROLLERS = {}
    @MODELS = {'models/ppm/player_default_base.mdl', 'models/ppm/player_default_base_nj.mdl', 'models/cppm/player_default_base.mdl', 'models/cppm/player_default_base_nj.mdl'}
    @__inherited: (child) =>
        child.MODELS_HASH = {mod, true for mod in *child.MODELS}
        @AVALIABLE_CONTROLLERS[mod] = child for mod in *child.MODELS
    @__inherited(@)
    @NEXT_OBJ_ID = 0

    CompileTextures: => @GetTextureController()\CompileTextures() if @GetTextureController and @GetTextureController()
    new: (data) =>
        @objID = @@NEXT_OBJ_ID
        @@NEXT_OBJ_ID += 1
        @isValid = true
        @networkedData = data
        @ent = data.ent
        @modelCached = data\GetModel()
        @IGNORE_DRAW = false
        @CompileTextures() if @ent
        @CreateLegs() if @ent == LocalPlayer()
        @socksModel = data\GetSocksModel()
        @CreateFlexController() if @ent
    __tostring: => "[#{@@__name}:#{@objID}|#{@GetData()}]"
    GetEntity: => @ent
    GetData: => @networkedData
    GetModel: => @networkedData\GetModel()

    GetLegs: =>
        return NULL if not @isValid
        return NULL if @ent ~= LocalPlayer()
        @CreateLegs() if not IsValid()
        return @legsModel
    CreateLegs: =>
        return NULL if not @isValid
        return NULL if @ent ~= LocalPlayer()
        for ent in *ents.GetAll()
            if ent.isPonyLegsModel
                ent\Remove()
        @legsModel = ClientsideModel(@modelCached)
        with @legsModel
            .isPonyLegsModel = true
            \SetNoDraw(true)
            .__PPM2_PonyData = @GetData()

        @GetData()\GetWeightController()\UpdateWeight(@legsModel)

        @lastLegUpdate = CurTime()
        @legClipPlanePos = Vector(0, 0, 0)
        @legBGSetup = CurTime()
        @legUpdateFrame = 0
        @legClipDot = 0
        @duckOffsetHack = @@LEG_CLIP_OFFSET_STAND
        @legsClipPlane = @@LEG_CLIP_VECTOR
        return @legsModel

    @LEG_SHIFT_CONST = 24
    @LEG_SHIFT_CONST_VEHICLE = 14
    @LEG_Z_CONST = 0
    @LEG_Z_CONST_VEHICLE = 20
    @LEG_ANIM_SPEED_CONST = 1
    @LEG_CLIP_OFFSET_STAND = 28
    @LEG_CLIP_OFFSET_DUCK = 12
    @LEG_CLIP_OFFSET_VEHICLE = 11

    UpdateLegs: =>
        return if not @isValid
        return unless IsValid(@legsModel)
        return if @legUpdateFrame == FrameNumber()
        @legUpdateFrame = FrameNumber()
        ctime = CurTime()
        ply = @ent
        seq = ply\GetSequence()

        if seq ~= @legSeq
            @legSeq = seq
            @legsModel\ResetSequence(seq)

        if @legBGSetup < ctime
            @legBGSetup = ctime + 1
            for group in *ply\GetBodyGroups()
                @legsModel\SetBodygroup(group.id, ply\GetBodygroup(group.id))

        with @legsModel
            \FrameAdvance(ctime - @lastLegUpdate)
            \SetPlaybackRate(@@LEG_ANIM_SPEED_CONST * ply\GetPlaybackRate())
            @lastLegUpdate = ctime
            \SetPoseParameter('move_x',       (ply\GetPoseParameter('move_x')     * 2) - 1)
            \SetPoseParameter('move_y',       (ply\GetPoseParameter('move_y')     * 2) - 1)
            \SetPoseParameter('move_yaw',     (ply\GetPoseParameter('move_yaw')   * 360) - 180)
            \SetPoseParameter('body_yaw',     (ply\GetPoseParameter('body_yaw')   * 180) - 90)
            \SetPoseParameter('spine_yaw',    (ply\GetPoseParameter('spine_yaw')  * 180) - 90)

        if ply\InVehicle()
            veh = ply\GetVehicle()
            vehAng = veh\GetAngles()
            eyepos = EyePos()
            vehAng\RotateAroundAxis(vehAng\Up(), 90)

            clipAng = Angle(vehAng.p, vehAng.y, vehAng.r)
            clipAng\RotateAroundAxis(clipAng\Right(), -90)

            @legsClipPlane = clipAng\Forward()
            @legsModel\SetRenderAngles(vehAng)

            legClipPlanePos = Vector(0, 0, @@LEG_CLIP_OFFSET_VEHICLE)
            legClipPlanePos\Rotate(vehAng)
            @legClipPlanePos = eyepos - legClipPlanePos

            drawPos = Vector(@@LEG_SHIFT_CONST_VEHICLE, 0, @@LEG_Z_CONST_VEHICLE)
            drawPos\Rotate(vehAng)
            @legsModel\SetRenderOrigin(eyepos - drawPos)
        else
            @legsClipPlane = @@LEG_CLIP_VECTOR
            eangles = EyeAngles()
            yaw = eangles.y - ply\GetPoseParameter('head_yaw') * 180 + 90
            newAng = Angle(0, yaw, 0)
            rad = math.rad(yaw)
            sin, cos = math.sin(rad), math.cos(rad)
            pos = ply\GetPos()
            {:x, :y, :z} = pos
            newPos = Vector(x - cos * @@LEG_SHIFT_CONST, y - sin * @@LEG_SHIFT_CONST, z + @@LEG_Z_CONST)
            if ply\Crouching()
                @duckOffsetHack = @@LEG_CLIP_OFFSET_DUCK
            else
                @duckOffsetHack = Lerp(0.1, @duckOffsetHack, @@LEG_CLIP_OFFSET_STAND)

            @legClipPlanePos = Vector(x, y, z + @duckOffsetHack)
            @legsModel\SetRenderAngles(newAng)
            @legsModel\SetRenderOrigin(newPos)
        @legClipDot = @legsClipPlane\Dot(@legClipPlanePos)

    @LEG_CLIP_VECTOR = Vector(0, 0, -1)
    DrawLegs: (start3D = true) =>
        return if not @isValid
        @CreateLegs() unless IsValid(@legsModel)
        return unless IsValid(@legsModel)
        return if @ent\ShouldDrawLocalPlayer()
        @UpdateLegs()

        oldClip = render.EnableClipping(true)
        render.PushCustomClipPlane(@legsClipPlane, @legClipDot)
        cam.Start3D() if start3D

        if ENABLE_FLASHLIGHT_PASS\GetBool()
            render.PushFlashlightMode(true)
            @PreDraw()
            @legsModel\DrawModel()
            @PostDraw()
            render.PopFlashlightMode()
        @PreDraw()
        @legsModel\DrawModel()
        @PostDraw()

        render.PopCustomClipPlane()
        cam.End3D() if start3D
        render.EnableClipping(oldClip)

    IsValid: => IsValid(@ent) and @isValid
    Remove: =>
        @flexes\Remove() if @flexes
        @GetTextureController()\Remove() if @GetTextureController and @GetTextureController()
        @isValid = false

    PlayerRespawn: =>
        return if not @isValid
        @flexes\PlayerRespawn() if @flexes

    PreDraw: (ent = @ent) =>
        return if not @isValid
        return false if @IGNORE_DRAW
        @GetTextureController()\PreDraw(ent)
        @flexes\Think() if @flexes
    PostDraw: (ent = @ent) =>
        return if not @isValid
        return if @IGNORE_DRAW
        textures = @GetTextureController()
        textures\PostDraw(ent)

        @IGNORE_DRAW = true
        if @GetData()\IsNetworked()
            @socksModel = @ent\GetNWEntity('PPM2.SocksModel') if not IsValid(@socksModel)

        @socksModel = @GetData()\GetSocksModel() if not IsValid(@socksModel)

        if IsValid(@socksModel)
            @socksModel\SetNoDraw(true)
            if ENABLE_FLASHLIGHT_PASS\GetBool()
                render.PushFlashlightMode(true)
                textures\PreDrawSocks()
                @socksModel\DrawModel()
                textures\PostDrawSocks()
                render.PopFlashlightMode()

            textures\PreDrawSocks()
            @socksModel\DrawModel()
            textures\PostDrawSocks()
        @IGNORE_DRAW = false

    @ARMS_MATERIAL_INDEX = 0
    PreDrawArms: (ent) =>
        return if not @isValid
        if ent and not @armsWeightSetup
            @armsWeightSetup = true
            weight = @GetData()\GetWeight()
            vec = Vector(weight, weight, weight)
            for i = 1, 13
                ent\ManipulateBoneScale(i, vec)
        render.MaterialOverrideByIndex(@@ARMS_MATERIAL_INDEX, @GetTextureController()\GetBody())
    PostDrawArms: (ent) =>
        return if not @isValid
        render.MaterialOverrideByIndex(@@ARMS_MATERIAL_INDEX)

    DataChanges: (state) =>
        return if not @isValid
        return if not @ent
        @GetTextureController()\DataChanges(state)
        @flexes\DataChanges(state) if @flexes
        switch state\GetKey()
            when 'Weight'
                @armsWeightSetup = false
                @GetData()\GetWeightController()\UpdateWeight(@legsModel) if IsValid(@legsModel)
            when 'SocksModel'
                @socksModel = @GetData()\GetSocksModel()
                @socksModel\SetNoDraw(true) if IsValid(@socksModel)
            when 'NoFlex'
                if state\GetValue()
                    @flexes\ResetSequences() if @flexes
                    @flexes = nil
                else
                    @CreateFlexController()
    GetTextureController: =>
        return @renderController if not @isValid
        if not @renderController
            cls = PPM2.GetTextureController(@modelCached)
            @renderController = cls(@)
        @renderController.ent = @ent
        return @renderController
    CreateFlexController: =>
        return if not @isValid
        return if not @ent\IsPlayer()
        return if @GetData()\GetNoFlex()
        if not @flexes
            cls = PPM2.GetFlexController(@modelCached)
            return if not cls
            @flexes = cls(@)
        @flexes.ent = @ent
        return @flexes
    GetFlexController: => @flexes

class NewPonyRenderController extends PonyRenderController
    @MODELS = {'models/ppm/player_default_base_new.mdl'}

    new: (data) =>
        @upperManeModel = data\GetUpperManeModel()
        @lowerManeModel = data\GetLowerManeModel()
        @tailModel = data\GetTailModel()
        @upperManeModel\SetNoDraw(true) if IsValid(@upperManeModel)
        @lowerManeModel\SetNoDraw(true) if IsValid(@lowerManeModel)
        @tailModel\SetNoDraw(true) if IsValid(@tailModel)
        super(data)
    __tostring: => "[#{@@__name}:#{@objID}|#{@GetData()}]"

    DataChanges: (state) =>
        return if not @ent
        return if not @isValid
        switch state\GetKey()
            when 'UpperManeModel'
                @upperManeModel = @GetData()\GetUpperManeModel()
                @upperManeModel\SetNoDraw(true) if IsValid(@upperManeModel)
            when 'LowerManeMode'
                @lowerManeModel = @GetData()\GetLowerManeModel()
                @lowerManeModel\SetNoDraw(true) if IsValid(@lowerManeModel)
            when 'TailModel'
                @tailModel = @GetData()\GetTailModel()
                @tailModel\SetNoDraw(true) if IsValid(@tailModel)
        super(state)

    DrawManeAndTailModels: =>
        return if not @isValid
        textures = @GetTextureController()
        return if not textures
        if IsValid(@upperManeModel)
            @upperManeModel\SetNoDraw(true)
            textures\PreDrawUpperMane()
            @upperManeModel\DrawModel()
            textures\PostDrawUpperMane()

        if IsValid(@lowerManeModel)
            @lowerManeModel\SetNoDraw(true)
            textures\PreDrawLowerMane()
            @lowerManeModel\DrawModel()
            textures\PostDrawLowerMane()

        if IsValid(@tailModel)
            @tailModel\SetNoDraw(true)
            textures\PreDrawTail()
            @tailModel\DrawModel()
            textures\PostDrawTail()

    PostDraw: (ent = @ent) =>
        return if @IGNORE_DRAW
        return if not @isValid
        @IGNORE_DRAW = true

        if @GetData()\IsNetworked()
            @upperManeModel = @ent\GetNWEntity('PPM2.UpperManeModel') if not IsValid(@upperManeModel)
            @lowerManeModel = @ent\GetNWEntity('PPM2.LowerManeModel') if not IsValid(@lowerManeModel)
            @tailModel = @ent\GetNWEntity('PPM2.TailModel') if not IsValid(@tailModel)

        @upperManeModel = @GetData()\GetUpperManeModel() if not IsValid(@upperManeModel)
        @lowerManeModel = @GetData()\GetLowerManeModel() if not IsValid(@lowerManeModel)
        @tailModel = @GetData()\GetTailModel() if not IsValid(@tailModel)

        if ENABLE_FLASHLIGHT_PASS\GetBool()
            render.PushFlashlightMode(true)
            @DrawManeAndTailModels()
            render.PopFlashlightMode()
        @DrawManeAndTailModels()

        @IGNORE_DRAW = false
        super(ent)

PPM2.PonyRenderController = PonyRenderController
PPM2.NewPonyRenderController = NewPonyRenderController
PPM2.GetPonyRenderController = (model = 'models/ppm/player_default_base.mdl') -> PonyRenderController.AVALIABLE_CONTROLLERS[model\lower()] or PonyRenderController
PPM2.GetPonyRendererController = PPM2.GetPonyRenderController
PPM2.GetRenderController = PPM2.GetPonyRenderController
PPM2.GetRendererController = PPM2.GetPonyRenderController


Fixed PAC3 bone anim lib isn't working

Fixed PAC3 bone anim lib isn't working

--
-- Copyright (C) 2017 DBot
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
--     http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--

-- 0	LrigPelvis
-- 1	LrigSpine1
-- 2	LrigSpine2
-- 3	LrigRibcage
-- 4	LrigNeck1
-- 5	LrigNeck2
-- 6	LrigNeck3
-- 7	LrigScull
-- 8	Lrig_LEG_BL_Femur
-- 9	Lrig_LEG_BL_Tibia
-- 10	Lrig_LEG_BL_LargeCannon
-- 11	Lrig_LEG_BL_PhalanxPrima
-- 12	Lrig_LEG_BL_RearHoof
-- 13	Lrig_LEG_BR_Femur
-- 14	Lrig_LEG_BR_Tibia
-- 15	Lrig_LEG_BR_LargeCannon
-- 16	Lrig_LEG_BR_PhalanxPrima
-- 17	Lrig_LEG_BR_RearHoof
-- 18	Lrig_LEG_FL_Scapula
-- 19	Lrig_LEG_FL_Humerus
-- 20	Lrig_LEG_FL_Radius
-- 21	Lrig_LEG_FL_Metacarpus
-- 22	Lrig_LEG_FL_PhalangesManus
-- 23	Lrig_LEG_FL_FrontHoof
-- 24	Lrig_LEG_FR_Scapula
-- 25	Lrig_LEG_FR_Humerus
-- 26	Lrig_LEG_FR_Radius
-- 27	Lrig_LEG_FR_Metacarpus
-- 28	Lrig_LEG_FR_PhalangesManus
-- 29	Lrig_LEG_FR_FrontHoof
-- 30	Mane01
-- 31	Mane02
-- 32	Mane03
-- 33	Mane04
-- 34	Mane05
-- 35	Mane06
-- 36	Mane07
-- 37	Mane03_tip
-- 38	Tail01
-- 39	Tail02
-- 40	Tail03

USE_NEW_HULL = CreateConVar('ppm2_sv_newhull', '1', {FCVAR_ARCHIVE, FCVAR_NOTIFY, FCVAR_REPLICATED}, 'Use proper collision box for ponies. Slightly affects jump mechanics. When disabled, unexpected behaviour could happen.')

class PonySizeController
    @AVALIABLE_CONTROLLERS = {}
    @MODELS = {'models/ppm/player_default_base.mdl', 'models/ppm/player_default_base_nj.mdl', 'models/cppm/player_default_base.mdl', 'models/cppm/player_default_base_nj.mdl'}
    @__inherited: (child) =>
        child.MODELS_HASH = {mod, true for mod in *child.MODELS}
        @AVALIABLE_CONTROLLERS[mod] = child for mod in *child.MODELS
    @__inherited(@)

    @NECK_BONE_1 = 4
    @NECK_BONE_2 = 5
    @NECK_BONE_3 = 6
    @NECK_BONE_4 = 7

    @LEGS_BONE_ROOT = 0

    @LEGS_FRONT_1 = 23
    @LEGS_FRONT_2 = 29

    @LEGS_FRONT_3 = 21
    @LEGS_FRONT_4 = 27

    @LEGS_FRONT_5 = 20
    @LEGS_FRONT_6 = 26

    @LEGS_BEHIND_1_1 = 14
    @LEGS_BEHIND_2_1 = 16
    @LEGS_BEHIND_3_1 = 15

    @LEGS_BEHIND_1_2 = 9
    @LEGS_BEHIND_2_2 = 11
    @LEGS_BEHIND_3_2 = 10

    @NEXT_OBJ_ID = 0

    new: (controller) =>
        @isValid = true
        @ent = controller.ent
        @entID = controller.entID
        @controller = controller
        @objID = @@NEXT_OBJ_ID
        @@NEXT_OBJ_ID += 1
        @lastPAC3BoneReset = 0
        PPM2.DebugPrint('Created new size controller for ', @ent, ' as part of ', controller, '; internal ID is ', @objID)

    __tostring: => "[#{@@__name}:#{@objID}|#{@ent}]"
    IsValid: => @isValid
    GetData: => @controller
    GetEntity: => @ent
    GetEntityID: => @entID
    GetDataID: => @entID

    @STEP_SIZE = 18
    @PONY_HULL = 19
    @HULL_MINS = Vector(-@PONY_HULL, -@PONY_HULL, 0)
    @HULL_MAXS = Vector(@PONY_HULL, @PONY_HULL, 72 * PPM2.PONY_HEIGHT_MODIFIER)
    @HULL_MAXS_DUCK = Vector(@PONY_HULL, @PONY_HULL, 36 * PPM2.PONY_HEIGHT_MODIFIER_DUCK_HULL)

    @DEFAULT_HULL_MINS = Vector(-16, -16, 0)
    @DEFAULT_HULL_MAXS = Vector(16, 16, 72)
    @DEFAULT_HULL_MAXS_DUCK = Vector(16, 16, 36)
    @DEF_SCALE = Vector(1, 1, 1)

    DataChanges: (state) =>
        return if not IsValid(@ent)
        return if not @ent\IsPony()
        if state\GetKey() == 'PonySize'
            @ModifyScale()

        if state\GetKey() == 'NeckSize'
            @ModifyNeck()
            @ModifyViewOffset()

        if state\GetKey() == 'LegsSize'
            @ModifyLegs()
            @ModifyHull()
            @ModifyViewOffset()

    ResetViewOffset: (ent = @ent) =>
        ent\SetViewOffset(PPM2.PLAYER_VIEW_OFFSET_ORIGINAL) if ent.SetViewOffset
        ent\SetViewOffsetDucked(PPM2.PLAYER_VIEW_OFFSET_DUCK_ORIGINAL) if ent.SetViewOffsetDucked

    ResetHulls: (ent = @ent) =>
        ent\ResetHull() if ent.ResetHull
        ent\SetStepSize(@@STEP_SIZE) if ent.SetStepSize
        ent.__ppm2_modified_hull = false

    ResetJumpHeight: (ent = @ent) =>
        return if CLIENT
        return if not ent.SetJumpPower
        return if not ent.__ppm2_modified_jump
        ent\SetJumpPower(ent\GetJumpPower() / PPM2.PONY_JUMP_MODIFIER)
        ent.__ppm2_modified_jump = false

    ResetDrawMatrix: (ent = @ent) =>
        return if SERVER
        mat = Matrix()
        mat\Scale(@@DEF_SCALE)
        ent\EnableMatrix('RenderMultiply', mat)

    ResetScale: (ent = @ent) =>
        return if not IsValid(ent)

        if USE_NEW_HULL\GetBool() or ent.__ppm2_modified_hull
            @ResetHulls(ent)
            @ResetJumpHeight(ent)

        @ResetViewOffset(ent)
        @ResetDrawMatrix(ent)
        @ResetNeck(ent)
        @ResetLegs(ent)

    ResetNeck: (ent = @ent) =>
        return if not CLIENT
        return if not IsValid(@ent)
        with ent
            \ManipulateBoneScale(@@NECK_BONE_1, Vector(1, 1, 1))
            \ManipulateBoneScale(@@NECK_BONE_2, Vector(1, 1, 1))
            \ManipulateBoneScale(@@NECK_BONE_3, Vector(1, 1, 1))
            \ManipulateBoneScale(@@NECK_BONE_4, Vector(1, 1, 1))
            \ManipulateBoneAngles(@@NECK_BONE_1, Angle(0, 0, 0))
            \ManipulateBoneAngles(@@NECK_BONE_2, Angle(0, 0, 0))
            \ManipulateBoneAngles(@@NECK_BONE_3, Angle(0, 0, 0))
            \ManipulateBoneAngles(@@NECK_BONE_4, Angle(0, 0, 0))
            \ManipulateBonePosition(@@NECK_BONE_1, Vector(0, 0, 0))
            \ManipulateBonePosition(@@NECK_BONE_2, Vector(0, 0, 0))
            \ManipulateBonePosition(@@NECK_BONE_3, Vector(0, 0, 0))
            \ManipulateBonePosition(@@NECK_BONE_4, Vector(0, 0, 0))

    ResetLegs: (ent = @ent) =>
        return if not CLIENT
        return if not IsValid(ent)

        vec1 = Vector(1, 1, 1)
        vec2 = Vector(0, 0, 0)
        ang = Angle(0, 0, 0)

        with ent
            \ManipulateBoneScale(@@LEGS_BONE_ROOT, vec1)
            \ManipulateBoneScale(@@LEGS_FRONT_1, vec1)
            \ManipulateBoneScale(@@LEGS_FRONT_2, vec1)
            \ManipulateBoneScale(@@LEGS_BEHIND_1_1, vec1)
            \ManipulateBoneScale(@@LEGS_BEHIND_2_1, vec1)
            \ManipulateBoneScale(@@LEGS_BEHIND_3_1, vec1)
            \ManipulateBoneScale(@@LEGS_BEHIND_1_2, vec1)
            \ManipulateBoneScale(@@LEGS_BEHIND_2_2, vec1)
            \ManipulateBoneScale(@@LEGS_BEHIND_3_2, vec1)

            \ManipulateBoneAngles(@@LEGS_BONE_ROOT, ang)
            \ManipulateBoneAngles(@@LEGS_FRONT_1, ang)
            \ManipulateBoneAngles(@@LEGS_FRONT_2, ang)
            \ManipulateBoneAngles(@@LEGS_BEHIND_1_1, ang)
            \ManipulateBoneAngles(@@LEGS_BEHIND_2_1, ang)
            \ManipulateBoneAngles(@@LEGS_BEHIND_3_1, ang)
            \ManipulateBoneAngles(@@LEGS_BEHIND_1_2, ang)
            \ManipulateBoneAngles(@@LEGS_BEHIND_2_2, ang)
            \ManipulateBoneAngles(@@LEGS_BEHIND_3_2, ang)

            \ManipulateBonePosition(@@LEGS_BONE_ROOT, vec2)
            \ManipulateBonePosition(@@LEGS_FRONT_1, vec2)
            \ManipulateBonePosition(@@LEGS_FRONT_2, vec2)
            \ManipulateBonePosition(@@LEGS_BEHIND_1_1, vec2)
            \ManipulateBonePosition(@@LEGS_BEHIND_2_1, vec2)
            \ManipulateBonePosition(@@LEGS_BEHIND_3_1, vec2)
            \ManipulateBonePosition(@@LEGS_BEHIND_1_2, vec2)
            \ManipulateBonePosition(@@LEGS_BEHIND_2_2, vec2)
            \ManipulateBonePosition(@@LEGS_BEHIND_3_2, vec2)

    Remove: => @ResetScale()
    Reset: =>
        @ResetScale()
        @ResetNeck()
        @ResetLegs()
        @ModifyScale()

    GetLegsSize: => @GetData()\GetLegsSize()
    GetLegsScale: => @GetData()\GetLegsSize()
    GetNeckSize: => @GetData()\GetNeckSize()
    GetNeckScale: => @GetData()\GetNeckSize()
    GetPonySize: => @GetData()\GetPonySize()
    GetPonyScale: => @GetData()\GetPonySize()

    PlayerDeath: =>
        @ResetScale()
        @ResetNeck()
        @ResetLegs()
    PlayerRespawn: =>
        @ResetScale()
        @ModifyScale()

    SlowUpdate: =>
        @ModifyScale()

    ModifyHull: (ent = @ent) =>
        ent.__ppm2_modified_hull = true
        size = @GetPonySize()
        legssize = @GetLegsModifier()

        HULL_MINS = Vector(@@HULL_MINS)
        HULL_MAXS = Vector(@@HULL_MAXS)
        HULL_MAXS_DUCK = Vector(@@HULL_MAXS_DUCK)

        HULL_MINS *= size
        HULL_MAXS *= size
        HULL_MAXS_DUCK *= size

        HULL_MINS.z *= legssize
        HULL_MAXS.z *= legssize
        HULL_MAXS_DUCK.z *= legssize

        with ent
            \SetHull(HULL_MINS, HULL_MAXS) if .SetHull
            \SetHullDuck(HULL_MINS, HULL_MAXS_DUCK) if .SetHullDuck
            \SetStepSize(@@STEP_SIZE * size * @GetLegsModifier(1.2)) if .SetStepSize

    ModifyJumpHeight: (ent = @ent) =>
        return if CLIENT
        return if not @ent.SetJumpPower
        return if ent.__ppm2_modified_jump
        ent\SetJumpPower(ent\GetJumpPower() * PPM2.PONY_JUMP_MODIFIER)
        ent.__ppm2_modified_jump = true

    GetLegsModifier: (mult = 0.4) => 1 + (@GetLegsSize() - 1) * mult

    ModifyViewOffset: (ent = @ent) =>
        size = @GetPonySize()
        necksize = 1 + (@GetNeckSize() - 1) * .3
        legssize = @GetLegsModifier()

        PLAYER_VIEW_OFFSET = Vector(PPM2.PLAYER_VIEW_OFFSET)
        PLAYER_VIEW_OFFSET_DUCK = Vector(PPM2.PLAYER_VIEW_OFFSET_DUCK)

        PLAYER_VIEW_OFFSET *= size * necksize
        PLAYER_VIEW_OFFSET_DUCK *= size * necksize

        PLAYER_VIEW_OFFSET.z *= legssize
        PLAYER_VIEW_OFFSET_DUCK.z *= legssize

        ent\SetViewOffset(PLAYER_VIEW_OFFSET) if ent.SetViewOffset
        ent\SetViewOffsetDucked(PLAYER_VIEW_OFFSET_DUCK) if ent.SetViewOffsetDucked

    ModifyDrawMatrix: (ent = @ent) =>
        return if SERVER
        mat = Matrix()
        mat\Scale(@@DEF_SCALE * @GetPonySize())
        ent\EnableMatrix('RenderMultiply', mat)

    ModifyScale: (ent = @ent) =>
        return if not IsValid(ent)
        return if not ent\IsPony()
        return if ent.Alive and not ent\Alive()
        size = @GetPonySize()

        if USE_NEW_HULL\GetBool()
            @ModifyHull(ent)
            @ModifyJumpHeight(ent)

        @ModifyViewOffset(ent)
        @ModifyDrawMatrix(ent)
        if @lastPAC3BoneReset < RealTime()
            @ModifyNeck(ent)
            @ModifyLegs(ent)

    ModifyNeck: (ent = @ent) =>
        return if SERVER
        return if not IsValid(ent)
        size = (@GetNeckSize() - 1) * 3
        vec = Vector(size, -size, 0)

        boneAnimTable = ent.pac_boneanim and ent.pac_boneanim.positions or {}
        emptyVector = Vector(0, 0, 0)

        with ent
            \ManipulateBonePosition(@@NECK_BONE_1, vec + (boneAnimTable[@@NECK_BONE_1] or emptyVector))
            \ManipulateBonePosition(@@NECK_BONE_2, vec + (boneAnimTable[@@NECK_BONE_2] or emptyVector))
            \ManipulateBonePosition(@@NECK_BONE_3, vec + (boneAnimTable[@@NECK_BONE_3] or emptyVector))
            \ManipulateBonePosition(@@NECK_BONE_4, vec + (boneAnimTable[@@NECK_BONE_4] or emptyVector))

    ModifyLegs: (ent = @ent) =>
        return if SERVER
        return if not IsValid(ent)
        realSizeModify = @GetLegsSize() - 1
        size = realSizeModify * 3

        boneAnimTable = ent.pac_boneanim and ent.pac_boneanim.positions or {}
        emptyVector = Vector(0, 0, 0)

        with ent
            \ManipulateBonePosition(@@LEGS_BONE_ROOT, Vector(0, 0, size * 5) + (boneAnimTable[@@LEGS_BONE_ROOT] or emptyVector))
            \ManipulateBonePosition(@@LEGS_FRONT_1, Vector(size * 1.5, 0, 0) + (boneAnimTable[@@LEGS_FRONT_1] or emptyVector))
            \ManipulateBonePosition(@@LEGS_FRONT_2, Vector(size * 1.5, 0, 0) + (boneAnimTable[@@LEGS_FRONT_2] or emptyVector))

            \ManipulateBonePosition(@@LEGS_FRONT_3, Vector(size, 0, 0) + (boneAnimTable[@@LEGS_FRONT_3] or emptyVector))
            \ManipulateBonePosition(@@LEGS_FRONT_4, Vector(size, 0, 0) + (boneAnimTable[@@LEGS_FRONT_4] or emptyVector))

            \ManipulateBonePosition(@@LEGS_FRONT_5, Vector(size, size, 0) + (boneAnimTable[@@LEGS_FRONT_5] or emptyVector))
            \ManipulateBonePosition(@@LEGS_FRONT_6, Vector(size, size, 0) + (boneAnimTable[@@LEGS_FRONT_6] or emptyVector))

            \ManipulateBonePosition(@@LEGS_BEHIND_1_1, Vector(size, -size * 0.5, 0) + (boneAnimTable[@@LEGS_BEHIND_1_1] or emptyVector))
            \ManipulateBonePosition(@@LEGS_BEHIND_1_2, Vector(size, -size * 0.5, 0) + (boneAnimTable[@@LEGS_BEHIND_1_2] or emptyVector))

            \ManipulateBonePosition(@@LEGS_BEHIND_2_1, Vector(size, 0, 0) + (boneAnimTable[@@LEGS_BEHIND_2_1] or emptyVector))
            \ManipulateBonePosition(@@LEGS_BEHIND_2_2, Vector(size, 0, 0) + (boneAnimTable[@@LEGS_BEHIND_2_2] or emptyVector))

            \ManipulateBonePosition(@@LEGS_BEHIND_3_1, Vector(size * 2, 0, 0) + (boneAnimTable[@@LEGS_BEHIND_3_1] or emptyVector))
            \ManipulateBonePosition(@@LEGS_BEHIND_3_2, Vector(size * 2, 0, 0) + (boneAnimTable[@@LEGS_BEHIND_3_2] or emptyVector))

--
-- 0	LrigPelvis
-- 1	Lrig_LEG_BL_Femur
-- 2	Lrig_LEG_BL_Tibia
-- 3	Lrig_LEG_BL_LargeCannon
-- 4	Lrig_LEG_BL_PhalanxPrima
-- 5	Lrig_LEG_BL_RearHoof
-- 6	Lrig_LEG_BR_Femur
-- 7	Lrig_LEG_BR_Tibia
-- 8	Lrig_LEG_BR_LargeCannon
-- 9	Lrig_LEG_BR_PhalanxPrima
-- 10	Lrig_LEG_BR_RearHoof
-- 11	LrigSpine1
-- 12	LrigSpine2
-- 13	LrigRibcage
-- 14	Lrig_LEG_FL_Scapula
-- 15	Lrig_LEG_FL_Humerus
-- 16	Lrig_LEG_FL_Radius
-- 17	Lrig_LEG_FL_Metacarpus
-- 18	Lrig_LEG_FL_PhalangesManus
-- 19	Lrig_LEG_FL_FrontHoof
-- 20	Lrig_LEG_FR_Scapula
-- 21	Lrig_LEG_FR_Humerus
-- 22	Lrig_LEG_FR_Radius
-- 23	Lrig_LEG_FR_Metacarpus
-- 24	Lrig_LEG_FR_PhalangesManus
-- 25	Lrig_LEG_FR_FrontHoof
-- 26	LrigNeck1
-- 27	LrigNeck2
-- 28	LrigNeck3
-- 29	LrigScull
-- 30	Jaw
-- 31	Ear_L
-- 32	Ear_R
-- 33	Mane02
-- 34	Mane03
-- 35	Mane03_tip
-- 36	Mane04
-- 37	Mane05
-- 38	Mane06
-- 39	Mane07
-- 40	Mane01
-- 41	Lrigweaponbone
-- 42	Tail01
-- 43	Tail02
-- 44	Tail03
--

class NewPonySizeContoller extends PonySizeController
    @MODELS = {'models/ppm/player_default_base_new.mdl', 'models/ppm/player_default_base_new_nj.mdl'}

    @NECK_BONE_1 = 26
    @NECK_BONE_2 = 27
    @NECK_BONE_3 = 28
    @NECK_BONE_4 = 29

    @LEGS_FRONT_1 = 19
    @LEGS_FRONT_2 = 25

    @LEGS_FRONT_3 = 17
    @LEGS_FRONT_4 = 23

    @LEGS_FRONT_5 = 16
    @LEGS_FRONT_6 = 22

    @LEGS_BEHIND_1_1 = 2
    @LEGS_BEHIND_1_2 = 7

    @LEGS_BEHIND_2_1 = 4
    @LEGS_BEHIND_2_2 = 9

    @LEGS_BEHIND_3_1 = 3
    @LEGS_BEHIND_3_2 = 8

    new: (...) =>
        super(...)

if CLIENT
    hook.Add 'PPM2_PACResetBones', 'PPM2.Size', (ent, data) ->
        if sizes = data\GetSizeController()
            sizes.ent = ent
            sizes\ModifyNeck()
            sizes\ModifyLegs()
            sizes.lastPAC3BoneReset = RealTime() + 1

PPM2.GetSizeController = (model = 'models/ppm/player_default_base.mdl') -> PonySizeController.AVALIABLE_CONTROLLERS[model\lower()] or PonySizeController

--
-- Copyright (C) 2017 DBot
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
--     http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--

-- 0	LrigPelvis
-- 1	LrigSpine1
-- 2	LrigSpine2
-- 3	LrigRibcage
-- 4	LrigNeck1
-- 5	LrigNeck2
-- 6	LrigNeck3
-- 7	LrigScull
-- 8	Lrig_LEG_BL_Femur
-- 9	Lrig_LEG_BL_Tibia
-- 10	Lrig_LEG_BL_LargeCannon
-- 11	Lrig_LEG_BL_PhalanxPrima
-- 12	Lrig_LEG_BL_RearHoof
-- 13	Lrig_LEG_BR_Femur
-- 14	Lrig_LEG_BR_Tibia
-- 15	Lrig_LEG_BR_LargeCannon
-- 16	Lrig_LEG_BR_PhalanxPrima
-- 17	Lrig_LEG_BR_RearHoof
-- 18	Lrig_LEG_FL_Scapula
-- 19	Lrig_LEG_FL_Humerus
-- 20	Lrig_LEG_FL_Radius
-- 21	Lrig_LEG_FL_Metacarpus
-- 22	Lrig_LEG_FL_PhalangesManus
-- 23	Lrig_LEG_FL_FrontHoof
-- 24	Lrig_LEG_FR_Scapula
-- 25	Lrig_LEG_FR_Humerus
-- 26	Lrig_LEG_FR_Radius
-- 27	Lrig_LEG_FR_Metacarpus
-- 28	Lrig_LEG_FR_PhalangesManus
-- 29	Lrig_LEG_FR_FrontHoof
-- 30	Mane01
-- 31	Mane02
-- 32	Mane03
-- 33	Mane04
-- 34	Mane05
-- 35	Mane06
-- 36	Mane07
-- 37	Mane03_tip
-- 38	Tail01
-- 39	Tail02
-- 40	Tail03

USE_NEW_HULL = CreateConVar('ppm2_sv_newhull', '1', {FCVAR_ARCHIVE, FCVAR_NOTIFY, FCVAR_REPLICATED}, 'Use proper collision box for ponies. Slightly affects jump mechanics. When disabled, unexpected behaviour could happen.')

class PonySizeController
    @AVALIABLE_CONTROLLERS = {}
    @MODELS = {'models/ppm/player_default_base.mdl', 'models/ppm/player_default_base_nj.mdl', 'models/cppm/player_default_base.mdl', 'models/cppm/player_default_base_nj.mdl'}
    @__inherited: (child) =>
        child.MODELS_HASH = {mod, true for mod in *child.MODELS}
        @AVALIABLE_CONTROLLERS[mod] = child for mod in *child.MODELS
    @__inherited(@)

    @NECK_BONE_1 = 4
    @NECK_BONE_2 = 5
    @NECK_BONE_3 = 6
    @NECK_BONE_4 = 7

    @LEGS_BONE_ROOT = 0

    @LEGS_FRONT_1 = 23
    @LEGS_FRONT_2 = 29

    @LEGS_FRONT_3 = 21
    @LEGS_FRONT_4 = 27

    @LEGS_FRONT_5 = 20
    @LEGS_FRONT_6 = 26

    @LEGS_BEHIND_1_1 = 14
    @LEGS_BEHIND_2_1 = 16
    @LEGS_BEHIND_3_1 = 15

    @LEGS_BEHIND_1_2 = 9
    @LEGS_BEHIND_2_2 = 11
    @LEGS_BEHIND_3_2 = 10

    @NEXT_OBJ_ID = 0

    new: (controller) =>
        @isValid = true
        @ent = controller.ent
        @entID = controller.entID
        @controller = controller
        @objID = @@NEXT_OBJ_ID
        @@NEXT_OBJ_ID += 1
        @lastPAC3BoneReset = 0
        PPM2.DebugPrint('Created new size controller for ', @ent, ' as part of ', controller, '; internal ID is ', @objID)

    __tostring: => "[#{@@__name}:#{@objID}|#{@ent}]"
    IsValid: => @isValid
    GetData: => @controller
    GetEntity: => @ent
    GetEntityID: => @entID
    GetDataID: => @entID

    @STEP_SIZE = 18
    @PONY_HULL = 19
    @HULL_MINS = Vector(-@PONY_HULL, -@PONY_HULL, 0)
    @HULL_MAXS = Vector(@PONY_HULL, @PONY_HULL, 72 * PPM2.PONY_HEIGHT_MODIFIER)
    @HULL_MAXS_DUCK = Vector(@PONY_HULL, @PONY_HULL, 36 * PPM2.PONY_HEIGHT_MODIFIER_DUCK_HULL)

    @DEFAULT_HULL_MINS = Vector(-16, -16, 0)
    @DEFAULT_HULL_MAXS = Vector(16, 16, 72)
    @DEFAULT_HULL_MAXS_DUCK = Vector(16, 16, 36)
    @DEF_SCALE = Vector(1, 1, 1)

    DataChanges: (state) =>
        return if not IsValid(@ent)
        return if not @ent\IsPony()
        if state\GetKey() == 'PonySize'
            @ModifyScale()

        if state\GetKey() == 'NeckSize'
            @ModifyNeck()
            @ModifyViewOffset()

        if state\GetKey() == 'LegsSize'
            @ModifyLegs()
            @ModifyHull()
            @ModifyViewOffset()

    ResetViewOffset: (ent = @ent) =>
        ent\SetViewOffset(PPM2.PLAYER_VIEW_OFFSET_ORIGINAL) if ent.SetViewOffset
        ent\SetViewOffsetDucked(PPM2.PLAYER_VIEW_OFFSET_DUCK_ORIGINAL) if ent.SetViewOffsetDucked

    ResetHulls: (ent = @ent) =>
        ent\ResetHull() if ent.ResetHull
        ent\SetStepSize(@@STEP_SIZE) if ent.SetStepSize
        ent.__ppm2_modified_hull = false

    ResetJumpHeight: (ent = @ent) =>
        return if CLIENT
        return if not ent.SetJumpPower
        return if not ent.__ppm2_modified_jump
        ent\SetJumpPower(ent\GetJumpPower() / PPM2.PONY_JUMP_MODIFIER)
        ent.__ppm2_modified_jump = false

    ResetDrawMatrix: (ent = @ent) =>
        return if SERVER
        mat = Matrix()
        mat\Scale(@@DEF_SCALE)
        ent\EnableMatrix('RenderMultiply', mat)

    ResetScale: (ent = @ent) =>
        return if not IsValid(ent)

        if USE_NEW_HULL\GetBool() or ent.__ppm2_modified_hull
            @ResetHulls(ent)
            @ResetJumpHeight(ent)

        @ResetViewOffset(ent)
        @ResetDrawMatrix(ent)
        @ResetNeck(ent)
        @ResetLegs(ent)

    ResetNeck: (ent = @ent) =>
        return if not CLIENT
        return if not IsValid(@ent)
        with ent
            \ManipulateBoneScale(@@NECK_BONE_1, Vector(1, 1, 1))
            \ManipulateBoneScale(@@NECK_BONE_2, Vector(1, 1, 1))
            \ManipulateBoneScale(@@NECK_BONE_3, Vector(1, 1, 1))
            \ManipulateBoneScale(@@NECK_BONE_4, Vector(1, 1, 1))
            \ManipulateBoneAngles(@@NECK_BONE_1, Angle(0, 0, 0))
            \ManipulateBoneAngles(@@NECK_BONE_2, Angle(0, 0, 0))
            \ManipulateBoneAngles(@@NECK_BONE_3, Angle(0, 0, 0))
            \ManipulateBoneAngles(@@NECK_BONE_4, Angle(0, 0, 0))
            \ManipulateBonePosition(@@NECK_BONE_1, Vector(0, 0, 0))
            \ManipulateBonePosition(@@NECK_BONE_2, Vector(0, 0, 0))
            \ManipulateBonePosition(@@NECK_BONE_3, Vector(0, 0, 0))
            \ManipulateBonePosition(@@NECK_BONE_4, Vector(0, 0, 0))

    ResetLegs: (ent = @ent) =>
        return if not CLIENT
        return if not IsValid(ent)

        vec1 = Vector(1, 1, 1)
        vec2 = Vector(0, 0, 0)
        ang = Angle(0, 0, 0)

        with ent
            \ManipulateBoneScale(@@LEGS_BONE_ROOT, vec1)
            \ManipulateBoneScale(@@LEGS_FRONT_1, vec1)
            \ManipulateBoneScale(@@LEGS_FRONT_2, vec1)
            \ManipulateBoneScale(@@LEGS_BEHIND_1_1, vec1)
            \ManipulateBoneScale(@@LEGS_BEHIND_2_1, vec1)
            \ManipulateBoneScale(@@LEGS_BEHIND_3_1, vec1)
            \ManipulateBoneScale(@@LEGS_BEHIND_1_2, vec1)
            \ManipulateBoneScale(@@LEGS_BEHIND_2_2, vec1)
            \ManipulateBoneScale(@@LEGS_BEHIND_3_2, vec1)

            \ManipulateBoneAngles(@@LEGS_BONE_ROOT, ang)
            \ManipulateBoneAngles(@@LEGS_FRONT_1, ang)
            \ManipulateBoneAngles(@@LEGS_FRONT_2, ang)
            \ManipulateBoneAngles(@@LEGS_BEHIND_1_1, ang)
            \ManipulateBoneAngles(@@LEGS_BEHIND_2_1, ang)
            \ManipulateBoneAngles(@@LEGS_BEHIND_3_1, ang)
            \ManipulateBoneAngles(@@LEGS_BEHIND_1_2, ang)
            \ManipulateBoneAngles(@@LEGS_BEHIND_2_2, ang)
            \ManipulateBoneAngles(@@LEGS_BEHIND_3_2, ang)

            \ManipulateBonePosition(@@LEGS_BONE_ROOT, vec2)
            \ManipulateBonePosition(@@LEGS_FRONT_1, vec2)
            \ManipulateBonePosition(@@LEGS_FRONT_2, vec2)
            \ManipulateBonePosition(@@LEGS_BEHIND_1_1, vec2)
            \ManipulateBonePosition(@@LEGS_BEHIND_2_1, vec2)
            \ManipulateBonePosition(@@LEGS_BEHIND_3_1, vec2)
            \ManipulateBonePosition(@@LEGS_BEHIND_1_2, vec2)
            \ManipulateBonePosition(@@LEGS_BEHIND_2_2, vec2)
            \ManipulateBonePosition(@@LEGS_BEHIND_3_2, vec2)

    Remove: => @ResetScale()
    Reset: =>
        @ResetScale()
        @ResetNeck()
        @ResetLegs()
        @ModifyScale()

    GetLegsSize: => @GetData()\GetLegsSize()
    GetLegsScale: => @GetData()\GetLegsSize()
    GetNeckSize: => @GetData()\GetNeckSize()
    GetNeckScale: => @GetData()\GetNeckSize()
    GetPonySize: => @GetData()\GetPonySize()
    GetPonyScale: => @GetData()\GetPonySize()

    PlayerDeath: =>
        @ResetScale()
        @ResetNeck()
        @ResetLegs()
    PlayerRespawn: =>
        @ResetScale()
        @ModifyScale()

    SlowUpdate: =>
        @ModifyScale()

    ModifyHull: (ent = @ent) =>
        ent.__ppm2_modified_hull = true
        size = @GetPonySize()
        legssize = @GetLegsModifier()

        HULL_MINS = Vector(@@HULL_MINS)
        HULL_MAXS = Vector(@@HULL_MAXS)
        HULL_MAXS_DUCK = Vector(@@HULL_MAXS_DUCK)

        HULL_MINS *= size
        HULL_MAXS *= size
        HULL_MAXS_DUCK *= size

        HULL_MINS.z *= legssize
        HULL_MAXS.z *= legssize
        HULL_MAXS_DUCK.z *= legssize

        with ent
            \SetHull(HULL_MINS, HULL_MAXS) if .SetHull
            \SetHullDuck(HULL_MINS, HULL_MAXS_DUCK) if .SetHullDuck
            \SetStepSize(@@STEP_SIZE * size * @GetLegsModifier(1.2)) if .SetStepSize

    ModifyJumpHeight: (ent = @ent) =>
        return if CLIENT
        return if not @ent.SetJumpPower
        return if ent.__ppm2_modified_jump
        ent\SetJumpPower(ent\GetJumpPower() * PPM2.PONY_JUMP_MODIFIER)
        ent.__ppm2_modified_jump = true

    GetLegsModifier: (mult = 0.4) => 1 + (@GetLegsSize() - 1) * mult

    ModifyViewOffset: (ent = @ent) =>
        size = @GetPonySize()
        necksize = 1 + (@GetNeckSize() - 1) * .3
        legssize = @GetLegsModifier()

        PLAYER_VIEW_OFFSET = Vector(PPM2.PLAYER_VIEW_OFFSET)
        PLAYER_VIEW_OFFSET_DUCK = Vector(PPM2.PLAYER_VIEW_OFFSET_DUCK)

        PLAYER_VIEW_OFFSET *= size * necksize
        PLAYER_VIEW_OFFSET_DUCK *= size * necksize

        PLAYER_VIEW_OFFSET.z *= legssize
        PLAYER_VIEW_OFFSET_DUCK.z *= legssize

        ent\SetViewOffset(PLAYER_VIEW_OFFSET) if ent.SetViewOffset
        ent\SetViewOffsetDucked(PLAYER_VIEW_OFFSET_DUCK) if ent.SetViewOffsetDucked

    ModifyDrawMatrix: (ent = @ent) =>
        return if SERVER
        mat = Matrix()
        mat\Scale(@@DEF_SCALE * @GetPonySize())
        ent\EnableMatrix('RenderMultiply', mat)

    ModifyScale: (ent = @ent) =>
        return if not IsValid(ent)
        return if not ent\IsPony()
        return if ent.Alive and not ent\Alive()
        size = @GetPonySize()

        if USE_NEW_HULL\GetBool()
            @ModifyHull(ent)
            @ModifyJumpHeight(ent)

        @ModifyViewOffset(ent)
        @ModifyDrawMatrix(ent)
        if @lastPAC3BoneReset < RealTime()
            @ModifyNeck(ent)
            @ModifyLegs(ent)

    ModifyNeck: (ent = @ent) =>
        return if SERVER
        return if not IsValid(ent)
        size = (@GetNeckSize() - 1) * 3
        vec = Vector(size, -size, 0)

        with ent
            \ManipulateBonePosition(@@NECK_BONE_1, vec)
            \ManipulateBonePosition(@@NECK_BONE_2, vec)
            \ManipulateBonePosition(@@NECK_BONE_3, vec)
            \ManipulateBonePosition(@@NECK_BONE_4, vec)

    ModifyLegs: (ent = @ent) =>
        return if SERVER
        return if not IsValid(ent)
        realSizeModify = @GetLegsSize() - 1
        size = realSizeModify * 3

        with ent
            \ManipulateBonePosition(@@LEGS_BONE_ROOT, Vector(0, 0, size * 5))
            \ManipulateBonePosition(@@LEGS_FRONT_1, Vector(size * 1.5, 0, 0))
            \ManipulateBonePosition(@@LEGS_FRONT_2, Vector(size * 1.5, 0, 0))

            \ManipulateBonePosition(@@LEGS_FRONT_3, Vector(size, 0, 0))
            \ManipulateBonePosition(@@LEGS_FRONT_4, Vector(size, 0, 0))

            \ManipulateBonePosition(@@LEGS_FRONT_5, Vector(size, size, 0))
            \ManipulateBonePosition(@@LEGS_FRONT_6, Vector(size, size, 0))

            \ManipulateBonePosition(@@LEGS_BEHIND_1_1, Vector(size, -size * 0.5, 0))
            \ManipulateBonePosition(@@LEGS_BEHIND_1_2, Vector(size, -size * 0.5, 0))

            \ManipulateBonePosition(@@LEGS_BEHIND_2_1, Vector(size, 0, 0))
            \ManipulateBonePosition(@@LEGS_BEHIND_2_2, Vector(size, 0, 0))

            \ManipulateBonePosition(@@LEGS_BEHIND_3_1, Vector(size * 2, 0, 0))
            \ManipulateBonePosition(@@LEGS_BEHIND_3_2, Vector(size * 2, 0, 0))

--
-- 0	LrigPelvis
-- 1	Lrig_LEG_BL_Femur
-- 2	Lrig_LEG_BL_Tibia
-- 3	Lrig_LEG_BL_LargeCannon
-- 4	Lrig_LEG_BL_PhalanxPrima
-- 5	Lrig_LEG_BL_RearHoof
-- 6	Lrig_LEG_BR_Femur
-- 7	Lrig_LEG_BR_Tibia
-- 8	Lrig_LEG_BR_LargeCannon
-- 9	Lrig_LEG_BR_PhalanxPrima
-- 10	Lrig_LEG_BR_RearHoof
-- 11	LrigSpine1
-- 12	LrigSpine2
-- 13	LrigRibcage
-- 14	Lrig_LEG_FL_Scapula
-- 15	Lrig_LEG_FL_Humerus
-- 16	Lrig_LEG_FL_Radius
-- 17	Lrig_LEG_FL_Metacarpus
-- 18	Lrig_LEG_FL_PhalangesManus
-- 19	Lrig_LEG_FL_FrontHoof
-- 20	Lrig_LEG_FR_Scapula
-- 21	Lrig_LEG_FR_Humerus
-- 22	Lrig_LEG_FR_Radius
-- 23	Lrig_LEG_FR_Metacarpus
-- 24	Lrig_LEG_FR_PhalangesManus
-- 25	Lrig_LEG_FR_FrontHoof
-- 26	LrigNeck1
-- 27	LrigNeck2
-- 28	LrigNeck3
-- 29	LrigScull
-- 30	Jaw
-- 31	Ear_L
-- 32	Ear_R
-- 33	Mane02
-- 34	Mane03
-- 35	Mane03_tip
-- 36	Mane04
-- 37	Mane05
-- 38	Mane06
-- 39	Mane07
-- 40	Mane01
-- 41	Lrigweaponbone
-- 42	Tail01
-- 43	Tail02
-- 44	Tail03
--

class NewPonySizeContoller extends PonySizeController
    @MODELS = {'models/ppm/player_default_base_new.mdl', 'models/ppm/player_default_base_new_nj.mdl'}

    @NECK_BONE_1 = 26
    @NECK_BONE_2 = 27
    @NECK_BONE_3 = 28
    @NECK_BONE_4 = 29

    @LEGS_FRONT_1 = 19
    @LEGS_FRONT_2 = 25

    @LEGS_FRONT_3 = 17
    @LEGS_FRONT_4 = 23

    @LEGS_FRONT_5 = 16
    @LEGS_FRONT_6 = 22

    @LEGS_BEHIND_1_1 = 2
    @LEGS_BEHIND_1_2 = 7

    @LEGS_BEHIND_2_1 = 4
    @LEGS_BEHIND_2_2 = 9

    @LEGS_BEHIND_3_1 = 3
    @LEGS_BEHIND_3_2 = 8

    new: (...) =>
        super(...)

if CLIENT
    hook.Add 'PPM2_PACResetBones', 'PPM2.Size', (ent, data) ->
        if sizes = data\GetSizeController()
            sizes.ent = ent
            sizes\ModifyNeck()
            sizes\ModifyLegs()
            sizes.lastPAC3BoneReset = RealTime() + 1

PPM2.GetSizeController = (model = 'models/ppm/player_default_base.mdl') -> PonySizeController.AVALIABLE_CONTROLLERS[model\lower()] or PonySizeController


Add RemoveEventListener

Add RemoveEventListener

require "LovePunk.utils.List"

export ^

class eventlistener
	new: =>
		@__listeners = {}

	add: (type, f) =>
		@__listeners[type] = List! if @__listeners[type] == nil
		@__listeners[type]\push f

	remove: (type, f) =>
		l = @__listeners[type]
		return if l == nil
		for i, v in l\ipairs!
			if v == f
				l\remove i
				break

	dispatch: (event) =>
		return if @__listeners[type] == nil
		for e in @__listeners[type]\pairs!
			e!

EventListener = eventlistener!

AddEventListener = (type, f) -> EventListener\add type, f
RemoveEventListener = (type, f) -> EventListener\remove type, f
DispatchEvent = (event) -> EventListener\dispatch event\type! if event.type != nil

require "LovePunk.utils.List"

export ^

class eventlistener
	new: =>
		@__listeners = {}

	add: (type, f) =>
		@__listeners[type] = List! if @__listeners[type] == nil
		@__listeners[type]\push f

	dispatch: (event) =>
		return if @__listeners[type] == nil
		for e in @__listeners[type]\pairs!
			e!

EventListener = eventlistener!

AddEventListener = (type, f) -> EventListener\add type, f
DispatchEvent = (event) -> EventListener\dispatch event\type! if event.type != nil