Fixed error on old files import

Fixed error on old files import

--
-- 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.
--

PARSE_VECTOR = (str = '1.0 1.0 1.0', X = 1, Y = 1, Z = 1) ->
    return Vector(X, Y, Z) if str == ''
    x, y, z = str\match('([0-9.]+) ([0-9.]+) ([0-9.]+)')
    return Vector(tonumber(x) or X, tonumber(y) or Y, tonumber(z) or Z)

PARSE_COLOR = (str = '1.0 1.0 1.0', r = 255, g = 255, b = 255) ->
    return Color(r, g, b) if str == ''
    {x, y, z} = PARSE_VECTOR(str, r / 255, g / 255, b / 255)
    return Color(x * 255, y * 255, z * 255)

IMPORT_TABLE = {
    'gender': {
        name: 'Gender'
        func: (arg = 0) ->
            num = tonumber(arg)
            return num == 0 and 'MALE' or 'FEMALE'
    }

    'coatcolor': {
        name: 'BodyColor'
        func: (arg = '1.0 1.0 1.0') -> PARSE_COLOR(arg)
    }

    'eyecolor_bg': {
        name: 'EyeBackground'
        func: (arg = '1.0 1.0 1.0') -> PARSE_COLOR(arg)
    }

    'eyecolor_grad': {
        name: 'EyeIrisBottom'
        func: (arg = '1.0 1.0 1.0') -> PARSE_COLOR(arg)
    }

    'eyecolor_iris': {
        name: 'EyeIrisTop'
        func: (arg = '1.0 1.0 1.0') -> PARSE_COLOR(arg)
    }

    'eyecolor_line1': {
        name: 'EyeIrisLine1'
        func: (arg = '1.0 1.0 1.0') -> PARSE_COLOR(arg)
    }

    'eyecolor_line2': {
        name: 'EyeIrisLine2'
        func: (arg = '1.0 1.0 1.0') -> PARSE_COLOR(arg)
    }

    'haircolor1': {
        name: {'ManeColor1', 'TailColor1', 'ManeColor2', 'TailColor2'}
        func: (arg = '1.0 1.0 1.0') -> PARSE_COLOR(arg)
    }

    'eyejholerssize': {
        name: 'HoleWidth'
        func: (arg = '1') -> tonumber(arg) or 1
    }

    'eyeirissize': {
        name: 'IrisSize'
        func: (arg = '1') -> (tonumber(arg) or 1) * 1.2
    }

    'eyeholesize': {
        name: 'HoleSize'
        func: (arg = '0.8') -> tonumber(arg) or 0.8
    }

    'bodyweight': {
        name: 'Weight'
        func: (arg = 1) -> tonumber(arg) or 1
    }

    'mane': {
        name: {'ManeType', 'ManeTypeNew'}
        func: (arg = 0) -> (tonumber(arg) or 0) - 1
    }

    'manel': {
        name: {'ManeTypeLower', 'ManeTypeLowerNew'}
        func: (arg = 0) -> (tonumber(arg) or 0) - 1
    }

    'tail': {
        name: {'TailType', 'TailTypeNew'}
        func: (arg = 0) -> (tonumber(arg) or 0) - 1
    }

    'tailsize': {
        name: 'TailSize'
        func: (arg = 1) -> tonumber(arg) or 1
    }

    'cmark': {
        name: 'CMarkType'
        func: (arg = 1) -> (tonumber(arg) or 1) - 1
    }

    'cmark_enabled': {
        name: 'CMark'
        func: (arg = '1') -> arg == '1' or arg == '2'
    }
}

for i = 1, 8
    IMPORT_TABLE["bodydetail#{i}"] = {
        name: "BodyDetail#{i}"
        func: (arg = 1) -> (tonumber(arg) or 1) - 1
    }

    IMPORT_TABLE["bodydetail#{i}_c"] = {
        name: "BodyDetailColor#{i}"
        func: (arg = '1.0 1.0 1.0') -> PARSE_COLOR(arg)
    }

for i = 2, 6
    IMPORT_TABLE["haircolor#{i}"] = {
        name: {"ManeDetailColor#{i - 1}", "TailDetailColor#{i - 1}"}
        func: (arg = '1.0 1.0 1.0') -> PARSE_COLOR(arg)
    }

PPM2.ReadFromOldData = (filename = '_current') ->
    read = file.Read("ppm/#{filename}.txt", 'DATA')
    return false if read == ''
    split = [str\Trim() for str in *string.Explode('\n', read\Replace('\r', ''))]
    outputData = {}

    for line in *split
        varID = line\match('([a-zA-Z0-9_]+)')
        continue if not varID or varID == ''
        continue if not IMPORT_TABLE[varID]
        dt = IMPORT_TABLE[varID]
        value = line\sub(#varID + 2)
        if type(dt.name) ~= 'table'
            outputData[dt.name] = dt.func(value)
        else
            get = dt.func(value)
            outputData[name] = get for name in *dt.name

    data = PPM2.PonyDataInstance("#{filename}_imported", nil, false)
    for key, value in pairs outputData
        data["Set#{key}"](data, value, false)
    return data, outputData

--
-- 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.
--

PARSE_VECTOR = (str = '1.0 1.0 1.0', X = 1, Y = 1, Z = 1) ->
    return Vector(X, Y, Z) if str == ''
    x, y, z = str\match('([0-9.]+) ([0-9.]+) ([0-9.]+)')
    return Vector(tonumber(x) or X, tonumber(y) or Y, tonumber(z) or Z)

PARSE_COLOR = (str = '1.0 1.0 1.0', r = 255, g = 255, b = 255) ->
    return Color(r, g, b) if str == ''
    {x, y, z} = PARSE_VECTOR(str, r / 255, g / 255, b / 255)
    return Color(x * 255, y * 255, z * 255)

IMPORT_TABLE = {
    'gender': {
        name: 'Gender'
        func: (arg = 0) ->
            num = tonumber(arg)
            return num == 0 and 'MALE' or 'FEMALE'
    }

    'coatcolor': {
        name: 'BodyColor'
        func: (arg = '1.0 1.0 1.0') -> PARSE_COLOR(arg)
    }

    'eyecolor_bg': {
        name: 'EyeBackground'
        func: (arg = '1.0 1.0 1.0') -> PARSE_COLOR(arg)
    }

    'eyecolor_grad': {
        name: 'EyeIrisBottom'
        func: (arg = '1.0 1.0 1.0') -> PARSE_COLOR(arg)
    }

    'eyecolor_iris': {
        name: 'EyeIrisTop'
        func: (arg = '1.0 1.0 1.0') -> PARSE_COLOR(arg)
    }

    'eyecolor_line1': {
        name: 'EyeIrisLine1'
        func: (arg = '1.0 1.0 1.0') -> PARSE_COLOR(arg)
    }

    'eyecolor_line2': {
        name: 'EyeIrisLine2'
        func: (arg = '1.0 1.0 1.0') -> PARSE_COLOR(arg)
    }

    'haircolor1': {
        name: {'ManeColor1', 'TailColor1', 'ManeColor2', 'TailColor2'}
        func: (arg = '1.0 1.0 1.0') -> PARSE_COLOR(arg)
    }

    'eyejholerssize': {
        name: 'HoleWidth'
        func: (arg = '1') -> tonumber(arg) or 1
    }

    'eyeirissize': {
        name: 'IrisSize'
        func: (arg = '1') -> (tonumber(arg) or 1) * 1.2
    }

    'eyeholesize': {
        name: 'HoleSize'
        func: (arg = '0.8') -> tonumber(arg) or 0.8
    }

    'bodyweight': {
        name: 'Weight'
        func: (arg = 1) -> tonumber(arg) or 1
    }

    'mane': {
        name: {'ManeType', 'ManeTypeNew'}
        func: (arg = 0) -> (tonumber(arg) or 0) - 1
    }

    'manel': {
        name: {'ManeTypeLower', 'ManeTypeLowerNew'}
        func: (arg = 0) -> (tonumber(arg) or 0) - 1
    }

    'tail': {
        name: {'TailType', 'TailTypeNew'}
        func: (arg = 0) -> (tonumber(arg) or 0) - 1
    }

    'tailsize': {
        name: 'TailSize'
        func: (arg = 1) -> tonumber(arg) or 1
    }

    'cmark': {
        name: 'CMarkType'
        func: (arg = 1) -> (tonumber(arg) or 1) - 1
    }

    'cmark_enabled': {
        name: 'CMark'
        func: (arg = '1') -> arg == '1' or arg == '2'
    }
}

for i = 1, 8
    IMPORT_TABLE["bodydetail#{i}"] = {
        name: "BodyDetail#{i}"
        func: (arg = 1) -> (tonumber(arg) or 1) - 1
    }

    IMPORT_TABLE["bodydetail#{i}_c"] = {
        name: "BodyDetailColor#{i}"
        func: (arg = '1.0 1.0 1.0') -> PARSE_COLOR(arg)
    }

for i = 2, 6
    IMPORT_TABLE["haircolor#{i}"] = {
        name: {"ManeDetailColor#{i - 1}", "TailDetailColor#{i - 1}"}
        func: (arg = '1.0 1.0 1.0') -> PARSE_COLOR(arg)
    }

PPM2.ReadFromOldData = (filename = '_current') ->
    read = file.Read("ppm/#{filename}.txt", 'DATA')
    return false if read == ''
    split = [str\Trim() for str in *string.Explode('\n', read\Replace('\r', ''))]
    outputData = {}

    for line in *split
        varID = line\match('([a-zA-Z0-9_]+)')
        continue if not varID or varID == ''
        continue if not IMPORT_TABLE[varID]
        dt = IMPORT_TABLE[varID]
        value = line\sub(#varID + 2)
        if type(dt.name) ~= 'table'
            outputData[dt.name] = dt.func(value)
        else
            get = dt.func(value)
            outputData[name] = get for name in *dt.name

    data = PonyDataInstance("#{filename}_imported", nil, false)
    for key, value in pairs outputData
        data["Set#{key}"](data, value, false)
    return data, outputData


refactor

refactor

export ^

require "star"
gamera = require "lib/gamera/gamera"

class SpacebaseView
    new: (@spacebase) =>
        @size = @spacebase.totalSize()
        @canvas = love.graphics.newCanvas(@size, @size)
        @cam = gamera.new(-@size/2, -@size/2, 2 * @size, 2 * @size)
        @cam\setPosition(@size/2, @size/2)
        @cam\setAngle(math.pi/4)

        @offset_speed = 500  -- px/s
        @zoom_rate = 0.7
        @rotationspeed = 1

        @starField = {}
        number_of_stars = 200
        for i=1,number_of_stars
            table.insert(@starField, Star())

    update: (dt) =>
        cam_x, cam_y = @cam\getPosition()
        cam_zoom = @cam\getScale()
        cam_angle = @cam\getAngle()
        if love.keyboard.isDown("down")
            cam_x -= @offset_speed * dt * math.sin(cam_angle)
            cam_y += @offset_speed * dt * math.cos(cam_angle)
        if love.keyboard.isDown("up")
            cam_x += @offset_speed * dt * math.sin(cam_angle)
            cam_y -= @offset_speed * dt * math.cos(cam_angle)
        if love.keyboard.isDown("right")
            cam_x += @offset_speed * dt * math.cos(cam_angle)
            cam_y += @offset_speed * dt * math.sin(cam_angle)
        if love.keyboard.isDown("left")
            cam_x -= @offset_speed * dt * math.cos(cam_angle)
            cam_y -= @offset_speed * dt * math.sin(cam_angle)
        @cam\setPosition(cam_x, cam_y)
        if love.keyboard.isDown("i")
            @cam\setScale(cam_zoom + cam_zoom * @zoom_rate * dt)
        if love.keyboard.isDown("o")
            @cam\setScale(cam_zoom - cam_zoom * @zoom_rate * dt)
        if love.keyboard.isDown("r")
            @cam\setAngle(cam_angle + @rotationspeed * dt)

    draw: =>
        @\draw_starfield()
        love.graphics.scale(1, 0.5)
        @cam\draw(@spacebase\draw)

    draw_starfield: =>
        spaceColor = {14, 17, 23}
        w_x, w_y = @cam\toScreen(0, 0)
        love.graphics.setColor(spaceColor)
        love.graphics.rectangle("fill", 0, 0, wScr(), hScr())
        for star in *@starField
            star\draw(w_x, w_y)

    -- draw_spacebase: =>
    --     w, h = wScr(), hScr()
    --     @canvas\clear(0, 0, 0, 0) -- clear to transparent
    --     love.graphics.setCanvas(@canvas)
    --     @spacebase\draw()
    --     love.graphics.setCanvas()
    --     love.graphics.scale(@zoom, @zoom)
    --     translate_x = @offset_center_x + w / (2 * @zoom)
    --     translate_y = @offset_center_y + h / (2 * @zoom)
    --     love.graphics.translate(translate_x, translate_y)
    --     -- love.graphics.scale(1, 0.5)
    --     -- love.graphics.rotate(math.pi/4 + @rotation)
    --     -- love.graphics.circle("fill", 0, 0, 10)
    --     love.graphics.setColor(255, 255, 255)
    --     love.graphics.draw(@canvas, -@size / (2 * @zoom), -@size / (2 * @zoom))

    keyreleased: (key) =>

    coordinatesInWorld: (x, y) =>
        world_x, world_y = @cam\toWorld(x, 2 * y)
        return {world_x, world_y}

export ^

require "star"
gamera = require "lib/gamera/gamera"

export cos, sin = math.cos, math.sin

class SpacebaseView
    new: (@spacebase) =>
        @size = @spacebase.totalSize()
        @canvas = love.graphics.newCanvas(@size, @size)
        @cam = gamera.new(-@size/2, -@size/2, 2 * @size, 2 * @size)
        @cam\setPosition(@size/2, @size/2)
        @cam\setAngle(math.pi/4)

        @offset_speed = 500  -- px/s
        @zoom_rate = 0.7
        @rotationspeed = 1

        @starField = {}
        number_of_stars = 200
        for i=1,number_of_stars
            table.insert(@starField, Star())

    update: (dt) =>
        cam_x, cam_y = @cam\getPosition()
        cam_zoom = @cam\getScale()
        cam_angle = @cam\getAngle()
        if love.keyboard.isDown("down")
            cam_x -= @offset_speed * dt * sin(cam_angle)
            cam_y += @offset_speed * dt * cos(cam_angle)
        if love.keyboard.isDown("up")
            cam_x += @offset_speed * dt * sin(cam_angle)
            cam_y -= @offset_speed * dt * cos(cam_angle)
        if love.keyboard.isDown("right")
            cam_x += @offset_speed * dt * cos(cam_angle)
            cam_y += @offset_speed * dt * sin(cam_angle)
        if love.keyboard.isDown("left")
            cam_x -= @offset_speed * dt * cos(cam_angle)
            cam_y -= @offset_speed * dt * sin(cam_angle)
        @cam\setPosition(cam_x, cam_y)
        if love.keyboard.isDown("i")
            @cam\setScale(cam_zoom + cam_zoom * @zoom_rate * dt)
        if love.keyboard.isDown("o")
            @cam\setScale(cam_zoom - cam_zoom * @zoom_rate * dt)
        if love.keyboard.isDown("r")
            @cam\setAngle(cam_angle + @rotationspeed * dt)

    draw: =>
        @\draw_starfield()
        love.graphics.scale(1, 0.5)
        @cam\draw(@spacebase\draw)

    draw_starfield: =>
        spaceColor = {14, 17, 23}
        w_x, w_y = @cam\toScreen(0, 0)
        love.graphics.setColor(spaceColor)
        love.graphics.rectangle("fill", 0, 0, wScr(), hScr())
        for star in *@starField
            star\draw(w_x, w_y)

    -- draw_spacebase: =>
    --     w, h = wScr(), hScr()
    --     @canvas\clear(0, 0, 0, 0) -- clear to transparent
    --     love.graphics.setCanvas(@canvas)
    --     @spacebase\draw()
    --     love.graphics.setCanvas()
    --     love.graphics.scale(@zoom, @zoom)
    --     translate_x = @offset_center_x + w / (2 * @zoom)
    --     translate_y = @offset_center_y + h / (2 * @zoom)
    --     love.graphics.translate(translate_x, translate_y)
    --     -- love.graphics.scale(1, 0.5)
    --     -- love.graphics.rotate(math.pi/4 + @rotation)
    --     -- love.graphics.circle("fill", 0, 0, 10)
    --     love.graphics.setColor(255, 255, 255)
    --     love.graphics.draw(@canvas, -@size / (2 * @zoom), -@size / (2 * @zoom))

    keyreleased: (key) =>

    coordinatesInWorld: (x, y) =>
        world_x, world_y = @cam\toWorld(x, 2 * y)
        return {world_x, world_y}


PreDrawOpaqueRenderables never gets called with b = false

thanks gmod

--
-- 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.
--

class BonesSequence extends DLib.SequenceBase
	new: (controller, data) =>
		super(controller, data)

		{
			'bones': @bonesNames
			'numid': @numid
		} = data

		@modifierID = controller\GetModifierID(@name .. '_sequence')
		@bonesFuncsPos = ['SetModifier' .. boneName .. 'Position' for boneName in *@bonesNames]
		@bonesFuncsScale = ['SetModifier' .. boneName .. 'Scale' for boneName in *@bonesNames]
		@bonesFuncsAngles = ['SetModifier' .. boneName .. 'Angles' for boneName in *@bonesNames]
		@ent = controller.ent
		@controller = controller
		@Launch()

	GetController: => @controller
	GetEntity: => @ent

	Think: (delta = 0) =>
		@ent = @controller.ent
		return false if not IsValid(@ent)
		super(delta)

	Stop: =>
		super()
		@controller\ResetModifiers(@name .. '_sequence')

	SetBonePosition: (id = 1, val = Vector(0, 0, 0)) => @controller[@bonesFuncsPos[id]] and @controller[@bonesFuncsPos[id]](@controller, @modifierID, val)
	SetBoneScale: (id = 1, val = 0) => @controller[@bonesFuncsScale[id]] and @controller[@bonesFuncsScale[id]](@controller, @modifierID, val)
	SetBoneAngles: (id = 1, val = Angle(0, 0, 0)) => @controller[@bonesFuncsAngles[id]] and @controller[@bonesFuncsAngles[id]](@controller, @modifierID, val)

PPM2.BonesSequence = BonesSequence

-- 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

RESET_BONE_POS = Vector(0, 0, 0)
RESET_BONE_ANGLES = Angle(0, 0, 0)
RESET_BONE_SCALE = Vector(1, 1, 1)
resetBones = (ent) ->
	for i = 0, ent\GetBoneCount() - 1
		ent\ManipulateBonePosition(i, RESET_BONE_POS)
		ent\ManipulateBoneScale(i, RESET_BONE_SCALE)
		ent\ManipulateBoneAngles(i, RESET_BONE_ANGLES)

for ent in *ents.GetAll()
	ent.__ppmBonesModifiers = nil

class PPM2.EntityBonesModifier extends DLib.SequenceHolder
	@OBJECTS = {}
	@resetBones = resetBones

	@SEQUENCES = {
		{
			'name': 'floppy_ears'
			'autostart': false
			'repeat': false
			'time': 5
			'bones': {'Ear_L', 'Ear_R'}
			'reset': =>
				@SetBoneAngles(1, Angle(0, -84, -40))
				@SetBoneAngles(2, Angle(0, 84, -40))
			'func': (delta, timeOfAnim) =>
		}

		{
			'name': 'floppy_ears_weak'
			'autostart': false
			'repeat': false
			'time': 5
			'bones': {'Ear_L', 'Ear_R'}
			'reset': =>
				@SetBoneAngles(1, Angle(0, -20, -20))
				@SetBoneAngles(2, Angle(0, 20, -20))
			'func': (delta, timeOfAnim) =>
		}

		{
			'name': 'forward_ears'
			'autostart': false
			'repeat': false
			'time': 5
			'bones': {'Ear_L', 'Ear_R'}
			'reset': =>
				@SetBoneAngles(1, Angle(0, -15, -27))
				@SetBoneAngles(2, Angle(0, 15, -27))
			'func': (delta, timeOfAnim) =>
		}

		{
			'name': 'neck_flopping_backward'
			'autostart': false
			'repeat': false
			'time': 3
			'bones': {'LrigNeck3'}
			'reset': =>
			'func': (delta, timeOfAnim) =>
				@SetBoneAngles(1, Angle(0, -12 * timeOfAnim, math.sin(RealTime() * 4) * 20))
		}

		{
			'name': 'neck_backward'
			'autostart': false
			'repeat': false
			'time': 5
			'bones': {'LrigNeck3'}
			'reset': => @SetBoneAngles(1, Angle(0, -12, 0))
		}

		{
			'name': 'neck_twitch'
			'autostart': false
			'repeat': false
			'time': 5
			'bones': {'LrigNeck3'}
			'func': (delta, timeOfAnim) =>
				@SetBoneAngles(1, Angle(0, math.cos(RealTime() * 4) * 20, 0))
		}

		{
			'name': 'neck_twitch_fast'
			'autostart': false
			'repeat': false
			'time': 5
			'bones': {'LrigNeck3'}
			'func': (delta, timeOfAnim) =>
				@SetBoneAngles(1, Angle(0, math.cos(RealTime() * 8) * 20, 0))
		}

		{
			'name': 'neck_left'
			'autostart': false
			'repeat': false
			'time': 5
			'bones': {'LrigNeck3'}
			'reset': => @SetBoneAngles(1, Angle(14, 0, 12))
		}

		{
			'name': 'neck_right'
			'autostart': false
			'repeat': false
			'time': 5
			'bones': {'LrigNeck3'}
			'reset': => @SetBoneAngles(1, Angle(-14, 0, -12))
		}

		{
			'name': 'forward_left'
			'autostart': false
			'repeat': false
			'time': 3
			'bones': {'LrigNeck3'}
			'reset': =>
				@SetBoneAngles(1, Angle(10, 12, -9))
		}

		{
			'name': 'forward_right'
			'autostart': false
			'repeat': false
			'time': 3
			'bones': {'LrigNeck3'}
			'reset': =>
				@SetBoneAngles(1, Angle(-10, 12, 9))
		}
	}

	@SequenceObject = BonesSequence

	PreDrawOpaqueRenderables = (a, b) ->
		frame = FrameNumber()
		rtime = RealTime()
		for obj in *@OBJECTS
			if not obj\IsValid()
				oldObjects = @OBJECTS
				@OBJECTS = {}
				for obj2 in *oldObjects
					if obj2\IsValid()
						table.insert(@OBJECTS, obj2)
					else
						lent = obj2.ent
						if IsValid(lent)
							lent.__ppmBonesModifiers = nil
				return

			if obj.callFrame ~= frame and (not obj.pac3Last or obj.pac3Last < rtime) and not obj.ent\IsDormant() and not obj.ent\GetNoDraw()
				resetBones(obj.ent)
				data = obj.ent\GetPonyData()
				hook.Call('PPM2.SetupBones', nil, StrongEntity(obj.ent), data) if data
				obj\Think()

	hook.Add 'PreDrawOpaqueRenderables', 'PPM2.EntityBonesModifier', PreDrawOpaqueRenderables, -2

	new: (ent = NULL) =>
		super()
		@ent = ent
		@bonesMappingID = {}
		@bonesMappingName = {}
		@bonesMapping = {}
		@bonesMappingForName = {}
		@bonesMappingForID = {}
		@bonesIterable = {}
		@boneCount = 0
		@isValid = false
		table.insert(@@OBJECTS, @)
		@lastCall = RealTime()
		@Setup() if IsValid(ent)

	Setup: (ent = @ent) =>
		return false if not IsValid(ent)
		@lastModel = ent\GetModel()
		@ClearModifiers()
		@isValid = true
		@ent = ent
		@bonesMappingID = {}
		@bonesMappingName = {}
		@boneCount = ent\GetBoneCount()
		@bonesIterable = for i = 0, @boneCount - 1
			name = ent\GetBoneName(i)
			@bonesMappingID[i] = name
			@bonesMapping[i] = name
			@bonesMappingName[name] = i
			@bonesMapping[name] = i
			@bonesMappingForName[name] = name
			@bonesMappingForName[i] = name
			@bonesMappingForID[name] = i
			@bonesMappingForID[i] = i
			@RegisterModifier(name .. 'Position', (-> Vector(0, 0, 0)), (-> Vector(0, 0, 0)))
			@RegisterModifier(name .. 'Scale', (-> Vector(0, 0, 0)), (-> Vector(0, 0, 0)))
			@RegisterModifier(name .. 'Angles', (-> Angle(0, 0, 0)), (-> Angle(0, 0, 0)))
			@SetupLerpTables(name .. 'Position')
			@SetupLerpTables(name .. 'Scale')
			@SetupLerpTables(name .. 'Angles')
			@SetLerpFunc(name .. 'Position', LerpVector)
			@SetLerpFunc(name .. 'Scale', LerpVector)
			@SetLerpFunc(name .. 'Angles', LerpAngle)
			--@RegisterModifier(name .. 'Jiggle', 0)
			{i, name, 'Calculate' .. name .. 'Position', 'Calculate' .. name .. 'Scale', 'Calculate' .. name .. 'Angles'}

	Think: (force = false) =>
		return if not super() or not force and @callFrame == FrameNumber()
		@callFrame = FrameNumber()
		for data in *@bonesIterable
			id = data[1]
			name = data[2]
			calc = data[3]
			calcScale = data[4]
			calcAngles = data[5]
			with @ent
				\ManipulateBonePosition(id, \GetManipulateBonePosition(id) + @[calc](@))
				\ManipulateBoneScale(id, \GetManipulateBoneScale(id) + @[calcScale](@))
				\ManipulateBoneAngles(id, \GetManipulateBoneAngles(id) + @[calcAngles](@))

	ResetBones: =>
		return if @pac3Last and @pac3Last > RealTime()
		resetBones(@ent)

	IsValid: => @isValid and @ent\IsValid()
	GetEntity: => @ent

with FindMetaTable('Entity')
	.PPMBonesModifier = =>
		with t = .GetTable(@)
			return if not t
			return .__ppmBonesModifiers if IsValid(.__ppmBonesModifiers)
			.__ppmBonesModifiers = PPM2.EntityBonesModifier(@)
			.__ppmBonesModifiers.ent = @
			.__ppmBonesModifiers\Setup(@) if .__ppmBonesModifiers.lastModel ~= @GetModel()
			return .__ppmBonesModifiers

hook.Add 'PAC3ResetBones', 'PPM2.EntityBonesModifier', =>
	data = @GetPonyData()
	hook.Call('PPM2.SetupBones', nil, StrongEntity(@), data) if data
	if @__ppmBonesModifiers
		@__ppmBonesModifiers\Think()
		@__ppmBonesModifiers.pac3Last = RealTime() + 0.2

ent.__ppmBonesModifiers = nil for ent in *ents.GetAll()

--
-- 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.
--

class BonesSequence extends DLib.SequenceBase
	new: (controller, data) =>
		super(controller, data)

		{
			'bones': @bonesNames
			'numid': @numid
		} = data

		@modifierID = controller\GetModifierID(@name .. '_sequence')
		@bonesFuncsPos = ['SetModifier' .. boneName .. 'Position' for boneName in *@bonesNames]
		@bonesFuncsScale = ['SetModifier' .. boneName .. 'Scale' for boneName in *@bonesNames]
		@bonesFuncsAngles = ['SetModifier' .. boneName .. 'Angles' for boneName in *@bonesNames]
		@ent = controller.ent
		@controller = controller
		@Launch()

	GetController: => @controller
	GetEntity: => @ent

	Think: (delta = 0) =>
		@ent = @controller.ent
		return false if not IsValid(@ent)
		super(delta)

	Stop: =>
		super()
		@controller\ResetModifiers(@name .. '_sequence')

	SetBonePosition: (id = 1, val = Vector(0, 0, 0)) => @controller[@bonesFuncsPos[id]] and @controller[@bonesFuncsPos[id]](@controller, @modifierID, val)
	SetBoneScale: (id = 1, val = 0) => @controller[@bonesFuncsScale[id]] and @controller[@bonesFuncsScale[id]](@controller, @modifierID, val)
	SetBoneAngles: (id = 1, val = Angle(0, 0, 0)) => @controller[@bonesFuncsAngles[id]] and @controller[@bonesFuncsAngles[id]](@controller, @modifierID, val)

PPM2.BonesSequence = BonesSequence

-- 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

RESET_BONE_POS = Vector(0, 0, 0)
RESET_BONE_ANGLES = Angle(0, 0, 0)
RESET_BONE_SCALE = Vector(1, 1, 1)
resetBones = (ent) ->
	for i = 0, ent\GetBoneCount() - 1
		ent\ManipulateBonePosition(i, RESET_BONE_POS)
		ent\ManipulateBoneScale(i, RESET_BONE_SCALE)
		ent\ManipulateBoneAngles(i, RESET_BONE_ANGLES)

for ent in *ents.GetAll()
	ent.__ppmBonesModifiers = nil

class PPM2.EntityBonesModifier extends DLib.SequenceHolder
	@OBJECTS = {}
	@resetBones = resetBones

	@SEQUENCES = {
		{
			'name': 'floppy_ears'
			'autostart': false
			'repeat': false
			'time': 5
			'bones': {'Ear_L', 'Ear_R'}
			'reset': =>
				@SetBoneAngles(1, Angle(0, -84, -40))
				@SetBoneAngles(2, Angle(0, 84, -40))
			'func': (delta, timeOfAnim) =>
		}

		{
			'name': 'floppy_ears_weak'
			'autostart': false
			'repeat': false
			'time': 5
			'bones': {'Ear_L', 'Ear_R'}
			'reset': =>
				@SetBoneAngles(1, Angle(0, -20, -20))
				@SetBoneAngles(2, Angle(0, 20, -20))
			'func': (delta, timeOfAnim) =>
		}

		{
			'name': 'forward_ears'
			'autostart': false
			'repeat': false
			'time': 5
			'bones': {'Ear_L', 'Ear_R'}
			'reset': =>
				@SetBoneAngles(1, Angle(0, -15, -27))
				@SetBoneAngles(2, Angle(0, 15, -27))
			'func': (delta, timeOfAnim) =>
		}

		{
			'name': 'neck_flopping_backward'
			'autostart': false
			'repeat': false
			'time': 3
			'bones': {'LrigNeck3'}
			'reset': =>
			'func': (delta, timeOfAnim) =>
				@SetBoneAngles(1, Angle(0, -12 * timeOfAnim, math.sin(RealTime() * 4) * 20))
		}

		{
			'name': 'neck_backward'
			'autostart': false
			'repeat': false
			'time': 5
			'bones': {'LrigNeck3'}
			'reset': => @SetBoneAngles(1, Angle(0, -12, 0))
		}

		{
			'name': 'neck_twitch'
			'autostart': false
			'repeat': false
			'time': 5
			'bones': {'LrigNeck3'}
			'func': (delta, timeOfAnim) =>
				@SetBoneAngles(1, Angle(0, math.cos(RealTime() * 4) * 20, 0))
		}

		{
			'name': 'neck_twitch_fast'
			'autostart': false
			'repeat': false
			'time': 5
			'bones': {'LrigNeck3'}
			'func': (delta, timeOfAnim) =>
				@SetBoneAngles(1, Angle(0, math.cos(RealTime() * 8) * 20, 0))
		}

		{
			'name': 'neck_left'
			'autostart': false
			'repeat': false
			'time': 5
			'bones': {'LrigNeck3'}
			'reset': => @SetBoneAngles(1, Angle(14, 0, 12))
		}

		{
			'name': 'neck_right'
			'autostart': false
			'repeat': false
			'time': 5
			'bones': {'LrigNeck3'}
			'reset': => @SetBoneAngles(1, Angle(-14, 0, -12))
		}

		{
			'name': 'forward_left'
			'autostart': false
			'repeat': false
			'time': 3
			'bones': {'LrigNeck3'}
			'reset': =>
				@SetBoneAngles(1, Angle(10, 12, -9))
		}

		{
			'name': 'forward_right'
			'autostart': false
			'repeat': false
			'time': 3
			'bones': {'LrigNeck3'}
			'reset': =>
				@SetBoneAngles(1, Angle(-10, 12, 9))
		}
	}

	@SequenceObject = BonesSequence

	PreDrawOpaqueRenderables = (a, b) ->
		--return if a or b
		frame = FrameNumber()
		rtime = RealTime()
		for obj in *@OBJECTS
			if not obj\IsValid()
				oldObjects = @OBJECTS
				@OBJECTS = {}
				for obj2 in *oldObjects
					if obj2\IsValid()
						table.insert(@OBJECTS, obj2)
					else
						lent = obj2.ent
						if IsValid(lent)
							lent.__ppmBonesModifiers = nil
				return

			if obj.callFrame ~= frame and (not obj.pac3Last or obj.pac3Last < rtime) and not obj.ent\IsDormant() and not obj.ent\GetNoDraw()
				resetBones(obj.ent)
				data = obj.ent\GetPonyData()
				hook.Call('PPM2.SetupBones', nil, StrongEntity(obj.ent), data) if data
				obj\Think()

	hook.Add 'PreDrawOpaqueRenderables', 'PPM2.EntityBonesModifier', PreDrawOpaqueRenderables, -2

	new: (ent = NULL) =>
		super()
		@ent = ent
		@bonesMappingID = {}
		@bonesMappingName = {}
		@bonesMapping = {}
		@bonesMappingForName = {}
		@bonesMappingForID = {}
		@bonesIterable = {}
		@boneCount = 0
		@isValid = false
		table.insert(@@OBJECTS, @)
		@lastCall = RealTime()
		@Setup() if IsValid(ent)

	Setup: (ent = @ent) =>
		return false if not IsValid(ent)
		@lastModel = ent\GetModel()
		@ClearModifiers()
		@isValid = true
		@ent = ent
		@bonesMappingID = {}
		@bonesMappingName = {}
		@boneCount = ent\GetBoneCount()
		@bonesIterable = for i = 0, @boneCount - 1
			name = ent\GetBoneName(i)
			@bonesMappingID[i] = name
			@bonesMapping[i] = name
			@bonesMappingName[name] = i
			@bonesMapping[name] = i
			@bonesMappingForName[name] = name
			@bonesMappingForName[i] = name
			@bonesMappingForID[name] = i
			@bonesMappingForID[i] = i
			@RegisterModifier(name .. 'Position', (-> Vector(0, 0, 0)), (-> Vector(0, 0, 0)))
			@RegisterModifier(name .. 'Scale', (-> Vector(0, 0, 0)), (-> Vector(0, 0, 0)))
			@RegisterModifier(name .. 'Angles', (-> Angle(0, 0, 0)), (-> Angle(0, 0, 0)))
			@SetupLerpTables(name .. 'Position')
			@SetupLerpTables(name .. 'Scale')
			@SetupLerpTables(name .. 'Angles')
			@SetLerpFunc(name .. 'Position', LerpVector)
			@SetLerpFunc(name .. 'Scale', LerpVector)
			@SetLerpFunc(name .. 'Angles', LerpAngle)
			--@RegisterModifier(name .. 'Jiggle', 0)
			{i, name, 'Calculate' .. name .. 'Position', 'Calculate' .. name .. 'Scale', 'Calculate' .. name .. 'Angles'}

	Think: (force = false) =>
		return if not super() or not force and @callFrame == FrameNumber()
		@callFrame = FrameNumber()
		for data in *@bonesIterable
			id = data[1]
			name = data[2]
			calc = data[3]
			calcScale = data[4]
			calcAngles = data[5]
			with @ent
				\ManipulateBonePosition(id, \GetManipulateBonePosition(id) + @[calc](@))
				\ManipulateBoneScale(id, \GetManipulateBoneScale(id) + @[calcScale](@))
				\ManipulateBoneAngles(id, \GetManipulateBoneAngles(id) + @[calcAngles](@))

	ResetBones: =>
		return if @pac3Last and @pac3Last > RealTime()
		resetBones(@ent)

	IsValid: => @isValid and @ent\IsValid()
	GetEntity: => @ent

with FindMetaTable('Entity')
	.PPMBonesModifier = =>
		with t = .GetTable(@)
			return if not t
			return .__ppmBonesModifiers if IsValid(.__ppmBonesModifiers)
			.__ppmBonesModifiers = PPM2.EntityBonesModifier(@)
			.__ppmBonesModifiers.ent = @
			.__ppmBonesModifiers\Setup(@) if .__ppmBonesModifiers.lastModel ~= @GetModel()
			return .__ppmBonesModifiers

hook.Add 'PAC3ResetBones', 'PPM2.EntityBonesModifier', =>
	data = @GetPonyData()
	hook.Call('PPM2.SetupBones', nil, StrongEntity(@), data) if data
	if @__ppmBonesModifiers
		@__ppmBonesModifiers\Think()
		@__ppmBonesModifiers.pac3Last = RealTime() + 0.2

ent.__ppmBonesModifiers = nil for ent in *ents.GetAll()