Don't use eye refract by default

Don't use eye refract by default

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

wUInt = (def = 0, size = 8) ->
    return (arg = def) -> net.WriteUInt(arg, size)

wInt = (def = 0, size = 8) ->
    return (arg = def) -> net.WriteInt(arg, size)

rUInt = (size = 8, min = 0, max = 255) ->
    return -> math.Clamp(net.ReadUInt(size), min, max)

rInt = (size = 8, min = -128, max = 127) ->
    return -> math.Clamp(net.ReadInt(size), min, max)

rFloat = (min = 0, max = 255) ->
    return -> math.Clamp(net.ReadFloat(), min, max)

wFloat = net.WriteFloat
rSEnt = net.ReadStrongEntity
wSEnt = net.WriteStrongEntity
rBool = net.ReadBool
wBool = net.WriteBool
rColor = net.ReadColor
wColor = net.WriteColor
rString = net.ReadString
wString = net.WriteString

COLOR_FIXER = (r = 255, g = 255, b = 255, a = 255) ->
    func = (arg = Color(r, g, b, a)) ->
        if type(arg) ~= 'table'
            return Color(255, 255, 255)
        else
            {:r, :g, :b, :a} = arg
            if r and g and b and a
                return Color(r, g, b, a)
            else
                return Color(255, 255, 255)
    return func

URL_FIXER = (arg = '') ->
    arg = tostring(arg)
    if arg\find('^https?://')
        return arg
    else
        return ''

rURL = -> URL_FIXER(rString())

FLOAT_FIXER = (def = 1, min = 0, max = 1) ->
    defFunc = -> def if type(def) ~= 'function'
    defFunc = def if type(def) == 'function'
    return (arg = defFunc()) -> math.Clamp(tonumber(arg) or defFunc(), min, max)

INT_FIXER = (def = 1, min = 0, max = 1) ->
    defFunc = -> def if type(def) ~= 'function'
    defFunc = def if type(def) == 'function'
    return (arg = defFunc()) -> math.floor(math.Clamp(tonumber(arg) or defFunc(), min, max))

PPM2.PonyDataRegistry = {
    'age': {
        default: -> PPM2.AGE_ADULT
        getFunc: 'Age'
        enum: {'FILLY', 'ADULT', 'MATURE'}
    }

    'race': {
        default: -> PPM2.RACE_EARTH
        getFunc: 'Race'
        enum: [arg for arg in *PPM2.RACE_ENUMS]
    }

    'wings_type': {
        default: -> 0
        getFunc: 'WingsType'
        enum: [arg for arg in *PPM2.AvaliablePonyWings]
    }

    'gender': {
        default: -> PPM2.GENDER_FEMALE
        getFunc: 'Gender'
        enum: [arg for arg in *PPM2.AGE_ENUMS]
    }

    'weight': {
        default: -> 1
        getFunc: 'Weight'
        min: PPM2.MIN_WEIGHT
        max: PPM2.MAX_WEIGHT
        type: 'FLOAT'
    }

    'ponysize': {
        default: -> 1
        getFunc: 'PonySize'
        min: PPM2.MIN_SCALE
        max: PPM2.MAX_SCALE
        type: 'FLOAT'
    }

    'necksize': {
        default: -> 1
        getFunc: 'NeckSize'
        min: PPM2.MIN_NECK
        max: PPM2.MAX_NECK
        type: 'FLOAT'
    }

    'legssize': {
        default: -> 1
        getFunc: 'LegsSize'
        min: PPM2.MIN_LEGS
        max: PPM2.MAX_LEGS
        type: 'FLOAT'
    }

    'male_buff': {
        default: -> PPM2.DEFAULT_MALE_BUFF
        getFunc: 'MaleBuff'
        min: PPM2.MIN_MALE_BUFF
        max: PPM2.MAX_MALE_BUFF
        type: 'FLOAT'
    }

    'eyelash': {
        default: -> 0
        getFunc: 'EyelashType'
        enum: [arg for arg in *PPM2.EyelashTypes]
    }

    'tail': {
        default: -> 0
        getFunc: 'TailType'
        enum: [arg for arg in *PPM2.AvaliableTails]
    }

    'tail_new': {
        default: -> 0
        getFunc: 'TailTypeNew'
        enum: [arg for arg in *PPM2.AvaliableTailsNew]
    }

    'mane': {
        default: -> 0
        getFunc: 'ManeType'
        enum: [arg for arg in *PPM2.AvaliableUpperManes]
    }

    'mane_new': {
        default: -> 0
        getFunc: 'ManeTypeNew'
        enum: [arg for arg in *PPM2.AvaliableUpperManesNew]
    }

    'manelower': {
        default: -> 0
        getFunc: 'ManeTypeLower'
        enum: [arg for arg in *PPM2.AvaliableLowerManes]
    }

    'manelower_new': {
        default: -> 0
        getFunc: 'ManeTypeLowerNew'
        enum: [arg for arg in *PPM2.AvaliableLowerManesNew]
    }

    'socks_texture': {
        default: -> 0
        getFunc: 'SocksTexture'
        enum: [arg for arg in *PPM2.SocksTypes]
    }

    'socks_texture_url': {
        default: -> ''
        getFunc: 'SocksTextureURL'
        type: 'URL'
    }

    'tailsize': {
        default: -> 1
        getFunc: 'TailSize'
        min: PPM2.MIN_TAIL_SIZE
        max: PPM2.MAX_TAIL_SIZE
        type: 'FLOAT'
    }

    'cmark': {
        default: -> true
        getFunc: 'CMark'
        type: 'BOOLEAN'
    }

    'cmark_size': {
        default: -> 1
        getFunc: 'CMarkSize'
        min: 0
        max: 1
        type: 'FLOAT'
    }

    'cmark_color': {
        default: -> Color(255, 255, 255)
        getFunc: 'CMarkColor'
        type: 'COLOR'
    }

    'fangs': {
        default: -> false
        getFunc: 'Fangs'
        type: 'BOOLEAN'
    }

    'bat_pony_ears': {
        default: -> false
        getFunc: 'BatPonyEars'
        type: 'BOOLEAN'
    }

    'claw_teeth': {
        default: -> false
        getFunc: 'ClawTeeth'
        type: 'BOOLEAN'
    }

    'cmark_type': {
        default: -> 4
        getFunc: 'CMarkType'
        enum: [arg for arg in *PPM2.DefaultCutiemarks]
    }

    'cmark_url': {
        default: -> ''
        getFunc: 'CMarkURL'
        type: 'URL'
    }

    'body': {
        default: -> Color(255, 255, 255)
        getFunc: 'BodyColor'
        type: 'COLOR'
    }

    'horn_color': {
        default: -> Color(255, 255, 255)
        getFunc: 'HornColor'
        type: 'COLOR'
    }

    'wings_color': {
        default: -> Color(255, 255, 255)
        getFunc: 'WingsColor'
        type: 'COLOR'
    }

    'separate_wings': {
        default: -> false
        getFunc: 'SeparateWings'
        type: 'BOOLEAN'
    }

    'separate_horn': {
        default: -> false
        getFunc: 'SeparateHorn'
        type: 'BOOLEAN'
    }

    'use_horn_detail': {
        default: -> false
        getFunc: 'UseHornDetail'
        type: 'BOOLEAN'
    }

    'horn_glow': {
        default: -> false
        getFunc: 'HornGlow'
        type: 'BOOLEAN'
    }

    'horn_glow_strength': {
        default: -> 1
        getFunc: 'HornGlowSrength'
        min: 0
        max: 1
        type: 'FLOAT'
    }

    'horn_detail_color': {
        default: -> Color(255, 255, 255)
        getFunc: 'HornDetailColor'
        type: 'COLOR'
    }

    'separate_eyes': {
        default: -> false
        getFunc: 'SeparateEyes'
        type: 'BOOLEAN'
    }

    'separate_mane': {
        default: -> false
        getFunc: 'SeparateMane'
        type: 'BOOLEAN'
    }

    'socks': {
        default: -> false
        getFunc: 'Socks'
        type: 'BOOLEAN'
    }

    'new_male_muzzle': {
        default: -> true
        getFunc: 'NewMuzzle'
        type: 'BOOLEAN'
    }

    'noflex': {
        default: -> false
        getFunc: 'NoFlex'
        type: 'BOOLEAN'
    }

    'socks_model': {
        default: -> false
        getFunc: 'SocksAsModel'
        type: 'BOOLEAN'
    }

    'socks_model_color': {
        default: -> Color(255, 255, 255)
        getFunc: 'SocksColor'
        type: 'COLOR'
    }

    'suit': {
        default: -> 0
        getFunc: 'Bodysuit'
        enum: [arg for arg in *PPM2.AvaliablePonySuits]
    }

    'left_wing_size': {
        default: -> 1
        getFunc: 'LWingSize'
        min: PPM2.MIN_WING
        max: PPM2.MAX_WING
        type: 'FLOAT'
    }

    'left_wing_x': {
        default: -> 0
        getFunc: 'LWingX'
        min: PPM2.MIN_WINGX
        max: PPM2.MAX_WINGX
        type: 'FLOAT'
    }

    'left_wing_y': {
        default: -> 0
        getFunc: 'LWingY'
        min: PPM2.MIN_WINGY
        max: PPM2.MAX_WINGY
        type: 'FLOAT'
    }

    'left_wing_z': {
        default: -> 0
        getFunc: 'LWingZ'
        min: PPM2.MIN_WINGZ
        max: PPM2.MAX_WINGZ
        type: 'FLOAT'
    }

    'right_wing_size': {
        default: -> 1
        getFunc: 'RWingSize'
        min: PPM2.MIN_WING
        max: PPM2.MAX_WING
        type: 'FLOAT'
    }

    'right_wing_x': {
        default: -> 0
        getFunc: 'RWingX'
        min: PPM2.MIN_WINGX
        max: PPM2.MAX_WINGX
        type: 'FLOAT'
    }

    'right_wing_y': {
        default: -> 0
        getFunc: 'RWingY'
        min: PPM2.MIN_WINGY
        max: PPM2.MAX_WINGY
        type: 'FLOAT'
    }

    'right_wing_z': {
        default: -> 0
        getFunc: 'RWingZ'
        min: PPM2.MIN_WINGZ
        max: PPM2.MAX_WINGZ
        type: 'FLOAT'
    }

    'teeth_color': {
        default: -> Color(255, 255, 255)
        getFunc: 'TeethColor'
        type: 'COLOR'
    }

    'mouth_color': {
        default: -> Color(219, 65, 155)
        getFunc: 'MouthColor'
        type: 'COLOR'
    }

    'tongue_color': {
        default: -> Color(235, 131, 59)
        getFunc: 'TongueColor'
        type: 'COLOR'
    }

    'bat_wing_color': {
        default: -> Color(255, 255, 255)
        getFunc: 'BatWingColor'
        type: 'COLOR'
    }

    'bat_wing_skin_color': {
        default: -> Color(255, 255, 255)
        getFunc: 'BatWingSkinColor'
        type: 'COLOR'
    }

    'separate_horn_phong': {
        default: -> false
        getFunc: 'SeparateHornPhong'
        type: 'BOOLEAN'
    }

    'separate_wings_phong': {
        default: -> false
        getFunc: 'SeparateWingsPhong'
        type: 'BOOLEAN'
    }

    'separate_mane_phong': {
        default: -> false
        getFunc: 'SeparateManePhong'
        type: 'BOOLEAN'
    }

    'separate_tail_phong': {
        default: -> false
        getFunc: 'SeparateTailPhong'
        type: 'BOOLEAN'
    }

    'alternative_fangs': {
        default: -> false
        getFunc: 'AlternativeFangs'
        type: 'BOOLEAN'
    }

    'hoof_fluffers': {
        default: -> false
        getFunc: 'HoofFluffers'
        type: 'BOOLEAN'
    }

    'hoof_fluffers_strength': {
        default: -> 1
        getFunc: 'HoofFluffersStrength'
        min: 0
        max: 1
        type: 'FLOAT'
    }

    'ears_size': {
        default: -> 1
        getFunc: 'EarsSize'
        min: 0.1
        max: 2
        type: 'FLOAT'
    }

    'bat_pony_ears_strength': {
        default: -> 1
        getFunc: 'BatPonyEarsStrength'
        min: 0
        max: 1
        type: 'FLOAT'
    }

    'fangs_strength': {
        default: -> 1
        getFunc: 'FangsStrength'
        min: 0
        max: 1
        type: 'FLOAT'
    }

    'clawteeth_strength': {
        default: -> 1
        getFunc: 'ClawTeethStrength'
        min: 0
        max: 1
        type: 'FLOAT'
    }
}

for {internal, publicName} in *{{'_left', 'Left'}, {'_right', 'Right'}, {'', ''}}
    PPM2.PonyDataRegistry["eye_url#{internal}"] = {
        default: -> ''
        getFunc: "EyeURL#{publicName}"
        type: 'URL'
    }

    PPM2.PonyDataRegistry["eye_bg#{internal}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "EyeBackground#{publicName}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["eye_hole#{internal}"] = {
        default: -> Color(0, 0, 0)
        getFunc: "EyeHole#{publicName}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["eye_iris1#{internal}"] = {
        default: -> Color(200, 200, 200)
        getFunc: "EyeIrisTop#{publicName}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["eye_iris2#{internal}"] = {
        default: -> Color(200, 200, 200)
        getFunc: "EyeIrisBottom#{publicName}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["eye_irisline1#{internal}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "EyeIrisLine1#{publicName}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["eye_irisline2#{internal}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "EyeIrisLine2#{publicName}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["eye_reflection#{internal}"] = {
        default: -> Color(255, 255, 255, 127)
        getFunc: "EyeReflection#{publicName}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["eye_effect#{internal}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "EyeEffect#{publicName}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["eye_lines#{internal}"] = {
        default: -> true
        getFunc: "EyeLines#{publicName}"
        type: 'BOOLEAN'
    }

    PPM2.PonyDataRegistry["eye_iris_size#{internal}"] = {
        default: -> 1
        getFunc: "IrisSize#{publicName}"
        min: PPM2.MIN_IRIS
        max: PPM2.MAX_IRIS
        type: 'FLOAT'
    }

    PPM2.PonyDataRegistry["eye_derp#{internal}"] = {
        default: -> false
        getFunc: "DerpEyes#{publicName}"
        type: 'BOOLEAN'
    }

    PPM2.PonyDataRegistry["eye_use_refract#{internal}"] = {
        default: -> false
        getFunc: "EyeRefract#{publicName}"
        type: 'BOOLEAN'
    }

    PPM2.PonyDataRegistry["eye_cornera#{internal}"] = {
        default: -> false
        getFunc: "EyeCornerA#{publicName}"
        type: 'BOOLEAN'
    }

    PPM2.PonyDataRegistry["eye_derp_strength#{internal}"] = {
        default: -> 1
        getFunc: "DerpEyesStrength#{publicName}"
        min: PPM2.MIN_DERP_STRENGTH
        max: PPM2.MAX_DERP_STRENGTH
        type: 'FLOAT'
    }

    PPM2.PonyDataRegistry["eye_type#{internal}"] = {
        default: -> 0
        getFunc: "EyeType#{publicName}"
        enum: [arg for arg in *PPM2.AvaliableEyeTypes]
    }

    PPM2.PonyDataRegistry["hole_width#{internal}"] = {
        default: -> 1
        getFunc: "HoleWidth#{publicName}"
        min: PPM2.MIN_PUPIL_SIZE
        max: PPM2.MAX_PUPIL_SIZE
        type: 'FLOAT'
    }

    PPM2.PonyDataRegistry["hole_height#{internal}"] = {
        default: -> 1
        getFunc: "HoleHeight#{publicName}"
        min: PPM2.MIN_PUPIL_SIZE
        max: PPM2.MAX_PUPIL_SIZE
        type: 'FLOAT'
    }

    PPM2.PonyDataRegistry["iris_width#{internal}"] = {
        default: -> 1
        getFunc: "IrisWidth#{publicName}"
        min: PPM2.MIN_PUPIL_SIZE
        max: PPM2.MAX_PUPIL_SIZE
        type: 'FLOAT'
    }

    PPM2.PonyDataRegistry["iris_height#{internal}"] = {
        default: -> 1
        getFunc: "IrisHeight#{publicName}"
        min: PPM2.MIN_PUPIL_SIZE
        max: PPM2.MAX_PUPIL_SIZE
        type: 'FLOAT'
    }

    PPM2.PonyDataRegistry["hole_shiftx#{internal}"] = {
        default: -> 0
        getFunc: "HoleShiftX#{publicName}"
        min: PPM2.MIN_HOLE_SHIFT
        max: PPM2.MAX_HOLE_SHIFT
        type: 'FLOAT'
    }

    PPM2.PonyDataRegistry["hole_shifty#{internal}"] = {
        default: -> 0
        getFunc: "HoleShiftY#{publicName}"
        min: PPM2.MIN_HOLE_SHIFT
        max: PPM2.MAX_HOLE_SHIFT
        type: 'FLOAT'
    }

    PPM2.PonyDataRegistry["eye_hole_size#{internal}"] = {
        default: -> .8
        getFunc: "HoleSize#{publicName}"
        min: PPM2.MIN_HOLE
        max: PPM2.MAX_HOLE
        type: 'FLOAT'
    }

    PPM2.PonyDataRegistry["eye_rotation#{internal}"] = {
        default: -> 0
        getFunc: "EyeRotation#{publicName}"
        min: PPM2.MIN_EYE_ROTATION
        max: PPM2.MAX_EYE_ROTATION
        type: 'INT'
    }

for i = 1, 3
    PPM2.PonyDataRegistry["horn_url_#{i}"] = {
        default: -> ''
        getFunc: "HornURL#{i}"
        type: 'URL'
    }

    PPM2.PonyDataRegistry["bat_wing_url_#{i}"] = {
        default: -> ''
        getFunc: "BatWingURL#{i}"
        type: 'URL'
    }

    PPM2.PonyDataRegistry["bat_wing_skin_url_#{i}"] = {
        default: -> ''
        getFunc: "BatWingSkinURL#{i}"
        type: 'URL'
    }

    PPM2.PonyDataRegistry["wings_url_#{i}"] = {
        default: -> ''
        getFunc: "WingsURL#{i}"
        type: 'URL'
    }

    PPM2.PonyDataRegistry["horn_url_color_#{i}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "HornURLColor#{i}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["bat_wing_url_color_#{i}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "BatWingURLColor#{i}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["bat_wing_skin_url_color_#{i}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "BatWingSkinURLColor#{i}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["wings_url_color_#{i}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "WingsURLColor#{i}"
        type: 'COLOR'
    }

for i = 1, 6
    PPM2.PonyDataRegistry["socks_detail_color_#{i}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "SocksDetailColor#{i}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["mane_color_#{i}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "ManeColor#{i}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["mane_detail_color_#{i}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "ManeDetailColor#{i}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["mane_url_color_#{i}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "ManeURLColor#{i}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["mane_url_#{i}"] = {
        default: -> ''
        getFunc: "ManeURL#{i}"
        type: 'URL'
    }

    PPM2.PonyDataRegistry["tail_detail_color_#{i}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "TailDetailColor#{i}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["tail_url_color_#{i}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "TailURLColor#{i}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["tail_url_#{i}"] = {
        default: -> ''
        getFunc: "TailURL#{i}"
        type: 'URL'
    }

    PPM2.PonyDataRegistry["tail_color_#{i}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "TailColor#{i}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["lower_mane_color_#{i}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "LowerManeColor#{i}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["lower_mane_url_color_#{i}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "LowerManeURLColor#{i}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["lower_mane_url_#{i}"] = {
        default: -> ''
        getFunc: "LowerManeURL#{i}"
        type: 'URL'
    }

    PPM2.PonyDataRegistry["upper_mane_color_#{i}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "UpperManeColor#{i}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["upper_mane_url_color_#{i}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "UpperManeURLColor#{i}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["upper_mane_url_#{i}"] = {
        default: -> ''
        getFunc: "UpperManeURL#{i}"
        type: 'URL'
    }

    PPM2.PonyDataRegistry["lower_mane_detail_color_#{i}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "LowerManeDetailColor#{i}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["upper_mane_detail_color_#{i}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "UpperManeDetailColor#{i}"
        type: 'COLOR'
    }

for i = 1, PPM2.MAX_BODY_DETAILS
    PPM2.PonyDataRegistry["body_detail_color_#{i}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "BodyDetailColor#{i}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["body_detail_#{i}"] = {
        default: -> 0
        getFunc: "BodyDetail#{i}"
        enum: [arg for arg in *PPM2.BodyDetailsEnum]
    }

    PPM2.PonyDataRegistry["body_detail_url_#{i}"] = {
        default: -> ''
        getFunc: "BodyDetailURL#{i}"
        type: 'URL'
    }

    PPM2.PonyDataRegistry["body_detail_url_color_#{i}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "BodyDetailURLColor#{i}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["body_detail_glow_#{i}"] = {
        default: -> false
        getFunc: "BodyDetailGlow#{i}"
        type: 'BOOLEAN'
    }

    PPM2.PonyDataRegistry["body_detail_glow_strength_#{i}"] = {
        default: -> 1
        getFunc: "BodyDetailGlowStrength#{i}"
        type: 'FLOAT'
        min: 0
        max: 1
    }

for i = 1, PPM2.MAX_TATTOOS
    PPM2.PonyDataRegistry["tattoo_type_#{i}"] = {
        default: -> 0
        getFunc: "TattooType#{i}"
        enum: [arg for arg in *PPM2.TATTOOS_REGISTRY]
    }

    PPM2.PonyDataRegistry["tattoo_posx_#{i}"] = {
        default: -> 0
        getFunc: "TattooPosX#{i}"
        min: -100
        max: 100
        type: 'FLOAT'
    }

    PPM2.PonyDataRegistry["tattoo_posy_#{i}"] = {
        default: -> 0
        getFunc: "TattooPosY#{i}"
        fix: (arg = 0) -> math.Clamp(tonumber(arg) or 0, -100, 100)
        min: -100
        max: 100
        type: 'FLOAT'
    }

    PPM2.PonyDataRegistry["tattoo_rotate_#{i}"] = {
        default: -> 0
        getFunc: "TattooRotate#{i}"
        min: -180
        max: 180
        type: 'INT'
    }

    PPM2.PonyDataRegistry["tattoo_scalex_#{i}"] = {
        default: -> 1
        getFunc: "TattooScaleX#{i}"
        min: 0
        max: 10
        type: 'FLOAT'
    }

    PPM2.PonyDataRegistry["tattoo_glow_strength_#{i}"] = {
        default: -> 1
        getFunc: "TattooGlowStrength#{i}"
        min: 0
        max: 1
        type: 'FLOAT'
    }

    PPM2.PonyDataRegistry["tattoo_scaley_#{i}"] = {
        default: -> 1
        getFunc: "TattooScaleY#{i}"
        min: 0
        max: 10
        type: 'FLOAT'
    }

    PPM2.PonyDataRegistry["tattoo_glow_#{i}"] = {
        default: -> false
        getFunc: "TattooGlow#{i}"
        type: 'BOOLEAN'
    }

    PPM2.PonyDataRegistry["tattoo_over_detail_#{i}"] = {
        default: -> false
        getFunc: "TattooOverDetail#{i}"
        type: 'BOOLEAN'
    }

    PPM2.PonyDataRegistry["tattoo_color_#{i}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "TattooColor#{i}"
        type: 'COLOR'
    }

for ttype in *{'Body', 'Horn', 'Wings', 'BatWingsSkin', 'Socks', 'Mane', 'Tail', 'UpperMane', 'LowerMane'}
    PPM2.PonyDataRegistry[ttype\lower() .. '_phong_exponent'] = {
        default: -> 3
        getFunc: ttype .. 'PhongExponent'
        min: 0.04
        max: 10
        type: 'FLOAT'
    }

    PPM2.PonyDataRegistry[ttype\lower() .. '_phong_boost'] = {
        default: -> 0.09
        getFunc: ttype .. 'PhongBoost'
        min: 0.01
        max: 1
        type: 'FLOAT'
    }

    PPM2.PonyDataRegistry[ttype\lower() .. '_phong_front'] = {
        default: -> 1
        getFunc: ttype .. 'PhongFront'
        min: 0
        max: 20
        type: 'FLOAT'
    }

    PPM2.PonyDataRegistry[ttype\lower() .. '_phong_middle'] = {
        default: -> 5
        getFunc: ttype .. 'PhongMiddle'
        min: 0
        max: 20
        type: 'FLOAT'
    }

    PPM2.PonyDataRegistry[ttype\lower() .. '_phong_sliding'] = {
        default: -> 10
        getFunc: ttype .. 'PhongSliding'
        min: 0
        max: 20
        type: 'FLOAT'
    }

    PPM2.PonyDataRegistry[ttype\lower() .. '_phong_tint'] = {
        default: -> Color(255, 200, 200)
        getFunc: ttype .. 'PhongTint'
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry[ttype\lower() .. '_lightwarp_texture'] = {
        default: -> 0
        getFunc: ttype .. 'Lightwarp'
        enum: [arg for arg in *PPM2.AvaliableLightwarps]
    }

    PPM2.PonyDataRegistry[ttype\lower() .. '_lightwarp_texture_url'] = {
        default: -> ''
        getFunc: ttype .. 'LightwarpURL'
        type: 'URL'
    }

for {:flex, :active} in *PPM2.PonyFlexController.FLEX_LIST
    continue if not active
    PPM2.PonyDataRegistry["flex_disable_#{flex\lower()}"] = {
        default: -> false
        getFunc: "DisableFlex#{flex}"
        type: 'BOOLEAN'
    }

for key, value in pairs PPM2.PonyDataRegistry
    if value.enum
        value.min = 0
        value.max = #value.enum - 1
        value.type = 'INT'

    switch value.type
        when 'INT'
            error("Variable #{key} has invalid minimal value (#{type(value.min)})") if type(value.min) ~= 'number'
            error("Variable #{max} has invalid maximal value (#{type(value.max)})") if type(value.max) ~= 'number'
            value.fix = INT_FIXER(value.default, value.min, value.max)
            if value.min >= 0
                selectBits = 16
                while 2 ^ (selectBits - 1) > value.max
                    selectBits -= 1
                value.read = rUInt(selectBits, value.min, value.max)
                value.write = wUInt(value.default(), selectBits)
            else
                delta = math.max(value.max, -value.min)
                selectBits = 16
                while 2 ^ (selectBits - 1) > delta
                    selectBits -= 1
                value.read = rInt(selectBits, value.min, value.max)
                value.write = wInt(value.default(), selectBits)
        when 'FLOAT'
            error("Variable #{key} has invalid minimal value (#{type(value.min)})") if type(value.min) ~= 'number'
            error("Variable #{max} has invalid maximal value (#{type(value.max)})") if type(value.max) ~= 'number'
            value.fix = FLOAT_FIXER(value.default, value.min, value.max)
            value.read = rFloat(value.min, value.max)
            value.write = (arg = value.default()) -> wFloat(arg)
        when 'URL'
            value.fix = URL_FIXER
            value.read = rURL
            value.write = wString
        when 'BOOLEAN'
            value.fix = (arg = value.default()) -> tobool(arg)
            value.read = rBool
            value.write = wBool
        when 'COLOR'
            {:r, :g, :b, :a} = value.default()
            value.fix = COLOR_FIXER(r, g, b, a)
            value.read = rColor
            value.write = wColor
        else
            error("Unknown variable type - #{value.type} for #{key}")

    error("Data has no fix function: #{key}") if not value.fix

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

wUInt = (def = 0, size = 8) ->
    return (arg = def) -> net.WriteUInt(arg, size)

wInt = (def = 0, size = 8) ->
    return (arg = def) -> net.WriteInt(arg, size)

rUInt = (size = 8, min = 0, max = 255) ->
    return -> math.Clamp(net.ReadUInt(size), min, max)

rInt = (size = 8, min = -128, max = 127) ->
    return -> math.Clamp(net.ReadInt(size), min, max)

rFloat = (min = 0, max = 255) ->
    return -> math.Clamp(net.ReadFloat(), min, max)

wFloat = net.WriteFloat
rSEnt = net.ReadStrongEntity
wSEnt = net.WriteStrongEntity
rBool = net.ReadBool
wBool = net.WriteBool
rColor = net.ReadColor
wColor = net.WriteColor
rString = net.ReadString
wString = net.WriteString

COLOR_FIXER = (r = 255, g = 255, b = 255, a = 255) ->
    func = (arg = Color(r, g, b, a)) ->
        if type(arg) ~= 'table'
            return Color(255, 255, 255)
        else
            {:r, :g, :b, :a} = arg
            if r and g and b and a
                return Color(r, g, b, a)
            else
                return Color(255, 255, 255)
    return func

URL_FIXER = (arg = '') ->
    arg = tostring(arg)
    if arg\find('^https?://')
        return arg
    else
        return ''

rURL = -> URL_FIXER(rString())

FLOAT_FIXER = (def = 1, min = 0, max = 1) ->
    defFunc = -> def if type(def) ~= 'function'
    defFunc = def if type(def) == 'function'
    return (arg = defFunc()) -> math.Clamp(tonumber(arg) or defFunc(), min, max)

INT_FIXER = (def = 1, min = 0, max = 1) ->
    defFunc = -> def if type(def) ~= 'function'
    defFunc = def if type(def) == 'function'
    return (arg = defFunc()) -> math.floor(math.Clamp(tonumber(arg) or defFunc(), min, max))

PPM2.PonyDataRegistry = {
    'age': {
        default: -> PPM2.AGE_ADULT
        getFunc: 'Age'
        enum: {'FILLY', 'ADULT', 'MATURE'}
    }

    'race': {
        default: -> PPM2.RACE_EARTH
        getFunc: 'Race'
        enum: [arg for arg in *PPM2.RACE_ENUMS]
    }

    'wings_type': {
        default: -> 0
        getFunc: 'WingsType'
        enum: [arg for arg in *PPM2.AvaliablePonyWings]
    }

    'gender': {
        default: -> PPM2.GENDER_FEMALE
        getFunc: 'Gender'
        enum: [arg for arg in *PPM2.AGE_ENUMS]
    }

    'weight': {
        default: -> 1
        getFunc: 'Weight'
        min: PPM2.MIN_WEIGHT
        max: PPM2.MAX_WEIGHT
        type: 'FLOAT'
    }

    'ponysize': {
        default: -> 1
        getFunc: 'PonySize'
        min: PPM2.MIN_SCALE
        max: PPM2.MAX_SCALE
        type: 'FLOAT'
    }

    'necksize': {
        default: -> 1
        getFunc: 'NeckSize'
        min: PPM2.MIN_NECK
        max: PPM2.MAX_NECK
        type: 'FLOAT'
    }

    'legssize': {
        default: -> 1
        getFunc: 'LegsSize'
        min: PPM2.MIN_LEGS
        max: PPM2.MAX_LEGS
        type: 'FLOAT'
    }

    'male_buff': {
        default: -> PPM2.DEFAULT_MALE_BUFF
        getFunc: 'MaleBuff'
        min: PPM2.MIN_MALE_BUFF
        max: PPM2.MAX_MALE_BUFF
        type: 'FLOAT'
    }

    'eyelash': {
        default: -> 0
        getFunc: 'EyelashType'
        enum: [arg for arg in *PPM2.EyelashTypes]
    }

    'tail': {
        default: -> 0
        getFunc: 'TailType'
        enum: [arg for arg in *PPM2.AvaliableTails]
    }

    'tail_new': {
        default: -> 0
        getFunc: 'TailTypeNew'
        enum: [arg for arg in *PPM2.AvaliableTailsNew]
    }

    'mane': {
        default: -> 0
        getFunc: 'ManeType'
        enum: [arg for arg in *PPM2.AvaliableUpperManes]
    }

    'mane_new': {
        default: -> 0
        getFunc: 'ManeTypeNew'
        enum: [arg for arg in *PPM2.AvaliableUpperManesNew]
    }

    'manelower': {
        default: -> 0
        getFunc: 'ManeTypeLower'
        enum: [arg for arg in *PPM2.AvaliableLowerManes]
    }

    'manelower_new': {
        default: -> 0
        getFunc: 'ManeTypeLowerNew'
        enum: [arg for arg in *PPM2.AvaliableLowerManesNew]
    }

    'socks_texture': {
        default: -> 0
        getFunc: 'SocksTexture'
        enum: [arg for arg in *PPM2.SocksTypes]
    }

    'socks_texture_url': {
        default: -> ''
        getFunc: 'SocksTextureURL'
        type: 'URL'
    }

    'tailsize': {
        default: -> 1
        getFunc: 'TailSize'
        min: PPM2.MIN_TAIL_SIZE
        max: PPM2.MAX_TAIL_SIZE
        type: 'FLOAT'
    }

    'cmark': {
        default: -> true
        getFunc: 'CMark'
        type: 'BOOLEAN'
    }

    'cmark_size': {
        default: -> 1
        getFunc: 'CMarkSize'
        min: 0
        max: 1
        type: 'FLOAT'
    }

    'cmark_color': {
        default: -> Color(255, 255, 255)
        getFunc: 'CMarkColor'
        type: 'COLOR'
    }

    'fangs': {
        default: -> false
        getFunc: 'Fangs'
        type: 'BOOLEAN'
    }

    'bat_pony_ears': {
        default: -> false
        getFunc: 'BatPonyEars'
        type: 'BOOLEAN'
    }

    'claw_teeth': {
        default: -> false
        getFunc: 'ClawTeeth'
        type: 'BOOLEAN'
    }

    'cmark_type': {
        default: -> 4
        getFunc: 'CMarkType'
        enum: [arg for arg in *PPM2.DefaultCutiemarks]
    }

    'cmark_url': {
        default: -> ''
        getFunc: 'CMarkURL'
        type: 'URL'
    }

    'body': {
        default: -> Color(255, 255, 255)
        getFunc: 'BodyColor'
        type: 'COLOR'
    }

    'horn_color': {
        default: -> Color(255, 255, 255)
        getFunc: 'HornColor'
        type: 'COLOR'
    }

    'wings_color': {
        default: -> Color(255, 255, 255)
        getFunc: 'WingsColor'
        type: 'COLOR'
    }

    'separate_wings': {
        default: -> false
        getFunc: 'SeparateWings'
        type: 'BOOLEAN'
    }

    'separate_horn': {
        default: -> false
        getFunc: 'SeparateHorn'
        type: 'BOOLEAN'
    }

    'use_horn_detail': {
        default: -> false
        getFunc: 'UseHornDetail'
        type: 'BOOLEAN'
    }

    'horn_glow': {
        default: -> false
        getFunc: 'HornGlow'
        type: 'BOOLEAN'
    }

    'horn_glow_strength': {
        default: -> 1
        getFunc: 'HornGlowSrength'
        min: 0
        max: 1
        type: 'FLOAT'
    }

    'horn_detail_color': {
        default: -> Color(255, 255, 255)
        getFunc: 'HornDetailColor'
        type: 'COLOR'
    }

    'separate_eyes': {
        default: -> false
        getFunc: 'SeparateEyes'
        type: 'BOOLEAN'
    }

    'separate_mane': {
        default: -> false
        getFunc: 'SeparateMane'
        type: 'BOOLEAN'
    }

    'socks': {
        default: -> false
        getFunc: 'Socks'
        type: 'BOOLEAN'
    }

    'new_male_muzzle': {
        default: -> true
        getFunc: 'NewMuzzle'
        type: 'BOOLEAN'
    }

    'noflex': {
        default: -> false
        getFunc: 'NoFlex'
        type: 'BOOLEAN'
    }

    'socks_model': {
        default: -> false
        getFunc: 'SocksAsModel'
        type: 'BOOLEAN'
    }

    'socks_model_color': {
        default: -> Color(255, 255, 255)
        getFunc: 'SocksColor'
        type: 'COLOR'
    }

    'suit': {
        default: -> 0
        getFunc: 'Bodysuit'
        enum: [arg for arg in *PPM2.AvaliablePonySuits]
    }

    'left_wing_size': {
        default: -> 1
        getFunc: 'LWingSize'
        min: PPM2.MIN_WING
        max: PPM2.MAX_WING
        type: 'FLOAT'
    }

    'left_wing_x': {
        default: -> 0
        getFunc: 'LWingX'
        min: PPM2.MIN_WINGX
        max: PPM2.MAX_WINGX
        type: 'FLOAT'
    }

    'left_wing_y': {
        default: -> 0
        getFunc: 'LWingY'
        min: PPM2.MIN_WINGY
        max: PPM2.MAX_WINGY
        type: 'FLOAT'
    }

    'left_wing_z': {
        default: -> 0
        getFunc: 'LWingZ'
        min: PPM2.MIN_WINGZ
        max: PPM2.MAX_WINGZ
        type: 'FLOAT'
    }

    'right_wing_size': {
        default: -> 1
        getFunc: 'RWingSize'
        min: PPM2.MIN_WING
        max: PPM2.MAX_WING
        type: 'FLOAT'
    }

    'right_wing_x': {
        default: -> 0
        getFunc: 'RWingX'
        min: PPM2.MIN_WINGX
        max: PPM2.MAX_WINGX
        type: 'FLOAT'
    }

    'right_wing_y': {
        default: -> 0
        getFunc: 'RWingY'
        min: PPM2.MIN_WINGY
        max: PPM2.MAX_WINGY
        type: 'FLOAT'
    }

    'right_wing_z': {
        default: -> 0
        getFunc: 'RWingZ'
        min: PPM2.MIN_WINGZ
        max: PPM2.MAX_WINGZ
        type: 'FLOAT'
    }

    'teeth_color': {
        default: -> Color(255, 255, 255)
        getFunc: 'TeethColor'
        type: 'COLOR'
    }

    'mouth_color': {
        default: -> Color(219, 65, 155)
        getFunc: 'MouthColor'
        type: 'COLOR'
    }

    'tongue_color': {
        default: -> Color(235, 131, 59)
        getFunc: 'TongueColor'
        type: 'COLOR'
    }

    'bat_wing_color': {
        default: -> Color(255, 255, 255)
        getFunc: 'BatWingColor'
        type: 'COLOR'
    }

    'bat_wing_skin_color': {
        default: -> Color(255, 255, 255)
        getFunc: 'BatWingSkinColor'
        type: 'COLOR'
    }

    'separate_horn_phong': {
        default: -> false
        getFunc: 'SeparateHornPhong'
        type: 'BOOLEAN'
    }

    'separate_wings_phong': {
        default: -> false
        getFunc: 'SeparateWingsPhong'
        type: 'BOOLEAN'
    }

    'separate_mane_phong': {
        default: -> false
        getFunc: 'SeparateManePhong'
        type: 'BOOLEAN'
    }

    'separate_tail_phong': {
        default: -> false
        getFunc: 'SeparateTailPhong'
        type: 'BOOLEAN'
    }

    'alternative_fangs': {
        default: -> false
        getFunc: 'AlternativeFangs'
        type: 'BOOLEAN'
    }

    'hoof_fluffers': {
        default: -> false
        getFunc: 'HoofFluffers'
        type: 'BOOLEAN'
    }

    'hoof_fluffers_strength': {
        default: -> 1
        getFunc: 'HoofFluffersStrength'
        min: 0
        max: 1
        type: 'FLOAT'
    }

    'ears_size': {
        default: -> 1
        getFunc: 'EarsSize'
        min: 0.1
        max: 2
        type: 'FLOAT'
    }

    'bat_pony_ears_strength': {
        default: -> 1
        getFunc: 'BatPonyEarsStrength'
        min: 0
        max: 1
        type: 'FLOAT'
    }

    'fangs_strength': {
        default: -> 1
        getFunc: 'FangsStrength'
        min: 0
        max: 1
        type: 'FLOAT'
    }

    'clawteeth_strength': {
        default: -> 1
        getFunc: 'ClawTeethStrength'
        min: 0
        max: 1
        type: 'FLOAT'
    }
}

for {internal, publicName} in *{{'_left', 'Left'}, {'_right', 'Right'}, {'', ''}}
    PPM2.PonyDataRegistry["eye_url#{internal}"] = {
        default: -> ''
        getFunc: "EyeURL#{publicName}"
        type: 'URL'
    }

    PPM2.PonyDataRegistry["eye_bg#{internal}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "EyeBackground#{publicName}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["eye_hole#{internal}"] = {
        default: -> Color(0, 0, 0)
        getFunc: "EyeHole#{publicName}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["eye_iris1#{internal}"] = {
        default: -> Color(200, 200, 200)
        getFunc: "EyeIrisTop#{publicName}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["eye_iris2#{internal}"] = {
        default: -> Color(200, 200, 200)
        getFunc: "EyeIrisBottom#{publicName}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["eye_irisline1#{internal}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "EyeIrisLine1#{publicName}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["eye_irisline2#{internal}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "EyeIrisLine2#{publicName}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["eye_reflection#{internal}"] = {
        default: -> Color(255, 255, 255, 127)
        getFunc: "EyeReflection#{publicName}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["eye_effect#{internal}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "EyeEffect#{publicName}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["eye_lines#{internal}"] = {
        default: -> true
        getFunc: "EyeLines#{publicName}"
        type: 'BOOLEAN'
    }

    PPM2.PonyDataRegistry["eye_iris_size#{internal}"] = {
        default: -> 1
        getFunc: "IrisSize#{publicName}"
        min: PPM2.MIN_IRIS
        max: PPM2.MAX_IRIS
        type: 'FLOAT'
    }

    PPM2.PonyDataRegistry["eye_derp#{internal}"] = {
        default: -> false
        getFunc: "DerpEyes#{publicName}"
        type: 'BOOLEAN'
    }

    PPM2.PonyDataRegistry["eye_use_refract#{internal}"] = {
        default: -> true
        getFunc: "EyeRefract#{publicName}"
        type: 'BOOLEAN'
    }

    PPM2.PonyDataRegistry["eye_cornera#{internal}"] = {
        default: -> false
        getFunc: "EyeCornerA#{publicName}"
        type: 'BOOLEAN'
    }

    PPM2.PonyDataRegistry["eye_derp_strength#{internal}"] = {
        default: -> 1
        getFunc: "DerpEyesStrength#{publicName}"
        min: PPM2.MIN_DERP_STRENGTH
        max: PPM2.MAX_DERP_STRENGTH
        type: 'FLOAT'
    }

    PPM2.PonyDataRegistry["eye_type#{internal}"] = {
        default: -> 0
        getFunc: "EyeType#{publicName}"
        enum: [arg for arg in *PPM2.AvaliableEyeTypes]
    }

    PPM2.PonyDataRegistry["hole_width#{internal}"] = {
        default: -> 1
        getFunc: "HoleWidth#{publicName}"
        min: PPM2.MIN_PUPIL_SIZE
        max: PPM2.MAX_PUPIL_SIZE
        type: 'FLOAT'
    }

    PPM2.PonyDataRegistry["hole_height#{internal}"] = {
        default: -> 1
        getFunc: "HoleHeight#{publicName}"
        min: PPM2.MIN_PUPIL_SIZE
        max: PPM2.MAX_PUPIL_SIZE
        type: 'FLOAT'
    }

    PPM2.PonyDataRegistry["iris_width#{internal}"] = {
        default: -> 1
        getFunc: "IrisWidth#{publicName}"
        min: PPM2.MIN_PUPIL_SIZE
        max: PPM2.MAX_PUPIL_SIZE
        type: 'FLOAT'
    }

    PPM2.PonyDataRegistry["iris_height#{internal}"] = {
        default: -> 1
        getFunc: "IrisHeight#{publicName}"
        min: PPM2.MIN_PUPIL_SIZE
        max: PPM2.MAX_PUPIL_SIZE
        type: 'FLOAT'
    }

    PPM2.PonyDataRegistry["hole_shiftx#{internal}"] = {
        default: -> 0
        getFunc: "HoleShiftX#{publicName}"
        min: PPM2.MIN_HOLE_SHIFT
        max: PPM2.MAX_HOLE_SHIFT
        type: 'FLOAT'
    }

    PPM2.PonyDataRegistry["hole_shifty#{internal}"] = {
        default: -> 0
        getFunc: "HoleShiftY#{publicName}"
        min: PPM2.MIN_HOLE_SHIFT
        max: PPM2.MAX_HOLE_SHIFT
        type: 'FLOAT'
    }

    PPM2.PonyDataRegistry["eye_hole_size#{internal}"] = {
        default: -> .8
        getFunc: "HoleSize#{publicName}"
        min: PPM2.MIN_HOLE
        max: PPM2.MAX_HOLE
        type: 'FLOAT'
    }

    PPM2.PonyDataRegistry["eye_rotation#{internal}"] = {
        default: -> 0
        getFunc: "EyeRotation#{publicName}"
        min: PPM2.MIN_EYE_ROTATION
        max: PPM2.MAX_EYE_ROTATION
        type: 'INT'
    }

for i = 1, 3
    PPM2.PonyDataRegistry["horn_url_#{i}"] = {
        default: -> ''
        getFunc: "HornURL#{i}"
        type: 'URL'
    }

    PPM2.PonyDataRegistry["bat_wing_url_#{i}"] = {
        default: -> ''
        getFunc: "BatWingURL#{i}"
        type: 'URL'
    }

    PPM2.PonyDataRegistry["bat_wing_skin_url_#{i}"] = {
        default: -> ''
        getFunc: "BatWingSkinURL#{i}"
        type: 'URL'
    }

    PPM2.PonyDataRegistry["wings_url_#{i}"] = {
        default: -> ''
        getFunc: "WingsURL#{i}"
        type: 'URL'
    }

    PPM2.PonyDataRegistry["horn_url_color_#{i}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "HornURLColor#{i}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["bat_wing_url_color_#{i}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "BatWingURLColor#{i}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["bat_wing_skin_url_color_#{i}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "BatWingSkinURLColor#{i}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["wings_url_color_#{i}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "WingsURLColor#{i}"
        type: 'COLOR'
    }

for i = 1, 6
    PPM2.PonyDataRegistry["socks_detail_color_#{i}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "SocksDetailColor#{i}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["mane_color_#{i}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "ManeColor#{i}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["mane_detail_color_#{i}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "ManeDetailColor#{i}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["mane_url_color_#{i}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "ManeURLColor#{i}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["mane_url_#{i}"] = {
        default: -> ''
        getFunc: "ManeURL#{i}"
        type: 'URL'
    }

    PPM2.PonyDataRegistry["tail_detail_color_#{i}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "TailDetailColor#{i}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["tail_url_color_#{i}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "TailURLColor#{i}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["tail_url_#{i}"] = {
        default: -> ''
        getFunc: "TailURL#{i}"
        type: 'URL'
    }

    PPM2.PonyDataRegistry["tail_color_#{i}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "TailColor#{i}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["lower_mane_color_#{i}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "LowerManeColor#{i}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["lower_mane_url_color_#{i}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "LowerManeURLColor#{i}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["lower_mane_url_#{i}"] = {
        default: -> ''
        getFunc: "LowerManeURL#{i}"
        type: 'URL'
    }

    PPM2.PonyDataRegistry["upper_mane_color_#{i}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "UpperManeColor#{i}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["upper_mane_url_color_#{i}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "UpperManeURLColor#{i}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["upper_mane_url_#{i}"] = {
        default: -> ''
        getFunc: "UpperManeURL#{i}"
        type: 'URL'
    }

    PPM2.PonyDataRegistry["lower_mane_detail_color_#{i}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "LowerManeDetailColor#{i}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["upper_mane_detail_color_#{i}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "UpperManeDetailColor#{i}"
        type: 'COLOR'
    }

for i = 1, PPM2.MAX_BODY_DETAILS
    PPM2.PonyDataRegistry["body_detail_color_#{i}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "BodyDetailColor#{i}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["body_detail_#{i}"] = {
        default: -> 0
        getFunc: "BodyDetail#{i}"
        enum: [arg for arg in *PPM2.BodyDetailsEnum]
    }

    PPM2.PonyDataRegistry["body_detail_url_#{i}"] = {
        default: -> ''
        getFunc: "BodyDetailURL#{i}"
        type: 'URL'
    }

    PPM2.PonyDataRegistry["body_detail_url_color_#{i}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "BodyDetailURLColor#{i}"
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry["body_detail_glow_#{i}"] = {
        default: -> false
        getFunc: "BodyDetailGlow#{i}"
        type: 'BOOLEAN'
    }

    PPM2.PonyDataRegistry["body_detail_glow_strength_#{i}"] = {
        default: -> 1
        getFunc: "BodyDetailGlowStrength#{i}"
        type: 'FLOAT'
        min: 0
        max: 1
    }

for i = 1, PPM2.MAX_TATTOOS
    PPM2.PonyDataRegistry["tattoo_type_#{i}"] = {
        default: -> 0
        getFunc: "TattooType#{i}"
        enum: [arg for arg in *PPM2.TATTOOS_REGISTRY]
    }

    PPM2.PonyDataRegistry["tattoo_posx_#{i}"] = {
        default: -> 0
        getFunc: "TattooPosX#{i}"
        min: -100
        max: 100
        type: 'FLOAT'
    }

    PPM2.PonyDataRegistry["tattoo_posy_#{i}"] = {
        default: -> 0
        getFunc: "TattooPosY#{i}"
        fix: (arg = 0) -> math.Clamp(tonumber(arg) or 0, -100, 100)
        min: -100
        max: 100
        type: 'FLOAT'
    }

    PPM2.PonyDataRegistry["tattoo_rotate_#{i}"] = {
        default: -> 0
        getFunc: "TattooRotate#{i}"
        min: -180
        max: 180
        type: 'INT'
    }

    PPM2.PonyDataRegistry["tattoo_scalex_#{i}"] = {
        default: -> 1
        getFunc: "TattooScaleX#{i}"
        min: 0
        max: 10
        type: 'FLOAT'
    }

    PPM2.PonyDataRegistry["tattoo_glow_strength_#{i}"] = {
        default: -> 1
        getFunc: "TattooGlowStrength#{i}"
        min: 0
        max: 1
        type: 'FLOAT'
    }

    PPM2.PonyDataRegistry["tattoo_scaley_#{i}"] = {
        default: -> 1
        getFunc: "TattooScaleY#{i}"
        min: 0
        max: 10
        type: 'FLOAT'
    }

    PPM2.PonyDataRegistry["tattoo_glow_#{i}"] = {
        default: -> false
        getFunc: "TattooGlow#{i}"
        type: 'BOOLEAN'
    }

    PPM2.PonyDataRegistry["tattoo_over_detail_#{i}"] = {
        default: -> false
        getFunc: "TattooOverDetail#{i}"
        type: 'BOOLEAN'
    }

    PPM2.PonyDataRegistry["tattoo_color_#{i}"] = {
        default: -> Color(255, 255, 255)
        getFunc: "TattooColor#{i}"
        type: 'COLOR'
    }

for ttype in *{'Body', 'Horn', 'Wings', 'BatWingsSkin', 'Socks', 'Mane', 'Tail', 'UpperMane', 'LowerMane'}
    PPM2.PonyDataRegistry[ttype\lower() .. '_phong_exponent'] = {
        default: -> 3
        getFunc: ttype .. 'PhongExponent'
        min: 0.04
        max: 10
        type: 'FLOAT'
    }

    PPM2.PonyDataRegistry[ttype\lower() .. '_phong_boost'] = {
        default: -> 0.09
        getFunc: ttype .. 'PhongBoost'
        min: 0.01
        max: 1
        type: 'FLOAT'
    }

    PPM2.PonyDataRegistry[ttype\lower() .. '_phong_front'] = {
        default: -> 1
        getFunc: ttype .. 'PhongFront'
        min: 0
        max: 20
        type: 'FLOAT'
    }

    PPM2.PonyDataRegistry[ttype\lower() .. '_phong_middle'] = {
        default: -> 5
        getFunc: ttype .. 'PhongMiddle'
        min: 0
        max: 20
        type: 'FLOAT'
    }

    PPM2.PonyDataRegistry[ttype\lower() .. '_phong_sliding'] = {
        default: -> 10
        getFunc: ttype .. 'PhongSliding'
        min: 0
        max: 20
        type: 'FLOAT'
    }

    PPM2.PonyDataRegistry[ttype\lower() .. '_phong_tint'] = {
        default: -> Color(255, 200, 200)
        getFunc: ttype .. 'PhongTint'
        type: 'COLOR'
    }

    PPM2.PonyDataRegistry[ttype\lower() .. '_lightwarp_texture'] = {
        default: -> 0
        getFunc: ttype .. 'Lightwarp'
        enum: [arg for arg in *PPM2.AvaliableLightwarps]
    }

    PPM2.PonyDataRegistry[ttype\lower() .. '_lightwarp_texture_url'] = {
        default: -> ''
        getFunc: ttype .. 'LightwarpURL'
        type: 'URL'
    }

for {:flex, :active} in *PPM2.PonyFlexController.FLEX_LIST
    continue if not active
    PPM2.PonyDataRegistry["flex_disable_#{flex\lower()}"] = {
        default: -> false
        getFunc: "DisableFlex#{flex}"
        type: 'BOOLEAN'
    }

for key, value in pairs PPM2.PonyDataRegistry
    if value.enum
        value.min = 0
        value.max = #value.enum - 1
        value.type = 'INT'

    switch value.type
        when 'INT'
            error("Variable #{key} has invalid minimal value (#{type(value.min)})") if type(value.min) ~= 'number'
            error("Variable #{max} has invalid maximal value (#{type(value.max)})") if type(value.max) ~= 'number'
            value.fix = INT_FIXER(value.default, value.min, value.max)
            if value.min >= 0
                selectBits = 16
                while 2 ^ (selectBits - 1) > value.max
                    selectBits -= 1
                value.read = rUInt(selectBits, value.min, value.max)
                value.write = wUInt(value.default(), selectBits)
            else
                delta = math.max(value.max, -value.min)
                selectBits = 16
                while 2 ^ (selectBits - 1) > delta
                    selectBits -= 1
                value.read = rInt(selectBits, value.min, value.max)
                value.write = wInt(value.default(), selectBits)
        when 'FLOAT'
            error("Variable #{key} has invalid minimal value (#{type(value.min)})") if type(value.min) ~= 'number'
            error("Variable #{max} has invalid maximal value (#{type(value.max)})") if type(value.max) ~= 'number'
            value.fix = FLOAT_FIXER(value.default, value.min, value.max)
            value.read = rFloat(value.min, value.max)
            value.write = (arg = value.default()) -> wFloat(arg)
        when 'URL'
            value.fix = URL_FIXER
            value.read = rURL
            value.write = wString
        when 'BOOLEAN'
            value.fix = (arg = value.default()) -> tobool(arg)
            value.read = rBool
            value.write = wBool
        when 'COLOR'
            {:r, :g, :b, :a} = value.default()
            value.fix = COLOR_FIXER(r, g, b, a)
            value.read = rColor
            value.write = wColor
        else
            error("Unknown variable type - #{value.type} for #{key}")

    error("Data has no fix function: #{key}") if not value.fix


Fixed traces and speed

Fixed traces and speed

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

ALLOW_FLIGHT = CreateConVar('ppm2_sv_flight', '1', {FCVAR_ARCHIVE, FCVAR_REPLICATED, FCVAR_NOTIFY}, 'Allow flight for pegasus and alicorns. It obeys PlayerNoClip hook.')

class PonyflyController
    new: (data) =>
        @controller = data
        @ent = data.ent
        @speedMult = 0.5
        @speedMultDirections = 1.25
        @dragMult = 0.95
        @obbCenter = Vector(0, 0, 0)
        @obbMins = Vector(0, 0, 0)
        @obbMaxs = Vector(0, 0, 0)
        @speedMultDiv = 2
        @speedMultLift = 2
        @pitch = 0
        @yaw = 0
        @roll = 0
        @angleLerp = 1
        @lastVelocity = Vector(0, 0, 0)
        @lastState = false

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

    Switch: (status = false) =>
        @ent = @controller.ent
        return if not IsValid(@ent)
        return if @lastState == status
        @lastState = status
        if not status
            {:p, :y, :r} = @ent\EyeAngles()
            newAng = Angle(p, y, 0)
            @ent\SetEyeAngles(newAng)
            @ent\SetMoveType(MOVETYPE_WALK)
            @roll = 0
            @pitch = 0
            @yaw = 0
            @ent\SetVelocity(@lastVelocity * 50)
            @lastVelocity = Vector(0, 0, 0)
        else
            @lastVelocity = Vector(0, 0, 0)
            @ent\SetVelocity(-@ent\GetVelocity() * .97)
            @ent\SetMoveType(MOVETYPE_CUSTOM)
            @obbCenter = @ent\OBBCenter()
            @obbMins = @ent\OBBMins()
            @obbMaxs = @ent\OBBMaxs()
            @roll = 0
            @pitch = 0
            @yaw = 0
    Think: (movedata) =>
        pos     = movedata\GetOrigin()
        ang     = movedata\GetAngles()
        fwd     = ang\Forward()
        bcwd    = -ang\Forward()
        right   = ang\Right()
        left    = -ang\Right()
        up      = ang\Up()
        down    = -ang\Up()
        W       = movedata\KeyDown(IN_FORWARD)
        S       = movedata\KeyDown(IN_BACK)
        D       = movedata\KeyDown(IN_MOVERIGHT)
        A       = movedata\KeyDown(IN_MOVELEFT)
        CTRL    = movedata\KeyDown(IN_DUCK)
        MULT    = FrameTime() * 66

        velocity = movedata\GetVelocity()
        cSpeed = velocity\Length()
        cSpeed = 1 if cSpeed < 1
        dragSqrt = math.min(math.sqrt(cSpeed) / cSpeed * 2, 0.99)
        cSpeedMult = @speedMultDiv / cSpeed
        cSpeedMult = @speedMultDiv if cSpeedMult ~= cSpeedMult
        cSpeedLiftMult = @speedMultLift / cSpeed
        cSpeedLiftMult = @speedMultLift if cSpeedLiftMult ~= cSpeedLiftMult

        dragCalc = math.Clamp(@dragMult / dragSqrt, 0, 0.99)
        pitch = 0
        yaw = 0
        roll = 0

        hit = false
        hitLift = false

        if W
            velocity += fwd * MULT * @speedMult * cSpeedMult * @speedMultDirections
            hit = true
            pitch += 20

        if S
            velocity += bcwd * MULT * @speedMult * cSpeedMult * @speedMultDirections
            hit = true
            pitch -= 20

        if A
            velocity += left * MULT * @speedMult * cSpeedMult * @speedMultDirections
            hit = true
            roll -= 20

        if D
            velocity += right * MULT * @speedMult * cSpeedMult * @speedMultDirections
            hit = true
            roll += 20

        if CTRL
            velocity += Vector(0, 0, -MULT * @speedMult * cSpeedLiftMult)
            hitLift = true

        if @isLiftingUp
            velocity += Vector(0, 0, MULT * @speedMult * cSpeedLiftMult)
            hitLift = true

        if CLIENT
            lerpMult = FrameTime() * @angleLerp
            {:p, :y, :r} = ang
            p -= @pitch
            y -= @yaw
            @pitch = Lerp(lerpMult, @pitch, pitch)
            @yaw = Lerp(lerpMult, @yaw, yaw)
            @roll = Lerp(lerpMult, @roll, roll)
            p += @pitch
            y += @yaw
            r = @roll + math.sin(RealTime()) * 2
            newAng = Angle(p, y, r)
            @ent\SetEyeAngles(newAng)

        if not hit
            velocity.x *= dragCalc
            velocity.y *= dragCalc

        if not hitLift
            velocity.z *= dragCalc
            velocity.z += math.sin(RealTime() * 2) * .01

        pos += velocity

        movedata\SetVelocity(velocity)
        movedata\SetOrigin(pos)
        return true

    SetupMove: (movedata, cmd) =>
        @isLiftingUp = movedata\KeyDown(IN_JUMP)
        if @isLiftingUp
            movedata\SetButtons(movedata\GetButtons() - IN_JUMP)
        cmd\SetButtons(cmd\GetButtons() - IN_JUMP) if cmd\KeyDown(IN_JUMP)

    FinishMove: (movedata) =>
        mvPos = movedata\GetOrigin()
        pos = @ent\GetPos()
        rpos = pos + @obbCenter
        tryMove = util.TraceHull({
            filter: (ent) ->
                return false if @ent == ent
                return true if not IsValid(ent)
                collision = ent\GetCollisionGroup()
                return false if collision == COLLISION_GROUP_WORLD
                return false if collision == COLLISION_GROUP_DEBRIS
                return false if collision == COLLISION_GROUP_DEBRIS_TRIGGER
                return false if collision == COLLISION_GROUP_WEAPON
                return false if collision == COLLISION_GROUP_PASSABLE_DOOR
                return true
            mins: @obbMins
            maxs: @obbMaxs
            start: rpos
            endpos: mvPos
        })

        velocity = movedata\GetVelocity()
        newVelocity = velocity
        length = velocity\Length()

        if not tryMove.Hit
            @ent\SetPos(mvPos)
        else
            if IsValid(tryMove.Entity)
                newVelocity = Vector(0, 0, 0)
                movedata\SetVelocity(newVelocity)
                newPos = tryMove.HitPos + tryMove.HitNormal
                @ent\SetPos(newPos)
                movedata\SetOrigin(newPos)
            else
                newVelocity = velocity - tryMove.HitNormal * velocity\Dot(tryMove.HitNormal * 1.1)
                movedata\SetVelocity(newVelocity)
                newPos = tryMove.HitPos + tryMove.HitNormal
                @ent\SetPos(newPos)
                movedata\SetOrigin(newPos)
            if length > 7 and SERVER
                dmgInfo = DamageInfo()
                dmgInfo\SetAttacker(@ent)
                dmgInfo\SetInflictor(@ent)
                dmgInfo\SetDamageType(DMG_CRUSH)
                calcDamage = math.Clamp((length / 4) ^ 2, 1, 100)
                if calcDamage >= 100
                    @ent\EmitSound('physics/flesh/flesh_bloody_break.wav', 100)
                elseif calcDamage > 70
                    @ent\EmitSound('physics/flesh/flesh_bloody_break.wav', 100)
                elseif calcDamage > 50
                    @ent\EmitSound("physics/body/body_medium_break#{math.random(2, 4)}.wav", 75)
                elseif calcDamage > 25
                    @ent\EmitSound("physics/body/body_medium_impact_hard#{math.random(1, 6)}.wav", 75)
                elseif calcDamage > 10
                    @ent\EmitSound("physics/body/body_medium_impact_soft#{math.random(1, 7)}.wav", 75)
                else
                    @ent\EmitSound("physics/flesh/flesh_impact_bullet#{math.random(1, 5)}.wav", 75)
                dmgInfo\SetDamage(calcDamage)
                @ent\TakeDamageInfo(dmgInfo)
        @lastVelocity = newVelocity

PPM2.PonyflyController = PonyflyController

hook.Add 'SetupMove', 'PPM2.Ponyfly', (movedata, cmd) =>
    return if not @IsPonyCached()
    data = @GetPonyData()
    return if not data
    return if not data\GetFly()
    flight = data\GetFlightController()
    return if not flight
    return flight\SetupMove(movedata, cmd)

hook.Add 'Move', 'PPM2.Ponyfly', (movedata) =>
    return if not @IsPonyCached()
    data = @GetPonyData()
    return if not data
    return if not data\GetFly()
    flight = data\GetFlightController()
    return if not flight
    return flight\Think(movedata)

hook.Add 'FinishMove', 'PPM2.Ponyfly', (movedata) =>
    return if not @IsPonyCached()
    data = @GetPonyData()
    return if not data
    return if not data\GetFly()
    flight = data\GetFlightController()
    return if not flight
    return flight\FinishMove(movedata)

hook.Add 'CalcMainActivity', 'PPM2.Ponyfly', (movedata) =>
    return if not @IsPonyCached()
    data = @GetPonyData()
    return if not data
    return if not data\GetFly()
    return ACT_SWIM, 370

if SERVER
    concommand.Add 'ppm2_fly', =>
        return if not ALLOW_FLIGHT\GetBool()
        return if not IsValid(@)
        return if not @IsPonyCached()
        data = @GetPonyData()
        return if not data
        if data\GetFly()
            can = hook.Run('PlayerNoClip', @, false)
            data\SetFly(false) if can ~= false
        else
            return if data\GetRace() ~= PPM2.RACE_PEGASUS and data\GetRace() ~= PPM2.RACE_ALICORN
            can = hook.Run('PlayerNoClip', @, true)
            data\SetFly(true) if can ~= false
else
    lastDouble = 0
    hook.Add 'PlayerBindPress', 'PPM2.Ponyfly', (bind = '', pressed = false) =>
        return if not ALLOW_FLIGHT\GetBool()
        return if not pressed
        return if bind ~= '+jump' and bind ~= 'jump'
        if lastDouble > RealTime()
            return if not @IsPonyCached()
            data = @GetPonyData()
            return if not data
            if data\GetRace() ~= PPM2.RACE_PEGASUS and data\GetRace() ~= PPM2.RACE_ALICORN
                PPM2.ChatPrint('You need to be a Pegasus or an Alicorn to fly!')
                return
            RunConsoleCommand('ppm2_fly')
            lastDouble = 0
            return
        lastDouble = RealTime() + 0.2

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

ALLOW_FLIGHT = CreateConVar('ppm2_sv_flight', '1', {FCVAR_ARCHIVE, FCVAR_REPLICATED, FCVAR_NOTIFY}, 'Allow flight for pegasus and alicorns. It obeys PlayerNoClip hook.')

class PonyflyController
    new: (data) =>
        @controller = data
        @ent = data.ent
        @speedMult = 0.5
        @speedMultDirections = 1.25
        @dragMult = 0.95
        @obbCenter = Vector(0, 0, 0)
        @obbMins = Vector(0, 0, 0)
        @obbMaxs = Vector(0, 0, 0)
        @speedMultDiv = 3
        @speedMultLift = 2
        @pitch = 0
        @yaw = 0
        @roll = 0
        @angleLerp = 1
        @lastVelocity = Vector(0, 0, 0)
        @lastState = false

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

    Switch: (status = false) =>
        @ent = @controller.ent
        return if not IsValid(@ent)
        return if @lastState == status
        @lastState = status
        if not status
            {:p, :y, :r} = @ent\EyeAngles()
            newAng = Angle(p, y, 0)
            @ent\SetEyeAngles(newAng)
            @ent\SetMoveType(MOVETYPE_WALK)
            @roll = 0
            @pitch = 0
            @yaw = 0
            @ent\SetVelocity(@lastVelocity * 50)
            @lastVelocity = Vector(0, 0, 0)
        else
            @lastVelocity = Vector(0, 0, 0)
            @ent\SetVelocity(-@ent\GetVelocity() * .97)
            @ent\SetMoveType(MOVETYPE_CUSTOM)
            @obbCenter = @ent\OBBCenter()
            @obbMins = @ent\OBBMins()
            @obbMaxs = @ent\OBBMaxs()
            @roll = 0
            @pitch = 0
            @yaw = 0
    Think: (movedata) =>
        pos     = movedata\GetOrigin()
        ang     = movedata\GetAngles()
        fwd     = ang\Forward()
        bcwd    = -ang\Forward()
        right   = ang\Right()
        left    = -ang\Right()
        up      = ang\Up()
        down    = -ang\Up()
        W       = movedata\KeyDown(IN_FORWARD)
        S       = movedata\KeyDown(IN_BACK)
        D       = movedata\KeyDown(IN_MOVERIGHT)
        A       = movedata\KeyDown(IN_MOVELEFT)
        CTRL    = movedata\KeyDown(IN_DUCK)
        MULT    = FrameTime() * 66

        velocity = movedata\GetVelocity()
        cSpeed = velocity\Length()
        cSpeed = 1 if cSpeed < 1
        dragSqrt = math.min(math.sqrt(cSpeed) / cSpeed * 2, 0.99)
        cSpeedMult = @speedMultDiv / cSpeed
        cSpeedMult = @speedMultDiv if cSpeedMult ~= cSpeedMult
        cSpeedLiftMult = @speedMultLift / cSpeed
        cSpeedLiftMult = @speedMultLift if cSpeedLiftMult ~= cSpeedLiftMult

        dragCalc = math.Clamp(@dragMult / dragSqrt, 0, 0.99)
        pitch = 0
        yaw = 0
        roll = 0

        hit = false
        hitLift = false

        if W
            velocity += fwd * MULT * @speedMult * cSpeedMult * @speedMultDirections
            hit = true
            pitch += 20

        if S
            velocity += bcwd * MULT * @speedMult * cSpeedMult * @speedMultDirections
            hit = true
            pitch -= 20

        if A
            velocity += left * MULT * @speedMult * cSpeedMult * @speedMultDirections
            hit = true
            roll -= 20

        if D
            velocity += right * MULT * @speedMult * cSpeedMult * @speedMultDirections
            hit = true
            roll += 20

        if CTRL
            velocity += Vector(0, 0, -MULT * @speedMult * cSpeedLiftMult)
            hitLift = true

        if @isLiftingUp
            velocity += Vector(0, 0, MULT * @speedMult * cSpeedLiftMult)
            hitLift = true

        if CLIENT
            lerpMult = FrameTime() * @angleLerp
            {:p, :y, :r} = ang
            p -= @pitch
            y -= @yaw
            @pitch = Lerp(lerpMult, @pitch, pitch)
            @yaw = Lerp(lerpMult, @yaw, yaw)
            @roll = Lerp(lerpMult, @roll, roll)
            p += @pitch
            y += @yaw
            r = @roll + math.sin(RealTime()) * 2
            newAng = Angle(p, y, r)
            @ent\SetEyeAngles(newAng)

        if not hit
            velocity.x *= dragCalc
            velocity.y *= dragCalc

        if not hitLift
            velocity.z *= dragCalc
            velocity.z += math.sin(RealTime() * 2) * .01

        pos += velocity

        movedata\SetVelocity(velocity)
        movedata\SetOrigin(pos)
        return true

    SetupMove: (movedata, cmd) =>
        @isLiftingUp = movedata\KeyDown(IN_JUMP)
        if @isLiftingUp
            movedata\SetButtons(movedata\GetButtons() - IN_JUMP)
        cmd\SetButtons(cmd\GetButtons() - IN_JUMP) if cmd\KeyDown(IN_JUMP)

    FinishMove: (movedata) =>
        mvPos = movedata\GetOrigin()
        pos = @ent\GetPos()
        rpos = pos + @obbCenter
        tryMove = util.TraceHull({
            filter: @ent
            mins: @obbMins
            maxs: @obbMaxs
            start: rpos
            endpos: mvPos
        })

        velocity = movedata\GetVelocity()
        newVelocity = velocity
        length = velocity\Length()

        if not tryMove.Hit
            @ent\SetPos(mvPos)
        else
            if IsValid(tryMove.Entity)
                newVelocity = Vector(0, 0, 0)
                movedata\SetVelocity(newVelocity)
                newPos = tryMove.HitPos + tryMove.HitNormal
                @ent\SetPos(newPos)
                movedata\SetOrigin(newPos)
            else
                newVelocity = velocity - tryMove.HitNormal * velocity\Dot(tryMove.HitNormal * 1.1)
                movedata\SetVelocity(newVelocity)
                newPos = tryMove.HitPos + tryMove.HitNormal
                @ent\SetPos(newPos)
                movedata\SetOrigin(newPos)
            if length > 7 and SERVER
                dmgInfo = DamageInfo()
                dmgInfo\SetAttacker(@ent)
                dmgInfo\SetInflictor(@ent)
                dmgInfo\SetDamageType(DMG_CRUSH)
                calcDamage = math.Clamp((length / 4) ^ 2, 1, 100)
                if calcDamage >= 100
                    @ent\EmitSound('physics/flesh/flesh_bloody_break.wav', 100)
                elseif calcDamage > 70
                    @ent\EmitSound('physics/flesh/flesh_bloody_break.wav', 100)
                elseif calcDamage > 50
                    @ent\EmitSound("physics/body/body_medium_break#{math.random(2, 4)}.wav", 75)
                elseif calcDamage > 25
                    @ent\EmitSound("physics/body/body_medium_impact_hard#{math.random(1, 6)}.wav", 75)
                elseif calcDamage > 10
                    @ent\EmitSound("physics/body/body_medium_impact_soft#{math.random(1, 7)}.wav", 75)
                else
                    @ent\EmitSound("physics/flesh/flesh_impact_bullet#{math.random(1, 5)}.wav", 75)
                dmgInfo\SetDamage(calcDamage)
                @ent\TakeDamageInfo(dmgInfo)
        @lastVelocity = newVelocity

PPM2.PonyflyController = PonyflyController

hook.Add 'SetupMove', 'PPM2.Ponyfly', (movedata, cmd) =>
    return if not @IsPonyCached()
    data = @GetPonyData()
    return if not data
    return if not data\GetFly()
    flight = data\GetFlightController()
    return if not flight
    return flight\SetupMove(movedata, cmd)

hook.Add 'Move', 'PPM2.Ponyfly', (movedata) =>
    return if not @IsPonyCached()
    data = @GetPonyData()
    return if not data
    return if not data\GetFly()
    flight = data\GetFlightController()
    return if not flight
    return flight\Think(movedata)

hook.Add 'FinishMove', 'PPM2.Ponyfly', (movedata) =>
    return if not @IsPonyCached()
    data = @GetPonyData()
    return if not data
    return if not data\GetFly()
    flight = data\GetFlightController()
    return if not flight
    return flight\FinishMove(movedata)

hook.Add 'CalcMainActivity', 'PPM2.Ponyfly', (movedata) =>
    return if not @IsPonyCached()
    data = @GetPonyData()
    return if not data
    return if not data\GetFly()
    return ACT_SWIM, 370

if SERVER
    concommand.Add 'ppm2_fly', =>
        return if not ALLOW_FLIGHT\GetBool()
        return if not IsValid(@)
        return if not @IsPonyCached()
        data = @GetPonyData()
        return if not data
        if data\GetFly()
            can = hook.Run('PlayerNoClip', @, false)
            data\SetFly(false) if can ~= false
        else
            return if data\GetRace() ~= PPM2.RACE_PEGASUS and data\GetRace() ~= PPM2.RACE_ALICORN
            can = hook.Run('PlayerNoClip', @, true)
            data\SetFly(true) if can ~= false
else
    lastDouble = 0
    hook.Add 'PlayerBindPress', 'PPM2.Ponyfly', (bind = '', pressed = false) =>
        return if not ALLOW_FLIGHT\GetBool()
        return if not pressed
        return if bind ~= '+jump' and bind ~= 'jump'
        if lastDouble > RealTime()
            return if not @IsPonyCached()
            data = @GetPonyData()
            return if not data
            if data\GetRace() ~= PPM2.RACE_PEGASUS and data\GetRace() ~= PPM2.RACE_ALICORN
                PPM2.ChatPrint('You need to be a Pegasus or an Alicorn to fly!')
                return
            RunConsoleCommand('ppm2_fly')
            lastDouble = 0
            return
        lastDouble = RealTime() + 0.2


Updated registry to use pngs

Updated registry to use pngs

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

PPM2.USE_HIGHRES_BODY = CreateConVar('ppm2_cl_hires_body', '0', {FCVAR_ACRHIVE}, 'Use high resoluation when rendering pony bodies. AFFECTS ONLY TEXTURE COMPILATION TIME (increases lag spike on pony data load)')
PPM2.USE_HIGHRES_TEXTURES = CreateConVar('ppm2_cl_hires_generic', '0', {FCVAR_ACRHIVE}, 'Create 1024x1024 textures instead of 512x512 on texture compiling')

RELOADABLE_MATERIALS = {}
PPM2.RELOADABLE_MATERIALS = RELOADABLE_MATERIALS
concommand.Add 'ppm2_reload_materials', ->
    cTime = SysTime()
    for mat in *RELOADABLE_MATERIALS
        if texname = mat\GetString('$basetexture')
            mat\SetTexture('$basetexture', texname)
        if texture = mat\GetTexture('$basetexture')
            texture\Download()
        mat\Recompute()
    PPM2.PonyTextureController.URL_MATERIAL_CACHE = {}
    PPM2.Message('Reloaded textures in ', math.floor((SysTime() - cTime) * 100000) / 100, ' milliseconds. Do not forget to ppm2_reload and ppm2_require now!')

_Material = Material
_CreateMaterial = CreateMaterial
Material = (path) ->
    matNew, time = _Material(path)
    table.insert(RELOADABLE_MATERIALS, matNew)
    return matNew, time

CreateMaterial = (name, shader, data) ->
    matNew, time = _CreateMaterial(name, shader, data)
    table.insert(RELOADABLE_MATERIALS, matNew)
    return matNew, time

module = {
    BODY_DETAILS: {
        Material('models/ppm/partrender/body_leggrad1.png')
        Material('models/ppm/partrender/body_lines1.png')
        Material('models/ppm/partrender/body_stripes1.png')
        Material('models/ppm/partrender/body_headstripes1.png')
        Material('models/ppm/partrender/body_freckles.png')
        Material('models/ppm/partrender/body_hooves1.png')
        Material('models/ppm/partrender/body_hooves2.png')
        Material('models/ppm/partrender/body_headmask1.png')
        Material('models/ppm/partrender/body_hooves1_crit.png')
        Material('models/ppm/partrender/body_hooves2_crit.png')
        Material('models/ppm/partrender/body_spots1.png')
        Material('models/ppm/partrender/body_robotic.png')
        Material('models/ppm/partrender/dash-e.png')
        Material('models/ppm/partrender/eye_scar.png')
        Material('models/ppm/partrender/eye_wound.png')
        Material('models/ppm/partrender/body_scar.png')
        Material('models/ppm/partrender/gear_socks.png')
        Material('models/ppm/partrender/sharp_hooves.png')
        Material('models/ppm/partrender/sharp_hooves2.png')
        Material('models/ppm/partrender/separated_muzzle.png')
        Material('models/ppm/partrender/eye_scar_left.png')
        Material('models/ppm/partrender/eye_scar_right.png')
    }

    UPPER_MANE_DETAILS: {
        [4]: {Material('models/ppm/partrender/upmane_5_mask0.png')}
        [5]: {Material('models/ppm/partrender/upmane_6_mask0.png')}
        [7]: {Material('models/ppm/partrender/upmane_8_mask0.png'), Material('models/ppm/partrender/upmane_8_mask1.png')}
        [8]: {Material('models/ppm/partrender/upmane_9_mask0.png'), Material('models/ppm/partrender/upmane_9_mask1.png'), Material('models/ppm/partrender/upmane_9_mask2.png')}
        [9]: {Material('models/ppm/partrender/upmane_10_mask0.png')}
        [10]: {Material('models/ppm/partrender/upmane_11_mask0.png'), Material('models/ppm/partrender/upmane_11_mask1.png'), Material('models/ppm/partrender/upmane_11_mask2.png')}
        [11]: {Material('models/ppm/partrender/upmane_12_mask0.png')}
        [12]: {Material('models/ppm/partrender/upmane_13_mask0.png')}
        [13]: {Material('models/ppm/partrender/upmane_14_mask0.png')}
        [14]: {Material('models/ppm/partrender/upmane_15_mask0.png')}
    }

    LOWER_MANE_DETAILS: {
        [4]: {Material('models/ppm/partrender/dnmane_5_mask0.png')}
        [7]: {Material('models/ppm/partrender/dnmane_8_mask0.png'), Material('models/ppm/partrender/dnmane_8_mask1.png')}
        [8]: {Material('models/ppm/partrender/dnmane_9_mask0.png'), Material('models/ppm/partrender/dnmane_9_mask1.png')}
        [9]: {Material('models/ppm/partrender/dnmane_10_mask0.png'), Material('models/ppm/partrender/dnmane_10_mask1.png'), Material('models/ppm/partrender/dnmane_10_mask2.png')}
        [10]: {Material('models/ppm/partrender/dnmane_11_mask0.png'), Material('models/ppm/partrender/dnmane_11_mask1.png')}
        [11]: {Material('models/ppm/partrender/dnmane_12_mask0.png')}
    }

    TAIL_DETAILS: {
        [4]: {Material('models/ppm/partrender/tail_5_mask0.png')}
        [7]: {Material('models/ppm/partrender/tail_8_mask0.png'), Material('models/ppm/partrender/tail_8_mask1.png'), Material('models/ppm/partrender/tail_8_mask2.png'), Material('models/ppm/partrender/tail_8_mask3.png'), Material('models/ppm/partrender/tail_8_mask4.png')}
        [9]: {Material('models/ppm/partrender/tail_10_mask0.png')}
        [10]: {Material('models/ppm/partrender/tail_11_mask0.png'), Material('models/ppm/partrender/tail_11_mask1.png'), Material('models/ppm/partrender/tail_11_mask2.png')}
        [11]: {Material('models/ppm/partrender/tail_12_mask0.png'), Material('models/ppm/partrender/tail_12_mask1.png')}
        [12]: {Material('models/ppm/partrender/tail_13_mask0.png')}
        [13]: {Material('models/ppm/partrender/tail_14_mask0.png')}
    }

    SOCKS_PATCHS: {
        'models/props_pony/ppm/ppm_socks/socks_striped_unlit.png'
        'models/props_pony/ppm/ppm_socks/custom/geometric1_1.png'
        'models/props_pony/ppm/ppm_socks/custom/geometric2_1.png'
        'models/props_pony/ppm/ppm_socks/custom/geometric3_1.png'
        'models/props_pony/ppm/ppm_socks/custom/geometric4_1.png'
        'models/props_pony/ppm/ppm_socks/custom/geometric5_1.png'
        'models/props_pony/ppm/ppm_socks/custom/geometric6_1.png'
        'models/props_pony/ppm/ppm_socks/custom/geometric7_1.png'
        'models/props_pony/ppm/ppm_socks/custom/geometric8_1.png'
        'models/props_pony/ppm/ppm_socks/custom_textured/dark1.png'
        'models/props_pony/ppm/ppm_socks/custom_textured/flowers10.png'
        'models/props_pony/ppm/ppm_socks/custom_textured/flowers11.png'
        'models/props_pony/ppm/ppm_socks/custom_textured/flowers12.png'
        'models/props_pony/ppm/ppm_socks/custom_textured/flowers13.png'
        'models/props_pony/ppm/ppm_socks/custom_textured/flowers14.png'
        'models/props_pony/ppm/ppm_socks/custom_textured/flowers15.png'
        'models/props_pony/ppm/ppm_socks/custom_textured/flowers16.png'
        'models/props_pony/ppm/ppm_socks/custom_textured/flowers17.png'
        'models/props_pony/ppm/ppm_socks/custom_textured/flowers18.png'
        'models/props_pony/ppm/ppm_socks/custom_textured/flowers19.png'
        'models/props_pony/ppm/ppm_socks/custom_textured/flowers2.png'
        'models/props_pony/ppm/ppm_socks/custom_textured/flowers20.png'
        'models/props_pony/ppm/ppm_socks/custom_textured/flowers3.png'
        'models/props_pony/ppm/ppm_socks/custom_textured/flowers4.png'
        'models/props_pony/ppm/ppm_socks/custom_textured/flowers5.png'
        'models/props_pony/ppm/ppm_socks/custom_textured/flowers6.png'
        'models/props_pony/ppm/ppm_socks/custom_textured/flowers7.png'
        'models/props_pony/ppm/ppm_socks/custom_textured/flowers8.png'
        'models/props_pony/ppm/ppm_socks/custom_textured/flowers9.png'
        'models/props_pony/ppm/ppm_socks/custom_textured/grey1.png'
        'models/props_pony/ppm/ppm_socks/custom_textured/grey2.png'
        'models/props_pony/ppm/ppm_socks/custom_textured/grey3.png'
        'models/props_pony/ppm/ppm_socks/custom_textured/hearts1.png'
        'models/props_pony/ppm/ppm_socks/custom_textured/hearts2.png'
        'models/props_pony/ppm/ppm_socks/custom_textured/snow1.png'
        'models/props_pony/ppm/ppm_socks/custom_textured/wallpaper1.png'
        'models/props_pony/ppm/ppm_socks/custom_textured/wallpaper2.png'
        'models/props_pony/ppm/ppm_socks/custom_textured/wallpaper3.png'
    }

    SOCKS_DETAILS_PATCHS: {
        [2]: {
            'models/props_pony/ppm/ppm_socks/custom/geometric1_4.png'
            'models/props_pony/ppm/ppm_socks/custom/geometric1_5.png'
            'models/props_pony/ppm/ppm_socks/custom/geometric1_6.png'
        }

        [3]: {
            'models/props_pony/ppm/ppm_socks/custom/geometric2_3.png'
            'models/props_pony/ppm/ppm_socks/custom/geometric2_4.png'
        }

        [4]: {
            'models/props_pony/ppm/ppm_socks/custom/geometric3_2.png'
            'models/props_pony/ppm/ppm_socks/custom/geometric3_3.png'
            'models/props_pony/ppm/ppm_socks/custom/geometric3_5.png'
        }

        [5]: {
            'models/props_pony/ppm/ppm_socks/custom/geometric4_2.png'
            'models/props_pony/ppm/ppm_socks/custom/geometric4_3.png'
            'models/props_pony/ppm/ppm_socks/custom/geometric4_4.png'
        }

        [6]: {
            'models/props_pony/ppm/ppm_socks/custom/geometric5_4.png'
            'models/props_pony/ppm/ppm_socks/custom/geometric5_5.png'
            'models/props_pony/ppm/ppm_socks/custom/geometric5_6.png'
        }

        [7]: {
            'models/props_pony/ppm/ppm_socks/custom/geometric6_2.png'
            'models/props_pony/ppm/ppm_socks/custom/geometric6_3.png'
            'models/props_pony/ppm/ppm_socks/custom/geometric6_4.png'
        }

        [8]: {
            'models/props_pony/ppm/ppm_socks/custom/geometric7_3.png'
            'models/props_pony/ppm/ppm_socks/custom/geometric7_4.png'
        }

        [9]: {
            'models/props_pony/ppm/ppm_socks/custom/geometric8_2.png'
            'models/props_pony/ppm/ppm_socks/custom/geometric8_3.png'
        }
    }
}

module.SOCKS_MATERIALS = [Material(id) for id in *module.SOCKS_PATCHS]
module.SOCKS_DETAILS = [Material(id) for id in *module.SOCKS_DETAILS_PATCHS]
module.CUTIEMARKS = [CreateMaterial("PPM2_CMarkDraw_#{mark}", 'UnlitGeneric', {'$basetexture': "models/ppm/cmarks/#{mark}", '$ignorez': 1, '$vertexcolor': 1, '$vertexalpha': 1, '$nolod': 1}) for mark in *PPM2.DefaultCutiemarks]
module.SUITS = [Material("models/ppm/texclothes/#{mat}.png") for mat in *{
    'clothes_royalguard', 'clothes_sbs_full'
    'clothes_sbs_light', 'clothes_wbs_full'
    'clothes_wbs_light', 'spidermane_light'
    'spidermane_full'
}]

additionTable = (...) ->
    tab = {'$ignorez': 1, '$vertexcolor': 1, '$vertexalpha': 1, '$nolod': 1}
    args = {...}
    for i = 1, #args, 2
        key, val = args[i], args[i + 1]
        tab[key] = val
    return tab

module.TATTOOS = [Material("models/ppm/partrender/tattoo/#{fil\lower()}.png") for fil in *PPM2.TATTOOS_REGISTRY when fil ~= 'NONE']
debugwhite = {
    '$basetexture': 'models/debug/debugwhite'
    '$ignorez': 1
    '$vertexcolor': 1
    '$vertexalpha': 1
    '$nolod': 1
}

module.EYE_OVALS = {
    Material('models/ppm/partrender/eye_oval.png')
    Material('models/ppm/partrender/eye_oval_aperture.png')
}

module.DEBUGWHITE = CreateMaterial('PPM2.Debugwhite', 'UnlitGeneric', debugwhite)
module.HAIR_MATERIAL_COLOR = CreateMaterial('PPM2.ManeTextureBase', 'UnlitGeneric', debugwhite)
module.TAIL_MATERIAL_COLOR = CreateMaterial('PPM2.TailTextureBase', 'UnlitGeneric', debugwhite)
module.WINGS_MATERIAL_COLOR = CreateMaterial('PPM2.WingsMaterialBase', 'UnlitGeneric', debugwhite)
module.HORN_MATERIAL_COLOR = CreateMaterial('PPM2.HornMaterialBase', 'UnlitGeneric', additionTable('$basetexture', 'models/ppm/base/horn'))
module.BODY_MATERIAL = CreateMaterial('PPM2.BodyTexture', 'UnlitGeneric', additionTable('$basetexture', 'models/ppm/base/body'))
module.HORN_DETAIL_BUMP = CreateMaterial('PPM2.HornBumpMapRenderer', 'UnlitGeneric', additionTable('$basetexture', 'models/ppm/base/horn_normal'))
module.HORN_DETAIL_COLOR = Material('models/ppm/partrender/horn_detail.png')
module.EYE_OVAL = Material('models/ppm/partrender/eye_oval.png')
module.EYE_GRAD = Material('models/ppm/partrender/eye_grad.png')
module.EYE_EFFECT = Material('models/ppm/partrender/eye_effect.png')
module.EYE_REFLECTION = Material('models/ppm/partrender/eye_reflection.png')
module.EYE_LINE_L_1 = Material('models/ppm/partrender/eye_line_l1.png')
module.EYE_LINE_R_1 = Material('models/ppm/partrender/eye_line_r1.png')
module.EYE_LINE_L_2 = Material('models/ppm/partrender/eye_line_l2.png')
module.EYE_LINE_R_2 = Material('models/ppm/partrender/eye_line_r2.png')
module.PONY_SOCKS = Material('models/ppm/texclothes/pony_socks.png')

module.LIPS = Material('models/ppm/partrender/lips.png')
module.NOSE = Material('models/ppm/partrender/nose.png')

module.EYE_CORNERA = Material('models/ppm/eyes/eye_cornea')
module.EYE_CORNERA_OVAL = Material('models/ppm/eyes/eye_cornea_oval')
module.EYE_EXTRA = Material('models/ppm/eyes/eye_extra')
module.EYE_EXTRA2 = Material('models/ppm/eyes/eye_extra2')
module.EYE_LIGHTWARP = Material('models/ppm/eyes/eye_lightwarp')
module.EYE_REFLECTION2 = Material('models/ppm/eyes/eye_reflection')

PPM2.MaterialsRegistry = module
return module

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

PPM2.USE_HIGHRES_BODY = CreateConVar('ppm2_cl_hires_body', '0', {FCVAR_ACRHIVE}, 'Use high resoluation when rendering pony bodies. AFFECTS ONLY TEXTURE COMPILATION TIME (increases lag spike on pony data load)')
PPM2.USE_HIGHRES_TEXTURES = CreateConVar('ppm2_cl_hires_generic', '0', {FCVAR_ACRHIVE}, 'Create 1024x1024 textures instead of 512x512 on texture compiling')

RELOADABLE_MATERIALS = {}
PPM2.RELOADABLE_MATERIALS = RELOADABLE_MATERIALS
concommand.Add 'ppm2_reload_materials', ->
    cTime = SysTime()
    for mat in *RELOADABLE_MATERIALS
        if texname = mat\GetString('$basetexture')
            mat\SetTexture('$basetexture', texname)
        if texture = mat\GetTexture('$basetexture')
            texture\Download()
        mat\Recompute()
    PPM2.PonyTextureController.URL_MATERIAL_CACHE = {}
    PPM2.Message('Reloaded textures in ', math.floor((SysTime() - cTime) * 100000) / 100, ' milliseconds. Do not forget to ppm2_reload and ppm2_require now!')

_Material = Material
_CreateMaterial = CreateMaterial
Material = (path) ->
    matNew, time = _Material(path)
    table.insert(RELOADABLE_MATERIALS, matNew)
    return matNew, time

CreateMaterial = (name, shader, data) ->
    matNew, time = _CreateMaterial(name, shader, data)
    table.insert(RELOADABLE_MATERIALS, matNew)
    return matNew, time

module = {
    BODY_DETAILS: {
        Material('models/ppm/partrender/body_leggrad1')
        Material('models/ppm/partrender/body_lines1')
        Material('models/ppm/partrender/body_stripes1')
        Material('models/ppm/partrender/body_headstripes1')
        Material('models/ppm/partrender/body_freckles')
        Material('models/ppm/partrender/body_hooves1')
        Material('models/ppm/partrender/body_hooves2')
        Material('models/ppm/partrender/body_headmask1')
        Material('models/ppm/partrender/body_hooves1_crit')
        Material('models/ppm/partrender/body_hooves2_crit')
        Material('models/ppm/partrender/body_spots1')
        Material('models/ppm/partrender/body_robotic')
        Material('models/ppm/partrender/dash-e')
        Material('models/ppm/partrender/eye_scar')
        Material('models/ppm/partrender/eye_wound')
        Material('models/ppm/partrender/body_scar')
        Material('models/ppm/partrender/gear_socks')
        Material('models/ppm/partrender/sharp_hooves')
        Material('models/ppm/partrender/sharp_hooves2')
        Material('models/ppm/partrender/separated_muzzle')
        Material('models/ppm/partrender/eye_scar_left')
        Material('models/ppm/partrender/eye_scar_right')
    }

    UPPER_MANE_DETAILS: {
        [4]: {Material('models/ppm/partrender/upmane_5_mask0')}
        [5]: {Material('models/ppm/partrender/upmane_6_mask0')}
        [7]: {Material('models/ppm/partrender/upmane_8_mask0'), Material('models/ppm/partrender/upmane_8_mask1')}
        [8]: {Material('models/ppm/partrender/upmane_9_mask0'), Material('models/ppm/partrender/upmane_9_mask1'), Material('models/ppm/partrender/upmane_9_mask2')}
        [9]: {Material('models/ppm/partrender/upmane_10_mask0')}
        [10]: {Material('models/ppm/partrender/upmane_11_mask0'), Material('models/ppm/partrender/upmane_11_mask1'), Material('models/ppm/partrender/upmane_11_mask2')}
        [11]: {Material('models/ppm/partrender/upmane_12_mask0')}
        [12]: {Material('models/ppm/partrender/upmane_13_mask0')}
        [13]: {Material('models/ppm/partrender/upmane_14_mask0')}
        [14]: {Material('models/ppm/partrender/upmane_15_mask0')}
    }

    LOWER_MANE_DETAILS: {
        [4]: {Material('models/ppm/partrender/dnmane_5_mask0')}
        [7]: {Material('models/ppm/partrender/dnmane_8_mask0'), Material('models/ppm/partrender/dnmane_8_mask1')}
        [8]: {Material('models/ppm/partrender/dnmane_9_mask0'), Material('models/ppm/partrender/dnmane_9_mask1')}
        [9]: {Material('models/ppm/partrender/dnmane_10_mask0'), Material('models/ppm/partrender/dnmane_10_mask1'), Material('models/ppm/partrender/dnmane_10_mask2')}
        [10]: {Material('models/ppm/partrender/dnmane_11_mask0'), Material('models/ppm/partrender/dnmane_11_mask1')}
        [11]: {Material('models/ppm/partrender/dnmane_12_mask0')}
    }

    TAIL_DETAILS: {
        [4]: {Material('models/ppm/partrender/tail_5_mask0')}
        [7]: {Material('models/ppm/partrender/tail_8_mask0'), Material('models/ppm/partrender/tail_8_mask1'), Material('models/ppm/partrender/tail_8_mask2'), Material('models/ppm/partrender/tail_8_mask3'), Material('models/ppm/partrender/tail_8_mask4')}
        [9]: {Material('models/ppm/partrender/tail_10_mask0')}
        [10]: {Material('models/ppm/partrender/tail_11_mask0'), Material('models/ppm/partrender/tail_11_mask1'), Material('models/ppm/partrender/tail_11_mask2')}
        [11]: {Material('models/ppm/partrender/tail_12_mask0'), Material('models/ppm/partrender/tail_12_mask1')}
        [12]: {Material('models/ppm/partrender/tail_13_mask0')}
        [13]: {Material('models/ppm/partrender/tail_14_mask0')}
    }

    SOCKS_PATCHS: {
        'models/props_pony/ppm/ppm_socks/socks_striped_unlit'
        'models/props_pony/ppm/ppm_socks/custom/geometric1_1'
        'models/props_pony/ppm/ppm_socks/custom/geometric2_1'
        'models/props_pony/ppm/ppm_socks/custom/geometric3_1'
        'models/props_pony/ppm/ppm_socks/custom/geometric4_1'
        'models/props_pony/ppm/ppm_socks/custom/geometric5_1'
        'models/props_pony/ppm/ppm_socks/custom/geometric6_1'
        'models/props_pony/ppm/ppm_socks/custom/geometric7_1'
        'models/props_pony/ppm/ppm_socks/custom/geometric8_1'
        'models/props_pony/ppm/ppm_socks/custom_textured/dark1'
        'models/props_pony/ppm/ppm_socks/custom_textured/flowers10'
        'models/props_pony/ppm/ppm_socks/custom_textured/flowers11'
        'models/props_pony/ppm/ppm_socks/custom_textured/flowers12'
        'models/props_pony/ppm/ppm_socks/custom_textured/flowers13'
        'models/props_pony/ppm/ppm_socks/custom_textured/flowers14'
        'models/props_pony/ppm/ppm_socks/custom_textured/flowers15'
        'models/props_pony/ppm/ppm_socks/custom_textured/flowers16'
        'models/props_pony/ppm/ppm_socks/custom_textured/flowers17'
        'models/props_pony/ppm/ppm_socks/custom_textured/flowers18'
        'models/props_pony/ppm/ppm_socks/custom_textured/flowers19'
        'models/props_pony/ppm/ppm_socks/custom_textured/flowers2'
        'models/props_pony/ppm/ppm_socks/custom_textured/flowers20'
        'models/props_pony/ppm/ppm_socks/custom_textured/flowers3'
        'models/props_pony/ppm/ppm_socks/custom_textured/flowers4'
        'models/props_pony/ppm/ppm_socks/custom_textured/flowers5'
        'models/props_pony/ppm/ppm_socks/custom_textured/flowers6'
        'models/props_pony/ppm/ppm_socks/custom_textured/flowers7'
        'models/props_pony/ppm/ppm_socks/custom_textured/flowers8'
        'models/props_pony/ppm/ppm_socks/custom_textured/flowers9'
        'models/props_pony/ppm/ppm_socks/custom_textured/grey1'
        'models/props_pony/ppm/ppm_socks/custom_textured/grey2'
        'models/props_pony/ppm/ppm_socks/custom_textured/grey3'
        'models/props_pony/ppm/ppm_socks/custom_textured/hearts1'
        'models/props_pony/ppm/ppm_socks/custom_textured/hearts2'
        'models/props_pony/ppm/ppm_socks/custom_textured/snow1'
        'models/props_pony/ppm/ppm_socks/custom_textured/wallpaper1'
        'models/props_pony/ppm/ppm_socks/custom_textured/wallpaper2'
        'models/props_pony/ppm/ppm_socks/custom_textured/wallpaper3'
    }

    SOCKS_DETAILS_PATCHS: {
        [2]: {
            'models/props_pony/ppm/ppm_socks/custom/geometric1_4'
            'models/props_pony/ppm/ppm_socks/custom/geometric1_5'
            'models/props_pony/ppm/ppm_socks/custom/geometric1_6'
        }

        [3]: {
            'models/props_pony/ppm/ppm_socks/custom/geometric2_3'
            'models/props_pony/ppm/ppm_socks/custom/geometric2_4'
        }

        [4]: {
            'models/props_pony/ppm/ppm_socks/custom/geometric3_2'
            'models/props_pony/ppm/ppm_socks/custom/geometric3_3'
            'models/props_pony/ppm/ppm_socks/custom/geometric3_5'
        }

        [5]: {
            'models/props_pony/ppm/ppm_socks/custom/geometric4_2'
            'models/props_pony/ppm/ppm_socks/custom/geometric4_3'
            'models/props_pony/ppm/ppm_socks/custom/geometric4_4'
        }

        [6]: {
            'models/props_pony/ppm/ppm_socks/custom/geometric5_4'
            'models/props_pony/ppm/ppm_socks/custom/geometric5_5'
            'models/props_pony/ppm/ppm_socks/custom/geometric5_6'
        }

        [7]: {
            'models/props_pony/ppm/ppm_socks/custom/geometric6_2'
            'models/props_pony/ppm/ppm_socks/custom/geometric6_3'
            'models/props_pony/ppm/ppm_socks/custom/geometric6_4'
        }

        [8]: {
            'models/props_pony/ppm/ppm_socks/custom/geometric7_3'
            'models/props_pony/ppm/ppm_socks/custom/geometric7_4'
        }

        [9]: {
            'models/props_pony/ppm/ppm_socks/custom/geometric8_2'
            'models/props_pony/ppm/ppm_socks/custom/geometric8_3'
        }
    }
}

module.SOCKS_MATERIALS = [Material(id) for id in *module.SOCKS_PATCHS]
module.SOCKS_DETAILS = [Material(id) for id in *module.SOCKS_DETAILS_PATCHS]
module.CUTIEMARKS = [CreateMaterial("PPM2_CMarkDraw_#{mark}", 'UnlitGeneric', {'$basetexture': "models/ppm/cmarks/#{mark}", '$ignorez': 1, '$vertexcolor': 1, '$vertexalpha': 1, '$nolod': 1}) for mark in *PPM2.DefaultCutiemarks]
module.SUITS = [Material("models/ppm/texclothes/#{mat}") for mat in *{
    'clothes_royalguard', 'clothes_sbs_full'
    'clothes_sbs_light', 'clothes_wbs_full'
    'clothes_wbs_light', 'spidermane_light'
    'spidermane_full'
}]

additionTable = (...) ->
    tab = {'$ignorez': 1, '$vertexcolor': 1, '$vertexalpha': 1, '$nolod': 1}
    args = {...}
    for i = 1, #args, 2
        key, val = args[i], args[i + 1]
        tab[key] = val
    return tab

module.TATTOOS = [Material("models/ppm/partrender/tattoo/#{fil\lower()}") for fil in *PPM2.TATTOOS_REGISTRY when fil ~= 'NONE']
debugwhite = {
    '$basetexture': 'models/debug/debugwhite'
    '$ignorez': 1
    '$vertexcolor': 1
    '$vertexalpha': 1
    '$nolod': 1
}

module.EYE_OVALS = {
    Material('models/ppm/partrender/eye_oval')
    Material('models/ppm/partrender/eye_oval_aperture')
}

module.DEBUGWHITE = CreateMaterial('PPM2.Debugwhite', 'UnlitGeneric', debugwhite)
module.HAIR_MATERIAL_COLOR = CreateMaterial('PPM2.ManeTextureBase', 'UnlitGeneric', debugwhite)
module.TAIL_MATERIAL_COLOR = CreateMaterial('PPM2.TailTextureBase', 'UnlitGeneric', debugwhite)
module.WINGS_MATERIAL_COLOR = CreateMaterial('PPM2.WingsMaterialBase', 'UnlitGeneric', debugwhite)
module.HORN_MATERIAL_COLOR = CreateMaterial('PPM2.HornMaterialBase', 'UnlitGeneric', additionTable('$basetexture', 'models/ppm/base/horn'))
module.BODY_MATERIAL = CreateMaterial('PPM2.BodyTexture', 'UnlitGeneric', additionTable('$basetexture', 'models/ppm/base/body'))
module.HORN_DETAIL_BUMP = CreateMaterial('PPM2.HornBumpMapRenderer', 'UnlitGeneric', additionTable('$basetexture', 'models/ppm/base/horn_normal'))
module.HORN_DETAIL_COLOR = Material('models/ppm/partrender/horn_detail')
module.EYE_OVAL = Material('models/ppm/partrender/eye_oval')
module.EYE_GRAD = Material('models/ppm/partrender/eye_grad')
module.EYE_EFFECT = Material('models/ppm/partrender/eye_effect')
module.EYE_REFLECTION = Material('models/ppm/partrender/eye_reflection')
module.EYE_LINE_L_1 = Material('models/ppm/partrender/eye_line_l1')
module.EYE_LINE_R_1 = Material('models/ppm/partrender/eye_line_r1')
module.EYE_LINE_L_2 = Material('models/ppm/partrender/eye_line_l2')
module.EYE_LINE_R_2 = Material('models/ppm/partrender/eye_line_r2')
module.PONY_SOCKS = Material('models/ppm/texclothes/pony_socks')

module.LIPS = Material('models/ppm/partrender/lips')
module.NOSE = Material('models/ppm/partrender/nose')

module.EYE_CORNERA = Material('models/ppm/eyes/eye_cornea')
module.EYE_CORNERA_OVAL = Material('models/ppm/eyes/eye_cornea_oval')
module.EYE_EXTRA = Material('models/ppm/eyes/eye_extra')
module.EYE_EXTRA2 = Material('models/ppm/eyes/eye_extra2')
module.EYE_LIGHTWARP = Material('models/ppm/eyes/eye_lightwarp')
module.EYE_REFLECTION2 = Material('models/ppm/eyes/eye_reflection')

PPM2.MaterialsRegistry = module
return module