ircsnap: cleanup

ircsnap: cleanup

{:urlEncode} = require'util'
html2unicode = require 'html'
lfs = require'lfs'

hex_to_char = (x) ->
  string.char(tonumber(x, 16))

unescape = (url) ->
  url\gsub("%%(%x%x)", hex_to_char)

-- All URLs in this module is under this prefix
urlbase = '/image/'

safe = (fn) ->
  f, ext = fn\match'^(.*)%.(.-)$'
  f = f\gsub '[^%w%-]', ''
  return f..'.'..ext

video_html = (video) ->
  videourl = ivar2.config.webserverprefix..urlbase..'file/'..video
  [[
  <!DOCTYPE html>

  <meta charset="utf-8">

    <video id="v" src="]]..videourl..[[" controls autoplay loop>
      Your browser does not support the video element.
      Try the direct link to the video: video
    </video>

    <button onclick="rotate(90)">Rotate ⟳</button>
    <button onclick="rotate(-90)">Rotate ⟲</button>

  ]]

ivar2.webserver.regUrl "#{urlbase}(.*)$", (req, res) =>
  url = req.url
  send = (body, code, content_type) ->
    if not code then code = "200"
    if not content_type then content_type = 'text/html'
    res\append ':status', code
    res\append 'Content-Type', content_type
    res\append 'Content-Length', tostring(#body)
    req\write_headers(res, false, 30)
    req\write_body_from_string(body, 30)
    return -- empty return

  file = url\match '/file/(.*)$'
  if file
    fn = "cache/images/#{safe file}"
    size = lfs.attributes(fn).size
    --body = fd\read '*a'
    content_type = 'image/jpeg'
    if file\lower!\match '.png'
      content_type = 'image/png'
    if file\lower!\match '.svg'
      content_type = 'image/svg'
    if file\lower!\match '.mp4'
      content_type = 'video/mp4'
    if file\lower!\match '.mov'
      content_type = 'video/quicktime'
    if file\lower!\match '.mp3'
      content_type = 'audio/mp3'

    res\append ':status', '200'
    res\append 'Content-Type', content_type
    res\append 'Content-Length', tostring(size)
    req\write_headers(res, false, 30)
    fd = io.open(fn, 'rb')
    req\write_body_from_file(fd, 5*60)
    fd\close!
    return

  -- Serve video player page
  video = url\match '/video/(.*)$'
  if video then
    send video_html(video)
    return

  channel = url\match('channel=(.+)%s*')
  unless channel
    send 'Invalid channel', 404
    return

  channel = html2unicode channel
  unescaped_channel = unescape channel

  html = [[
  <!DOCTYPE html>

  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=Edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
  <meta name="mobile-web-app-capable" content="yes">
  <meta name="apple-mobile-web-app-status-bar-style" content="black">
  <meta name="apple-mobile-web-app-title" content="IRCSNAP ]]..unescaped_channel..[[">
  <meta name="theme-color" content="#8f4099">

  <title>IRCSNAP ]]..unescaped_channel..[[</title>

Share to IRC app - ]]..unescaped_channel..[[ edition

Fill in your nick/name and optional text and then click on one of the yellow buttons to attach image. It will appear instantly on IRC!

    <form>

        <input id="sender" type="text" required>

        Your nickname

        <input id="text" type="text" required>

        Attach text, if you want

    </form>

Uploading. Percent complete: 0 %

      📷 Snap picture! <input type="file" accept="image/*" id="capturei" capture="camera" style="visibility:hidden;">
      📂 Browse gallery! <input type="file" accept="image/*" id="capturef" style="visibility:hidden;">
      🎥 Capture video! <input type="file" accept="video/*" capture="camcorder" id="capturev" style="visibility:hidden;">
      🎥 Upload video! <input type="file" accept="video/*" id="capturevf" style="visibility:hidden;">

You can also drag and drop here, or paste clipboard data, but beware, it will not ask for confirmation before uploading!!!

      <form class="box" method="post" action="" enctype="multipart/form-data">

          <input id="box__dropi" class="box__file" type="file" name="files[]" id="file" data-multiple-caption="{count} files selected" multiple />
          Drag a file here.

Uploading…

Done!

Error! .

      </form>

      What is this?

Share to IRC is a simple web app for sharing media directly from your device to an IRC channel.

Click Tools ->  Add to homescreen to create a convenient shortcut for easy and fast access to sharing

Made by xt

  ]]
  if req.method == 'POST'
    fn = req.headers['x-filename']
    sender = req.headers['x-sender'] or ''
    text = req.headers['x-text'] or ''
    file = req.filename
    ivar2\Log 'info', "imageupload: Recieved file name: <#{fn}> datalen: #{#file}, sender: <#{sender}> text: <#{text}>, channel: <#{unescaped_channel}>"
    if fn and file
      html = 'Ok'
      realfn = "#{os.time!}-#{safe fn}"
      save = ->
        -- Move tempfile to real location
        os.rename req.filename, "cache/images/#{realfn}"
        if sender ~= ''
          sender = "<#{sender\sub(1, 100)}> "
        if text ~= ''
          text = text\sub(1, 100) .. ' '
        file_or_video = 'file'
        if realfn\match '%.mp4$'
          file_or_video = 'video'
        msg = "[IRCSNAP] #{sender}#{text}#{ivar2.config.webserverprefix}#{urlbase}#{file_or_video}/#{realfn}"
        ivar2\Privmsg unescaped_channel, msg
      ok, err = pcall(save)
      unless ok
        ivar2\Log 'error', "imageupload: Error during saving upload: %s", err
    else
      html = 'Not OK'

  send html

-- Attempt to create the cache folder.
lfs.mkdir('cache/images')

PRIVMSG:
  '^%pircsnap$': (source, destination) =>
    channel = urlEncode destination
    say "#{ivar2.config.webserverprefix}#{urlbase}?channel=#{channel} IRCSNAP - sharing is caring."


Fixed flight animation in ppm2 flight

Fixed flight animation in ppm2 flight

--
-- 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.')
FORCE_ALLOW_FLIGHT = CreateConVar('ppm2_sv_flight_force', '0', {FCVAR_ARCHIVE, FCVAR_REPLICATED, FCVAR_NOTIFY}, 'Ignore PlayerNoClip hook')
FLIGHT_DAMAGE = CreateConVar('ppm2_sv_flightdmg', '1', {FCVAR_ARCHIVE, FCVAR_REPLICATED, FCVAR_NOTIFY}, 'Damage players in flight')

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) =>
        nativeEntity = @ent\GetEntity()
        mvPos = movedata\GetOrigin()
        pos = nativeEntity\GetPos()
        rpos = pos
        tryMove = util.TraceHull({
            filter: (ent) ->
                return false if nativeEntity == 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
            nativeEntity\SetPos(mvPos)
        else
            if IsValid(tryMove.Entity)
                newVelocity = Vector(0, 0, 0)
                movedata\SetVelocity(newVelocity)
                newPos = tryMove.HitPos + tryMove.HitNormal
                nativeEntity\SetPos(newPos)
                movedata\SetOrigin(newPos)
            else
                newVelocity = velocity - tryMove.HitNormal * velocity\Dot(tryMove.HitNormal * 1.1)
                movedata\SetVelocity(newVelocity)
                newPos = tryMove.HitPos + tryMove.HitNormal
                nativeEntity\SetPos(newPos)
                movedata\SetOrigin(newPos)
            if length > 7 and SERVER and FLIGHT_DAMAGE\GetBool()
                dmgInfo = DamageInfo()
                dmgInfo\SetAttacker(nativeEntity)
                dmgInfo\SetInflictor(nativeEntity)
                dmgInfo\SetDamageType(DMG_CRUSH)
                calcDamage = math.Clamp((length / 4) ^ 2, 1, 100)
                if calcDamage >= 100
                    nativeEntity\EmitSound('physics/flesh/flesh_bloody_break.wav', 100)
                elseif calcDamage > 70
                    nativeEntity\EmitSound('physics/flesh/flesh_bloody_break.wav', 100)
                elseif calcDamage > 50
                    nativeEntity\EmitSound("physics/body/body_medium_break#{math.random(2, 4)}.wav", 75)
                elseif calcDamage > 25
                    nativeEntity\EmitSound("physics/body/body_medium_impact_hard#{math.random(1, 6)}.wav", 75)
                elseif calcDamage > 10
                    nativeEntity\EmitSound("physics/body/body_medium_impact_soft#{math.random(1, 7)}.wav", 75)
                else
                    nativeEntity\EmitSound("physics/flesh/flesh_impact_bullet#{math.random(1, 5)}.wav", 75)
                dmgInfo\SetDamage(calcDamage)
                nativeEntity\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 @IsNewPonyCached()
    if data = @GetPonyData()
        if data\GetFly()
            if not @isPlayingPPM2Anim
                @isPlayingPPM2Anim = true
                @AnimRestartGesture(GESTURE_SLOT_CUSTOM, ACT_GMOD_NOCLIP_LAYER, false)
                @SetIK(false) if CLIENT
            return ACT_GMOD_NOCLIP_LAYER, 370
        else
            if @isPlayingPPM2Anim
                @isPlayingPPM2Anim = false
                @AnimResetGestureSlot(GESTURE_SLOT_CUSTOM)
                @SetIK(true) if CLIENT

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()
            return data\SetFly(false) if FORCE_ALLOW_FLIGHT\GetBool()
            can = hook.Run('PlayerNoClip', @, false) or hook.Run('PPM2Fly', @, false)
            data\SetFly(false) if can
        else
            return if data\GetRace() ~= PPM2.RACE_PEGASUS and data\GetRace() ~= PPM2.RACE_ALICORN
            return data\SetFly(true) if FORCE_ALLOW_FLIGHT\GetBool()
            can = hook.Run('PlayerNoClip', @, true) or hook.Run('PPM2Fly', @, true)
            data\SetFly(true) if can
else
    lastDouble = 0
    lastMessage = 0
    lastMessage2 = 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
                if lastMessage < RealTime()
                    lastMessage = RealTime() + 1
                    PPM2.ChatPrint('You need to be a Pegasus or an Alicorn to fly!')
                return
            can = hook.Run('PlayerNoClip', @, not data\GetFly()) or hook.Run('PPM2Fly', @, not data\GetFly())
            if not can
                if lastMessage2 < RealTime()
                    lastMessage2 = RealTime() + 1
                    PPM2.ChatPrint("You can not #{data\GetFly() and 'land' or 'fly'} right now.")
                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.')
FORCE_ALLOW_FLIGHT = CreateConVar('ppm2_sv_flight_force', '0', {FCVAR_ARCHIVE, FCVAR_REPLICATED, FCVAR_NOTIFY}, 'Ignore PlayerNoClip hook')
FLIGHT_DAMAGE = CreateConVar('ppm2_sv_flightdmg', '1', {FCVAR_ARCHIVE, FCVAR_REPLICATED, FCVAR_NOTIFY}, 'Damage players in flight')

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) =>
        nativeEntity = @ent\GetEntity()
        mvPos = movedata\GetOrigin()
        pos = nativeEntity\GetPos()
        rpos = pos
        tryMove = util.TraceHull({
            filter: (ent) ->
                return false if nativeEntity == 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
            nativeEntity\SetPos(mvPos)
        else
            if IsValid(tryMove.Entity)
                newVelocity = Vector(0, 0, 0)
                movedata\SetVelocity(newVelocity)
                newPos = tryMove.HitPos + tryMove.HitNormal
                nativeEntity\SetPos(newPos)
                movedata\SetOrigin(newPos)
            else
                newVelocity = velocity - tryMove.HitNormal * velocity\Dot(tryMove.HitNormal * 1.1)
                movedata\SetVelocity(newVelocity)
                newPos = tryMove.HitPos + tryMove.HitNormal
                nativeEntity\SetPos(newPos)
                movedata\SetOrigin(newPos)
            if length > 7 and SERVER and FLIGHT_DAMAGE\GetBool()
                dmgInfo = DamageInfo()
                dmgInfo\SetAttacker(nativeEntity)
                dmgInfo\SetInflictor(nativeEntity)
                dmgInfo\SetDamageType(DMG_CRUSH)
                calcDamage = math.Clamp((length / 4) ^ 2, 1, 100)
                if calcDamage >= 100
                    nativeEntity\EmitSound('physics/flesh/flesh_bloody_break.wav', 100)
                elseif calcDamage > 70
                    nativeEntity\EmitSound('physics/flesh/flesh_bloody_break.wav', 100)
                elseif calcDamage > 50
                    nativeEntity\EmitSound("physics/body/body_medium_break#{math.random(2, 4)}.wav", 75)
                elseif calcDamage > 25
                    nativeEntity\EmitSound("physics/body/body_medium_impact_hard#{math.random(1, 6)}.wav", 75)
                elseif calcDamage > 10
                    nativeEntity\EmitSound("physics/body/body_medium_impact_soft#{math.random(1, 7)}.wav", 75)
                else
                    nativeEntity\EmitSound("physics/flesh/flesh_impact_bullet#{math.random(1, 5)}.wav", 75)
                dmgInfo\SetDamage(calcDamage)
                nativeEntity\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()
            return data\SetFly(false) if FORCE_ALLOW_FLIGHT\GetBool()
            can = hook.Run('PlayerNoClip', @, false) or hook.Run('PPM2Fly', @, false)
            data\SetFly(false) if can
        else
            return if data\GetRace() ~= PPM2.RACE_PEGASUS and data\GetRace() ~= PPM2.RACE_ALICORN
            return data\SetFly(true) if FORCE_ALLOW_FLIGHT\GetBool()
            can = hook.Run('PlayerNoClip', @, true) or hook.Run('PPM2Fly', @, true)
            data\SetFly(true) if can
else
    lastDouble = 0
    lastMessage = 0
    lastMessage2 = 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
                if lastMessage < RealTime()
                    lastMessage = RealTime() + 1
                    PPM2.ChatPrint('You need to be a Pegasus or an Alicorn to fly!')
                return
            can = hook.Run('PlayerNoClip', @, not data\GetFly()) or hook.Run('PPM2Fly', @, not data\GetFly())
            if not can
                if lastMessage2 < RealTime()
                    lastMessage2 = RealTime() + 1
                    PPM2.ChatPrint("You can not #{data\GetFly() and 'land' or 'fly'} right now.")
                return
            RunConsoleCommand('ppm2_fly')
            lastDouble = 0
            return
        lastDouble = RealTime() + 0.2


Removed include

Removed include

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

export PPM2
PPM2 = PPM2 or {}

player_manager.AddValidModel('pony', 'models/ppm/player_default_base_new.mdl')
list.Set('PlayerOptionsModel', 'pony', 'models/ppm/player_default_base_new.mdl')

player_manager.AddValidModel('ponynj', 'models/ppm/player_default_base_new_nj.mdl')
list.Set('PlayerOptionsModel', 'ponynj', 'models/ppm/player_default_base_new_nj.mdl')

player_manager.AddValidModel('ponynj_old', 'models/ppm/player_default_base_nj.mdl')
list.Set('PlayerOptionsModel', 'ponynj_old', 'models/ppm/player_default_base_nj.mdl')

player_manager.AddValidModel('pony_old', 'models/ppm/player_default_base.mdl')
list.Set('PlayerOptionsModel', 'pony_old', 'models/ppm/player_default_base.mdl')

player_manager.AddValidModel('pony_cppm', 'models/cppm/player_default_base.mdl')
list.Set('PlayerOptionsModel', 'pony_cppm', 'models/cppm/player_default_base.mdl')

player_manager.AddValidModel('ponynj_cppm', 'models/cppm/player_default_base_nj.mdl')
list.Set('PlayerOptionsModel', 'ponynj_cppm', 'models/cppm/player_default_base_nj.mdl')

player_manager.AddValidHands(model, 'models/cppm/pony_arms.mdl', 0, '') for model in *{'pony', 'pony_cppm', 'ponynj', 'ponynj_cppm', 'pony_old'}

include 'autorun/strong_entity_link.lua' if not StrongEntity

include_ = include
AddCSLuaFile_ = AddCSLuaFile
include = (f) -> include_("autorun/ppm2/#{f}")
AddCSLuaFile = (f) -> AddCSLuaFile_("autorun/ppm2/#{f}")

include 'common/networked_object.lua'
include 'common/registry.lua'
include 'common/functions.lua'
include 'common/hooks.lua'
include 'common/bodygroup_controller.lua'
include 'common/weight_controller.lua'
include 'common/flex_controller.lua'
include 'common/ponydata.lua'
include 'common/emotes.lua'
include 'common/ponyfly.lua'
include 'common/size_controller.lua'

if CLIENT
    PPM2.ALTERNATIVE_RENDER = CreateConVar('ppm2_alternative_render', '0', {FCVAR_ARCHIVE}, 'Enable alternative render mode. This decreases FPS, enables compability with third-party BROKEN addons.')
    file.CreateDir('ppm2')
    file.CreateDir('ppm2/backups')
    include 'client/data_instance.lua'
    include 'client/texture_controller.lua'
    include 'client/hooks.lua'
    include 'client/render_controller.lua'
    include 'client/emotes.lua'
    include 'client/player_menu.lua'
    include 'client/editor.lua'
    include 'client/rag_edit.lua'
    include 'client/pac3_patch.lua'

    for ent in *ents.GetAll()
        if ent.isPonyLegsModel
            ent\Remove()
else
    resource.AddWorkshop('933203381')

    util.AddNetworkString('PPM2.RequestPonyData')
    util.AddNetworkString('PPM2.PlayerRespawn')
    util.AddNetworkString('PPM2.PlayerDeath')
    util.AddNetworkString('PPM2.PostPlayerDeath')
    util.AddNetworkString('PPM2.Require')
    util.AddNetworkString('PPM2.EditorStatus')
    util.AddNetworkString('PPM2.NotifyDisconnect')
    util.AddNetworkString('PPM2.PonyDataRemove')
    util.AddNetworkString('PPM2.RagdollEdit')
    util.AddNetworkString('PPM2.RagdollEditFlex')
    util.AddNetworkString('PPM2.RagdollEditEmote')

    AddCSLuaFile 'common/networked_object.lua'
    AddCSLuaFile 'common/registry.lua'
    AddCSLuaFile 'common/ponydata.lua'
    AddCSLuaFile 'common/hooks.lua'
    AddCSLuaFile 'common/bodygroup_controller.lua'
    AddCSLuaFile 'common/weight_controller.lua'
    AddCSLuaFile 'common/flex_controller.lua'
    AddCSLuaFile 'common/functions.lua'
    AddCSLuaFile 'common/emotes.lua'
    AddCSLuaFile 'common/ponyfly.lua'
    AddCSLuaFile 'common/size_controller.lua'
    AddCSLuaFile 'client/data_instance.lua'
    AddCSLuaFile 'client/texture_controller.lua'
    AddCSLuaFile 'client/hooks.lua'
    AddCSLuaFile 'client/render_controller.lua'
    AddCSLuaFile 'client/editor.lua'
    AddCSLuaFile 'client/emotes.lua'
    AddCSLuaFile 'client/player_menu.lua'
    AddCSLuaFile 'client/rag_edit.lua'
    AddCSLuaFile 'client/pac3_patch.lua'
    include 'server/hooks.lua'
    include 'server/emotes.lua'
    include 'server/hitgroups.lua'
    include 'server/rag_edit.lua'

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

export PPM2
PPM2 = PPM2 or {}

player_manager.AddValidModel('pony', 'models/ppm/player_default_base_new.mdl')
list.Set('PlayerOptionsModel', 'pony', 'models/ppm/player_default_base_new.mdl')

player_manager.AddValidModel('ponynj', 'models/ppm/player_default_base_new_nj.mdl')
list.Set('PlayerOptionsModel', 'ponynj', 'models/ppm/player_default_base_new_nj.mdl')

player_manager.AddValidModel('ponynj_old', 'models/ppm/player_default_base_nj.mdl')
list.Set('PlayerOptionsModel', 'ponynj_old', 'models/ppm/player_default_base_nj.mdl')

player_manager.AddValidModel('pony_old', 'models/ppm/player_default_base.mdl')
list.Set('PlayerOptionsModel', 'pony_old', 'models/ppm/player_default_base.mdl')

player_manager.AddValidModel('pony_cppm', 'models/cppm/player_default_base.mdl')
list.Set('PlayerOptionsModel', 'pony_cppm', 'models/cppm/player_default_base.mdl')

player_manager.AddValidModel('ponynj_cppm', 'models/cppm/player_default_base_nj.mdl')
list.Set('PlayerOptionsModel', 'ponynj_cppm', 'models/cppm/player_default_base_nj.mdl')

player_manager.AddValidHands(model, 'models/cppm/pony_arms.mdl', 0, '') for model in *{'pony', 'pony_cppm', 'ponynj', 'ponynj_cppm', 'pony_old'}

include 'autorun/strong_entity_link.lua' if not StrongEntity

include_ = include
AddCSLuaFile_ = AddCSLuaFile
include = (f) -> include_("autorun/ppm2/#{f}")
AddCSLuaFile = (f) -> AddCSLuaFile_("autorun/ppm2/#{f}")

include 'common/networked_object.lua'
include 'common/registry.lua'
include 'common/functions.lua'
include 'common/hooks.lua'
include 'common/bodygroup_controller.lua'
include 'common/weight_controller.lua'
include 'common/flex_controller.lua'
include 'common/ponydata.lua'
include 'common/emotes.lua'
include 'common/ponyfly.lua'
include 'common/size_controller.lua'

if CLIENT
    PPM2.ALTERNATIVE_RENDER = CreateConVar('ppm2_alternative_render', '0', {FCVAR_ARCHIVE}, 'Enable alternative render mode. This decreases FPS, enables compability with third-party BROKEN addons.')
    file.CreateDir('ppm2')
    file.CreateDir('ppm2/backups')
    include 'client/data_instance.lua'
    include 'client/texture_controller.lua'
    include 'client/hooks.lua'
    include 'client/render_controller.lua'
    include 'client/emotes.lua'
    include 'client/player_menu.lua'
    include 'client/editor.lua'
    include 'client/rag_edit.lua'
    include 'client/pac3_patch.lua'

    for ent in *ents.GetAll()
        if ent.isPonyLegsModel
            ent\Remove()
else
    resource.AddWorkshop('933203381')

    util.AddNetworkString('PPM2.RequestPonyData')
    util.AddNetworkString('PPM2.PlayerRespawn')
    util.AddNetworkString('PPM2.PlayerDeath')
    util.AddNetworkString('PPM2.PostPlayerDeath')
    util.AddNetworkString('PPM2.Require')
    util.AddNetworkString('PPM2.EditorStatus')
    util.AddNetworkString('PPM2.NotifyDisconnect')
    util.AddNetworkString('PPM2.PonyDataRemove')
    util.AddNetworkString('PPM2.RagdollEdit')
    util.AddNetworkString('PPM2.RagdollEditFlex')
    util.AddNetworkString('PPM2.RagdollEditEmote')

    AddCSLuaFile 'common/networked_object.lua'
    AddCSLuaFile 'common/registry.lua'
    AddCSLuaFile 'common/ponydata.lua'
    AddCSLuaFile 'common/hooks.lua'
    AddCSLuaFile 'common/bodygroup_controller.lua'
    AddCSLuaFile 'common/weight_controller.lua'
    AddCSLuaFile 'common/flex_controller.lua'
    AddCSLuaFile 'common/functions.lua'
    AddCSLuaFile 'common/emotes.lua'
    AddCSLuaFile 'common/ponyfly.lua'
    AddCSLuaFile 'common/size_controller.lua'
    AddCSLuaFile 'client/data_instance.lua'
    AddCSLuaFile 'client/texture_controller.lua'
    AddCSLuaFile 'client/hooks.lua'
    AddCSLuaFile 'client/render_controller.lua'
    AddCSLuaFile 'client/editor.lua'
    AddCSLuaFile 'client/emotes.lua'
    AddCSLuaFile 'client/player_menu.lua'
    AddCSLuaFile 'client/rag_edit.lua'
    AddCSLuaFile 'client/pac3_patch.lua'
    include 'server/hooks.lua'
    include 'server/fastdl.lua'
    include 'server/emotes.lua'
    include 'server/hitgroups.lua'
    include 'server/rag_edit.lua'