Change crypto stub functions in Cookies spec to be isomorphic

require 'moon.all'
Cookies = require 'ngx-oauth.Cookies'
import concat from require 'ngx-oauth.util'

ALL_COOKIES = {'access_token', 'refresh_token', 'username'}

set_cookie = (name, value) ->
  ngx.var['cookie_'..name] = value

describe '__call', ->

  conf =
    client_secret: 'super-top-secret-password'
    cookie_path: '/app'
    cookie_prefix: 'oa_'
    max_age: 600
    aes_bits: 128

  prefix = conf.cookie_prefix
  cookie_attrs = "path=#{conf.cookie_path};secure;version=1"

  setup ->
    _G.pairs = spec_helper.sorted_pairs
    export crypto_stub = mock {
      encrypt: (bits, key, value) -> string.reverse(value)
      decrypt: (bits, key, value) -> string.reverse(value)
    }

  before_each ->
    export cookies = Cookies(conf, crypto_stub)
    _G.ngx = spec_helper.ngx_mock!

  describe 'add_token', ->

    access_token_cookie = (token, max_age = token.expires_in) ->
      "#{prefix}access_token=#{token.access_token};max-age=#{max_age};#{cookie_attrs}"

    it 'does not overwrite content of Set-Cookie', ->
      existing = 'foo=42;path=/'
      _G.ngx.header['Set-Cookie'] = existing
      tkn = { access_token: 'acc-token', expires_in: 42 }

      cookies.add_token(tkn)
      assert.same {existing, access_token_cookie(tkn)}, _G.ngx.header['Set-Cookie']

    context 'with expires_in less than conf.max_age', ->
      tkn = { access_token: 'acc-token', expires_in: conf.max_age / 2 }
      expected = { access_token_cookie(tkn) }

      it "writes cookie with access token and Max-Age equal to token's expires_in", ->
        cookies.add_token(tkn)
        assert.same expected, _G.ngx.header['Set-Cookie']

    context 'with expires_in greater than conf.max_age', ->
      tkn = { access_token: 'acc-token', expires_in: conf.max_age * 2 }
      expected = { access_token_cookie(tkn, conf.max_age) }

      it 'writes cookie with access token and Max-Age equals to conf.max_age', ->
        cookies.add_token(tkn)
        assert.same expected, _G.ngx.header['Set-Cookie']

    context 'with both access and refresh token', ->
      tkn = { access_token: 'acc-token', expires_in: conf.max_age / 2, refresh_token: 'reftok-123' }
      expected = {
        access_token_cookie(tkn),
        "#{prefix}refresh_token=321-kotfer;max-age=#{conf.max_age};#{cookie_attrs}"
      }

      it 'writes cookie with access token and encrypted refresh token', ->
        cookies.add_token(tkn)
        assert.same expected, _G.ngx.header['Set-Cookie']
        assert.stub(crypto_stub.encrypt).called_with(conf.aes_bits, conf.client_secret, tkn.refresh_token)

  describe 'add_username', ->
    expected = { "#{prefix}username=flynn;max-age=#{conf.max_age};#{cookie_attrs}" }

    it 'writes cookies with username and Max-Age equals to conf.max_age', ->
      cookies.add_username('flynn')
      assert.same expected, _G.ngx.header['Set-Cookie']

    it 'does not overwrite existing Set-Cookie', ->
      existing = {'foo=42;path=/', 'bar=55;path=/'}
      _G.ngx.header['Set-Cookie'] = existing

      cookies.add_username('flynn')
      assert.same concat(existing, expected), _G.ngx.header['Set-Cookie']

  describe 'clear_all', ->
    expected = [ "#{prefix}#{name}=deleted;max-age=0;#{cookie_attrs}" for name in *ALL_COOKIES ]

    it 'sets access_token, refresh_token and username cookies to "deleted" and max-age 0', ->
      cookies.clear_all()
      assert.same expected, _G.ngx.header['Set-Cookie']

  describe 'get_access_token', ->

    it 'returns value of access_token cookie', ->
      set_cookie "#{prefix}access_token", 'token-123'
      assert.same 'token-123', cookies.get_access_token()

  describe 'get_refresh_token', ->

    context 'refresh_token cookie exists', ->
      it 'returns decrypted value of the cookie', ->
        set_cookie "#{prefix}refresh_token", '321-kotfer'

        assert.same 'reftok-123', cookies.get_refresh_token()
        assert.stub(crypto_stub.decrypt).called_with(conf.aes_bits, conf.client_secret, '321-kotfer')

    context 'refresh_token cookie does not exist', ->
      it 'returns nil', ->
        assert.is_nil cookies.get_refresh_token()

  describe 'get_username', ->

    it 'returns value of username cookie', ->
      set_cookie "#{prefix}username", 'flynn'
      assert.same 'flynn', cookies.get_username()

require 'moon.all'
Cookies = require 'ngx-oauth.Cookies'
import concat from require 'ngx-oauth.util'

ALL_COOKIES = {'access_token', 'refresh_token', 'username'}

set_cookie = (name, value) ->
  ngx.var['cookie_'..name] = value

describe '__call', ->

  conf =
    client_secret: 'super-top-secret-password'
    cookie_path: '/app'
    cookie_prefix: 'oa_'
    max_age: 600
    aes_bits: 128

  prefix = conf.cookie_prefix
  cookie_attrs = "path=#{conf.cookie_path};secure;version=1"

  setup ->
    _G.pairs = spec_helper.sorted_pairs
    export crypto_stub = mock {
      encrypt: (bits, key, value) -> "~~ENC-#{value}~~"
      decrypt: (bits, key, value) -> "~~DEC-#{value}~~"
    }

  before_each ->
    export cookies = Cookies(conf, crypto_stub)
    _G.ngx = spec_helper.ngx_mock!

  describe 'add_token', ->

    access_token_cookie = (token, max_age = token.expires_in) ->
      "#{prefix}access_token=#{token.access_token};max-age=#{max_age};#{cookie_attrs}"

    it 'does not overwrite content of Set-Cookie', ->
      existing = 'foo=42;path=/'
      _G.ngx.header['Set-Cookie'] = existing
      tkn = { access_token: 'acc-token', expires_in: 42 }

      cookies.add_token(tkn)
      assert.same {existing, access_token_cookie(tkn)}, _G.ngx.header['Set-Cookie']

    context 'token with expires_in less than conf.max_age', ->
      tkn = { access_token: 'acc-token', expires_in: conf.max_age / 2 }
      expected = { access_token_cookie(tkn) }

      it "writes cookie with access token and Max-Age equal to token's expires_in", ->
        cookies.add_token(tkn)
        assert.same expected, _G.ngx.header['Set-Cookie']

    context 'token with expires_in greater than conf.max_age', ->
      tkn = { access_token: 'acc-token', expires_in: conf.max_age * 2 }
      expected = { access_token_cookie(tkn, conf.max_age) }

      it 'writes cookie with access token and Max-Age equals to conf.max_age', ->
        cookies.add_token(tkn)
        assert.same expected, _G.ngx.header['Set-Cookie']

    context 'token with both access and refresh token', ->
      tkn = { access_token: 'acc-token', expires_in: conf.max_age / 2, refresh_token: 'ref-token' }
      expected = {
        access_token_cookie(tkn),
        "#{prefix}refresh_token=~~ENC-#{tkn.refresh_token}~~;max-age=#{conf.max_age};#{cookie_attrs}"
      }

      it 'writes cookie with access token and encrypted refresh token', ->
        cookies.add_token(tkn)
        assert.same expected, _G.ngx.header['Set-Cookie']
        assert.stub(crypto_stub.encrypt).called_with(conf.aes_bits, conf.client_secret, tkn.refresh_token)

  describe 'add_username', ->
    expected = { "#{prefix}username=flynn;max-age=#{conf.max_age};#{cookie_attrs}" }

    it 'writes cookies with username and Max-Age equals to conf.max_age', ->
      cookies.add_username('flynn')
      assert.same expected, _G.ngx.header['Set-Cookie']

    it 'does not overwrite existing Set-Cookie', ->
      existing = {'foo=42;path=/', 'bar=55;path=/'}
      _G.ngx.header['Set-Cookie'] = existing

      cookies.add_username('flynn')
      assert.same concat(existing, expected), _G.ngx.header['Set-Cookie']

  describe 'clear_all', ->
    expected = [ "#{prefix}#{name}=deleted;max-age=0;#{cookie_attrs}" for name in *ALL_COOKIES ]

    it 'sets access_token, refresh_token and username cookies to "deleted" and max-age 0', ->
      cookies.clear_all()
      assert.same expected, _G.ngx.header['Set-Cookie']

  describe 'get_access_token', ->

    it 'returns value of access_token cookie', ->
      set_cookie "#{prefix}access_token", 'token-123'
      assert.same 'token-123', cookies.get_access_token()

  describe 'get_refresh_token', ->

    context 'refresh_token cookie exists', ->
      it 'returns decrypted value of the cookie', ->
        set_cookie "#{prefix}refresh_token", 'token-123'

        assert.same '~~DEC-token-123~~', cookies.get_refresh_token()
        assert.stub(crypto_stub.decrypt).called_with(conf.aes_bits, conf.client_secret, 'token-123')

    context 'refresh_token cookie does not exist', ->
      it 'returns nil', ->
        assert.is_nil cookies.get_refresh_token()

  describe 'get_username', ->

    it 'returns value of username cookie', ->
      set_cookie "#{prefix}username", 'flynn'
      assert.same 'flynn', cookies.get_username()


Fixed legs

Fixed legs

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

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

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

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

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

    @LEGS_BONE_ROOT = 0

    @LEGS_FRONT_1 = 23
    @LEGS_FRONT_2 = 29

    @LEGS_FRONT_3 = 21
    @LEGS_FRONT_4 = 27

    @LEGS_FRONT_5 = 20
    @LEGS_FRONT_6 = 26

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

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

    @NEXT_OBJ_ID = 0

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    SlowUpdate: =>
        @ModifyScale()

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

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

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

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

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

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

    GetLegsModifier: => 1 + (@GetLegsSize() - 1) * .4

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    @LEGS_FRONT_1 = 19
    @LEGS_FRONT_2 = 25

    @LEGS_FRONT_3 = 17
    @LEGS_FRONT_4 = 23

    @LEGS_FRONT_5 = 16
    @LEGS_FRONT_6 = 22

    @LEGS_BEHIND_1_1 = 2
    @LEGS_BEHIND_1_2 = 7

    @LEGS_BEHIND_2_1 = 4
    @LEGS_BEHIND_2_2 = 9

    @LEGS_BEHIND_3_1 = 3
    @LEGS_BEHIND_3_2 = 8

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

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

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

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

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

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

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

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

    @LEGS_BONE_ROOT = 0

    @LEGS_FRONT_1 = 23
    @LEGS_FRONT_2 = 29

    @LEGS_FRONT_3 = 21
    @LEGS_FRONT_4 = 27

    @LEGS_FRONT_5 = 20
    @LEGS_FRONT_6 = 26

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

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

    @NEXT_OBJ_ID = 0

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    SlowUpdate: =>
        @ModifyScale()

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

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

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

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

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

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

    GetLegsModifier: => 1 + (@GetLegsSize() - 1) * .4

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    @LEGS_FRONT_1 = 19
    @LEGS_FRONT_2 = 25

    @LEGS_FRONT_3 = 14
    @LEGS_FRONT_4 = 20

    @LEGS_FRONT_5 = 16
    @LEGS_FRONT_6 = 22

    @LEGS_BEHIND_1_1 = 2
    @LEGS_BEHIND_1_2 = 7

    @LEGS_BEHIND_2_1 = 4
    @LEGS_BEHIND_2_2 = 9

    @LEGS_BEHIND_3_1 = 3
    @LEGS_BEHIND_3_2 = 8

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

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

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


Fix shader applying

Fix shader applying

import BulletManager, Bullet from require "lib.Bullet"
PatternManager = require "lib.PatternManager"
Vector = require "hump.vector"
Boss = require "characters.Boss"
SimpleEnemy = require "characters.SimpleEnemy"
Player = require "characters.Player"
StatsPanel = require "UI.StatsPanel"
StateManager = require "lib.StateManager"
MusicPlayer = require "lib.MusicPlayer"
Moonshine = require "moonshine"
fonts = require "resources.fonts"
lovelog = require "lib.lovelog"
signal = require "hump.signal"
colorize = require "lib.colorize"
const = require "const"

FX = Moonshine(Moonshine.effects.glow)
FX.glow.strength = 5

class SceneManager
  enemies = {}
  player = nil
  canvas: love.graphics.newCanvas const.scene_width, love.graphics.getHeight!

  new: (args) =>
    @statsPanel = StatsPanel {
      width: const.panel_width
      height: const.active_screen_height
    }
    @scene = args.scene
    @spawnPlayer!

    signal.register "dead", (obj) ->
      SceneManager\removeEnemy obj
    signal.register "player meets bullet", (playerstate) ->
      BulletManager\removeAllBullets!
    signal.register "game over", (playerstate) ->
      if playerstate.lives == 0
        MusicPlayer.pauseCurrent!
        StateManager.switch {screen: "GameOver"}
    signal.register "leave scene", ->
      MusicPlayer.pauseCurrent!
    signal.register "resume scene", ->
      MusicPlayer.resumeCurrent!

  addEnemy: (e) =>
    enemies[e] = true

  spawnPlayer: (pos) =>
    player = Player!
    player\setPos const.scene_width * 0.5, const.scene_height * 0.9

  spawnBoss: (args) =>
    pos_x = args.pos.x * const.scene_width
    pos_y = args.pos.y * const.scene_height
    income_pos_x = args.income_pos.x * const.scene_width
    income_pos_y = args.income_pos.y * const.scene_height
    boss = Boss{
      pos: Vector(pos_x, pos_y)
      income_pos: Vector(income_pos_x, income_pos_y)
      modes: args.modes
    }
    enemies[boss] = true

  spawnEnemy: (arg) =>
    enemy = SimpleEnemy arg
    enemies[enemy] = true

  removeEnemy: (obj) =>
    enemies[obj] = nil

  getPlayerPosition: =>
    player.pos

  setPlayer: (p) =>
    player = p

  clear: =>
    enemies = {}
    BulletManager\removeAllBullets!

  update: (dt) =>
    for enemy in pairs enemies
      enemy\update dt
    player\update dt
    PatternManager\update dt
    BulletManager\update dt
    @statsPanel\update dt
    if @scene.update
      @scene\update dt

  draw: =>
    lovelog.reset!
    love.graphics.setCanvas @canvas
    love.graphics.setFont fonts.art
    colorize {10, 10, 10}, ->
      love.graphics.rectangle "fill", 0, 0, @canvas\getWidth!, @canvas\getHeight!
    FX ->
      for enemy, _ in pairs enemies
        enemy\draw!
      player\draw!
      BulletManager\draw!
    love.graphics.setCanvas!
    love.graphics.scale const.scaling
    love.graphics.draw @canvas
    love.graphics.scale 1.0 / const.scaling
    @statsPanel\draw!
    lovelog.print "FPS: " .. love.timer.getFPS!
    if @scene.draw
      @scene\draw!

  keyreleased: (key, rawkey) =>
    if StateManager.PLAYABLE_STATE
      player and player\keyreleased key

  keypressed: (key, rawkey) =>
    if key == "escape"
      MusicPlayer.pauseCurrent!
      StateManager.switch {screen: "PauseMenu", pause: true}
      return
    player\keypressed key

return SceneManager

import BulletManager, Bullet from require "lib.Bullet"
PatternManager = require "lib.PatternManager"
Vector = require "hump.vector"
Boss = require "characters.Boss"
SimpleEnemy = require "characters.SimpleEnemy"
Player = require "characters.Player"
StatsPanel = require "UI.StatsPanel"
StateManager = require "lib.StateManager"
MusicPlayer = require "lib.MusicPlayer"
Moonshine = require "moonshine"
fonts = require "resources.fonts"
lovelog = require "lib.lovelog"
signal = require "hump.signal"
colorize = require "lib.colorize"
const = require "const"

FX = Moonshine(Moonshine.effects.glow)
FX.glow.strength = 3

class SceneManager
  enemies = {}
  player = nil
  canvas: love.graphics.newCanvas const.scene_width, love.graphics.getHeight!

  new: (args) =>
    @statsPanel = StatsPanel {
      width: const.panel_width
      height: const.active_screen_height
    }
    @scene = args.scene
    @spawnPlayer!

    signal.register "dead", (obj) ->
      SceneManager\removeEnemy obj
    signal.register "player meets bullet", (playerstate) ->
      BulletManager\removeAllBullets!
    signal.register "game over", (playerstate) ->
      if playerstate.lives == 0
        MusicPlayer.pauseCurrent!
        StateManager.switch {screen: "GameOver"}
    signal.register "leave scene", ->
      MusicPlayer.pauseCurrent!
    signal.register "resume scene", ->
      MusicPlayer.resumeCurrent!

  addEnemy: (e) =>
    enemies[e] = true

  spawnPlayer: (pos) =>
    player = Player!
    player\setPos const.scene_width * 0.5, const.scene_height * 0.9

  spawnBoss: (args) =>
    pos_x = args.pos.x * const.scene_width
    pos_y = args.pos.y * const.scene_height
    income_pos_x = args.income_pos.x * const.scene_width
    income_pos_y = args.income_pos.y * const.scene_height
    boss = Boss{
      pos: Vector(pos_x, pos_y)
      income_pos: Vector(income_pos_x, income_pos_y)
      modes: args.modes
    }
    enemies[boss] = true

  spawnEnemy: (arg) =>
    enemy = SimpleEnemy arg
    enemies[enemy] = true

  removeEnemy: (obj) =>
    enemies[obj] = nil

  getPlayerPosition: =>
    player.pos

  setPlayer: (p) =>
    player = p

  clear: =>
    enemies = {}
    BulletManager\removeAllBullets!

  update: (dt) =>
    for enemy in pairs enemies
      enemy\update dt
    player\update dt
    PatternManager\update dt
    BulletManager\update dt
    @statsPanel\update dt
    if @scene.update
      @scene\update dt

  draw: =>
    lovelog.reset!
    love.graphics.setCanvas @canvas
    love.graphics.setFont fonts.art
    colorize {10, 10, 10}, ->
      love.graphics.rectangle "fill", 0, 0, @canvas\getWidth!, @canvas\getHeight!

    for enemy, _ in pairs enemies
      enemy\draw!
    player\draw!
    PatternManager\draw!
    BulletManager\draw!
    love.graphics.setCanvas!
    -- FX ->
    love.graphics.scale const.scaling
    love.graphics.draw @canvas
    love.graphics.scale 1.0 / const.scaling
    @statsPanel\draw!
    lovelog.print "FPS: " .. love.timer.getFPS!
    if @scene.draw
      @scene\draw!

  keyreleased: (key, rawkey) =>
    if StateManager.PLAYABLE_STATE
      player and player\keyreleased key

  keypressed: (key, rawkey) =>
    if key == "escape"
      MusicPlayer.pauseCurrent!
      StateManager.switch {screen: "PauseMenu", pause: true}
      return
    player\keypressed key

return SceneManager


plugins/data: Fix handling of AWAY message

import IRCClient, priority from require 'lib.irc'
import Map, Option from require 'lib.std'
import Channel, User from require 'lib.models'

unpack = unpack or table.unpack

IRCClient\add_hook 'CONNECT', =>
	@channels = Map!
	@users    = Map!
	@server   = {
		caps:       {}
		ircv3_caps: {}
		batches:    {}
	}
	@vars = {}

IRCClient\add_hook 'CONNECT', =>
	-- Welcome
	@data = {} if not @data
	@data.last_connect = os.time()
	@send_raw 'CAP', 'LS', '302'

IRCClient\add_handler '005', (prefix, args)=>
	-- Capabilities
	isupport_caps = {select 2, unpack args}
	for cap in *isupport_caps
		if cap\sub(1, 1) == "-"
			-- remove support
			if cap\find "=" then
				@server.caps[cap\match "^%-(.+)="] = nil
			else
				@server.caps[cap\sub 2] = nil
		elseif cap\find "="
			key, value = cap\match '^(.-)=(.+)'
			@server.caps[key] = value
		else
			@server.caps[cap] = true

IRCClient\add_handler 'AWAY', (prefix, args)=>
	{:nick} = prefix
	@users\expect(nick).away = args[#args] == "G"

IRCClient\add_handler 'ACCOUNT', (prefix, args)=>
	@users\expect(nick).account = Option args[1] != "*" and args[1] or nil

IRCClient\add_handler 'RENAME', (prefix, args)=>
	{old, new} = args
	for _, user in @channels\expect(old).users\iter!
		user.channels\set new, user.channels\expect old
		user.channels\remove old
	@channels\set new, @channels\expect old
	@channels\remove old

IRCClient\add_handler 'JOIN', (prefix, args, tags={})=>
	-- user JOINs a channel
	local channel
	local account
	if @server.ircv3_caps['extended-join']
		account = args[2] if args[2] != '*'
		channel = args[1]
	elseif @server.ircv3_caps['account-tag'] and tags.account
		account = tags.account
		channel = args[1]
	else
		channel = args[1]
	{:nick, :user, :host} = prefix

	new_user = User self, nick, user, host, :account

	-- Make sure channel exists
	-- Confirm channel exists in bot object
	channel_entry = @channels\entry channel
	unless channel_entry\exists!
		-- Bot has joined channel
		if @server.caps['WHOX']
			@send_raw 'WHO', channel, '%nat,001'
		elseif @server.ircv3_caps['userhost-in-names']
			@send_raw 'NAMES', channel
		else
			@send_raw 'WHO', channel

		channel_entry\or_insert Channel self, {
			users: {
				[nick]: new_user
			}
		}
	else
		-- Bot is already in channels, shuffle over user
		@channels\expect(channel).users[nick] = new_user

	-- Confirm channel exists in user object
	new_user.channels\set channel, @channels\expect channel
	@users\set nick, new_user

IRCClient\add_hook 'WHOX_001', (nick, account)=>
	@users\expect(nick).account = Option(account) if account != '0'

IRCClient\add_handler 'NICK', (prefix, args)=>
	old = prefix.nick
	new = args[1]
	for channel_name in @users\expect(old).channels\iter!
		channel = @channels\expect channel_name
		channel.users\set new, channel.users\expect old
		channel.users\remove old
	@users\set new, @users\expect old
	@users\remove old

IRCClient\add_handler 'MODE', (prefix, args)=>
	-- User or bot called /mode
	if args[1] and args[1]\sub(1,1) == "#"
		@send_raw 'NAMES', args[1]

IRCClient\add_handler '353', (prefix, args)=>
	-- Result of NAMES
	target = args[3]
	statuses = @server.caps.PREFIX and @server.caps.PREFIX\match '%(.-%)(.+)' or "+@"
	statuses = "[" .. statuses\gsub("%p", "%%%1") .. "]"

	channel = @channels\expect target

	for text in args[#args]\gmatch '%S+'
		local status, pre, nick, ident, host
		if text\match statuses
			status, pre = text\match "^(#{statuses}*)(.-)$"
		else
			status, pre = nil, text
		if @server.ircv3_caps['userhost-in-names']
			nick, ident, host = pre\match '^(.-)!(.-)@(.-)$'
		else
			nick = pre

		channel.statuses\set nick, status

		if @users\contains_key nick -- NAMES not triggered from JOIN
			user = @users\expect nick
			user.user = ident if ident
			user.host = host if host
		else
			@users\set nick, User(self, nick, ident or "", host or "")

		-- Make sure channels and users both have links to each other
		channel.users\set nick, @users\expect nick
		@users\expect(nick).channels\set target, channel

IRCClient\add_handler '352', (prefix, args)=>
	-- Result of WHO
	_, user, host, _, nick, away = unpack args
	client = @users\entry(nick)\or_insert_with -> User self, nick, user, host
	client.user = user
	client.host = host
	client.away = away\sub(1, 1) == "G" -- "H"ere or "G"one

IRCClient\add_handler 'CHGHOST', (prefix, args)=>
	{:nick} = prefix
	client = @users\expect nick
	client.user, client.host = unpack args

IRCClient\add_handler 'KICK', (prefix, args)=>
	channel = args[1]
	nick = args[2]
	client = @users\expect nick
	client.channels\remove channel
	@users\remove nick unless client\is_visible!

IRCClient\add_handler 'PART', (prefix, args)=>
	-- User or bot parted channel, clear from lists
	channel = args[1]
	{:nick} = prefix
	client = @users\expect nick
	client.channels\remove channel
	@users\remove nick unless client\is_visible!

IRCClient\add_handler 'QUIT', (prefix, args)=>
	-- User or bot parted network, nuke from lists
	{:nick} = prefix
	for channel in @users\expect(nick).channels\iter!
		@channels\expect(channel).users\remove nick
	@users\remove nick

IRCClient\add_handler 'PRIVMSG', priority: priority.HIGH, (prefix, args, tags={})=>
	account_tag = @get_tag tags, key: "account"
	if account_tag and prefix.nick and @users\contains_key prefix.nick
		@users\expect(prefix.nick).account = Option account_tag.value

import IRCClient, priority from require 'lib.irc'
import Map, Option from require 'lib.std'
import Channel, User from require 'lib.models'

unpack = unpack or table.unpack

IRCClient\add_hook 'CONNECT', =>
	@channels = Map!
	@users    = Map!
	@server   = {
		caps:       {}
		ircv3_caps: {}
		batches:    {}
	}
	@vars = {}

IRCClient\add_hook 'CONNECT', =>
	-- Welcome
	@data = {} if not @data
	@data.last_connect = os.time()
	@send_raw 'CAP', 'LS', '302'

IRCClient\add_handler '005', (prefix, args)=>
	-- Capabilities
	isupport_caps = {select 2, unpack args}
	for cap in *isupport_caps
		if cap\sub(1, 1) == "-"
			-- remove support
			if cap\find "=" then
				@server.caps[cap\match "^%-(.+)="] = nil
			else
				@server.caps[cap\sub 2] = nil
		elseif cap\find "="
			key, value = cap\match '^(.-)=(.+)'
			@server.caps[key] = value
		else
			@server.caps[cap] = true

IRCClient\add_handler 'AWAY', (prefix, args)=>
	{:nick} = prefix
	@users\expect(nick).away = args[#args]

IRCClient\add_handler 'ACCOUNT', (prefix, args)=>
	@users\expect(nick).account = Option args[1] != "*" and args[1] or nil

IRCClient\add_handler 'RENAME', (prefix, args)=>
	{old, new} = args
	for _, user in @channels\expect(old).users\iter!
		user.channels\set new, user.channels\expect old
		user.channels\remove old
	@channels\set new, @channels\expect old
	@channels\remove old

IRCClient\add_handler 'JOIN', (prefix, args, tags={})=>
	-- user JOINs a channel
	local channel
	local account
	if @server.ircv3_caps['extended-join']
		account = args[2] if args[2] != '*'
		channel = args[1]
	elseif @server.ircv3_caps['account-tag'] and tags.account
		account = tags.account
		channel = args[1]
	else
		channel = args[1]
	{:nick, :user, :host} = prefix

	new_user = User self, nick, user, host, :account

	-- Make sure channel exists
	-- Confirm channel exists in bot object
	channel_entry = @channels\entry channel
	unless channel_entry\exists!
		-- Bot has joined channel
		if @server.caps['WHOX']
			@send_raw 'WHO', channel, '%nat,001'
		elseif @server.ircv3_caps['userhost-in-names']
			@send_raw 'NAMES', channel
		else
			@send_raw 'WHO', channel

		channel_entry\or_insert Channel self, {
			users: {
				[nick]: new_user
			}
		}
	else
		-- Bot is already in channels, shuffle over user
		@channels\expect(channel).users[nick] = new_user

	-- Confirm channel exists in user object
	new_user.channels\set channel, @channels\expect channel
	@users\set nick, new_user

IRCClient\add_hook 'WHOX_001', (nick, account)=>
	@users\expect(nick).account = Option(account) if account != '0'

IRCClient\add_handler 'NICK', (prefix, args)=>
	old = prefix.nick
	new = args[1]
	for channel_name in @users\expect(old).channels\iter!
		channel = @channels\expect channel_name
		channel.users\set new, channel.users\expect old
		channel.users\remove old
	@users\set new, @users\expect old
	@users\remove old

IRCClient\add_handler 'MODE', (prefix, args)=>
	-- User or bot called /mode
	if args[1] and args[1]\sub(1,1) == "#"
		@send_raw 'NAMES', args[1]

IRCClient\add_handler '353', (prefix, args)=>
	-- Result of NAMES
	target = args[3]
	statuses = @server.caps.PREFIX and @server.caps.PREFIX\match '%(.-%)(.+)' or "+@"
	statuses = "[" .. statuses\gsub("%p", "%%%1") .. "]"

	channel = @channels\expect target

	for text in args[#args]\gmatch '%S+'
		local status, pre, nick, ident, host
		if text\match statuses
			status, pre = text\match "^(#{statuses}*)(.-)$"
		else
			status, pre = nil, text
		if @server.ircv3_caps['userhost-in-names']
			nick, ident, host = pre\match '^(.-)!(.-)@(.-)$'
		else
			nick = pre

		channel.statuses\set nick, status

		if @users\contains_key nick -- NAMES not triggered from JOIN
			user = @users\expect nick
			user.user = ident if ident
			user.host = host if host
		else
			@users\set nick, User(self, nick, ident or "", host or "")

		-- Make sure channels and users both have links to each other
		channel.users\set nick, @users\expect nick
		@users\expect(nick).channels\set target, channel

IRCClient\add_handler '352', (prefix, args)=>
	-- Result of WHO
	_, user, host, _, nick, away = unpack args
	client = @users\entry(nick)\or_insert_with -> User self, nick, user, host
	client.user = user
	client.host = host
	client.away = away\sub(1, 1) == "G" -- "H"ere or "G"one

IRCClient\add_handler 'CHGHOST', (prefix, args)=>
	{:nick} = prefix
	client = @users\expect nick
	client.user, client.host = unpack args

IRCClient\add_handler 'KICK', (prefix, args)=>
	channel = args[1]
	nick = args[2]
	client = @users\expect nick
	client.channels\remove channel
	@users\remove nick unless client\is_visible!

IRCClient\add_handler 'PART', (prefix, args)=>
	-- User or bot parted channel, clear from lists
	channel = args[1]
	{:nick} = prefix
	client = @users\expect nick
	client.channels\remove channel
	@users\remove nick unless client\is_visible!

IRCClient\add_handler 'QUIT', (prefix, args)=>
	-- User or bot parted network, nuke from lists
	{:nick} = prefix
	for channel in @users\expect(nick).channels\iter!
		@channels\expect(channel).users\remove nick
	@users\remove nick

IRCClient\add_handler 'PRIVMSG', priority: priority.HIGH, (prefix, args, tags={})=>
	account_tag = @get_tag tags, key: "account"
	if account_tag and prefix.nick and @users\contains_key prefix.nick
		@users\expect(prefix.nick).account = Option account_tag.value


Added hooks Added SuppressPonyWeaponsHide(ply) Added ShouldDrawPonyWeapon(ply, weapon) Added Weapon:ShouldPonyDraw(ply)

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

timer.Create 'PPM2.ModelChecks', 1, 0, ->
    for task in *PPM2.NetworkedPonyData.RenderTasks
        ent = task.ent
        if IsValid(ent)
            ent.__cachedIsPony = ent\IsPony()

    for ply in *player.GetAll()
        ply.__cachedIsPony = ply\IsPony()
        ponydata = ply\GetPonyData()

        if ply.__cachedIsPony
            if (not ponydata or ponydata\GetHideWeapons()) and not hook.Run('SuppressPonyWeaponsHide', ply)
                for wep in *ply\GetWeapons()
                    if wep
                        if not wep.ShouldPonyDraw or not (wep\ShouldPonyDraw(ply) or hook.Run('ShouldDrawPonyWeapon', ply, wep))
                            wep\SetNoDraw(true)
                            wep.__ppm2_weapon_hit = true
                        elseif wep.__ppm2_weapon_hit
                            wep\SetNoDraw(false)
                            ply.__ppm2_weapon_hit = false
            else
                for wep in *ply\GetWeapons()
                    if wep and wep.__ppm2_weapon_hit
                        wep\SetNoDraw(false)
                        ply.__ppm2_weapon_hit = false

PlayerRespawn = ->
    ent = net.ReadEntity()
    return if not IsValid(ent)
    return if not ent\GetPonyData()
    ent\GetPonyData()\PlayerRespawn()

PlayerDeath = ->
    ent = net.ReadEntity()
    return if not IsValid(ent)
    return if not ent\GetPonyData()
    ent\GetPonyData()\PlayerDeath()

lastDataSend = 0
lastDataReceived = 0
net.Receive 'PPM2.RequestPonyData', ->
    return if lastDataReceived > RealTime()
    lastDataReceived = RealTime() + 10
    RunConsoleCommand('ppm2_reload')

net.Receive 'PPM2.PlayerRespawn', PlayerRespawn
net.Receive 'PPM2.PlayerDeath', PlayerDeath

concommand.Add 'ppm2_require', ->
    net.Start('PPM2.Require')
    net.SendToServer()
    PPM2.Message 'Requesting pony data...'

concommand.Add 'ppm2_reload', ->
    return if lastDataSend > RealTime()
    lastDataSend = RealTime() + 10
    instance = PPM2.GetMainData()
    newData = instance\CreateNetworkObject()
    newData\Create()
    instance\SetNetworkData(newData)
    PPM2.Message 'Sending pony data to server...'

hook.Add 'KeyPress', 'PPM2.RequireData', ->
    hook.Remove 'KeyPress', 'PPM2.RequireData'
    RunConsoleCommand('ppm2_reload')
    timer.Simple 3, -> RunConsoleCommand('ppm2_require')

PPM_HINT_COLOR_FIRST = Color(255, 255, 255)
PPM_HINT_COLOR_SECOND = Color(0, 0, 0)

hook.Add 'HUDPaint', 'PPM2.EditorStatus', ->
    lply = LocalPlayer()
    lpos = lply\EyePos()
    for ply in *player.GetAll()
        if ply ~= lply
            if ply\GetNWBool('PPM2.InEditor')
                pos = ply\EyePos()
                dist = pos\Distance(lpos)
                if dist < 250
                    pos.z += 10
                    alpha = math.Clamp(1.3 - dist / 250, 0.1, 1) * 255
                    {:x, :y} = pos\ToScreen()
                    draw.DrawText('In PPM/2 Editor', 'HudHintTextLarge', x + 1, y + 1, Color(255, 255, 255, alpha), TEXT_ALIGN_CENTER)
                    draw.DrawText('In PPM/2 Editor', 'HudHintTextLarge', x, y, Color(0, 0, 0, alpha), TEXT_ALIGN_CENTER)

concommand.Add 'ppm2_cleanup', ->
    for ent in *ents.GetAll()
        if ent.isPonyPropModel and not IsValid(ent.manePlayer)
            ent\Remove()
    PPM2.Message('All unused models were removed')

timer.Create 'PPM2.ModelCleanup', 60, 0, ->
    for ent in *ents.GetAll()
        if ent.isPonyPropModel and not IsValid(ent.manePlayer)
            ent\Remove()

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

timer.Create 'PPM2.ModelChecks', 1, 0, ->
    for task in *PPM2.NetworkedPonyData.RenderTasks
        ent = task.ent
        if IsValid(ent)
            ent.__cachedIsPony = ent\IsPony()

    for ply in *player.GetAll()
        ply.__cachedIsPony = ply\IsPony()
        ponydata = ply\GetPonyData()

        if ply.__cachedIsPony
            if not ponydata or ponydata\GetHideWeapons()
                for wep in *ply\GetWeapons()
                    if wep
                        wep\SetNoDraw(true)
                        wep.__ppm2_weapon_hit = true
            else
                for wep in *ply\GetWeapons()
                    if wep and wep.__ppm2_weapon_hit
                        wep\SetNoDraw(false)
                        ply.__ppm2_weapon_hit = false

PlayerRespawn = ->
    ent = net.ReadEntity()
    return if not IsValid(ent)
    return if not ent\GetPonyData()
    ent\GetPonyData()\PlayerRespawn()

PlayerDeath = ->
    ent = net.ReadEntity()
    return if not IsValid(ent)
    return if not ent\GetPonyData()
    ent\GetPonyData()\PlayerDeath()

lastDataSend = 0
lastDataReceived = 0
net.Receive 'PPM2.RequestPonyData', ->
    return if lastDataReceived > RealTime()
    lastDataReceived = RealTime() + 10
    RunConsoleCommand('ppm2_reload')

net.Receive 'PPM2.PlayerRespawn', PlayerRespawn
net.Receive 'PPM2.PlayerDeath', PlayerDeath

concommand.Add 'ppm2_require', ->
    net.Start('PPM2.Require')
    net.SendToServer()
    PPM2.Message 'Requesting pony data...'

concommand.Add 'ppm2_reload', ->
    return if lastDataSend > RealTime()
    lastDataSend = RealTime() + 10
    instance = PPM2.GetMainData()
    newData = instance\CreateNetworkObject()
    newData\Create()
    instance\SetNetworkData(newData)
    PPM2.Message 'Sending pony data to server...'

hook.Add 'KeyPress', 'PPM2.RequireData', ->
    hook.Remove 'KeyPress', 'PPM2.RequireData'
    RunConsoleCommand('ppm2_reload')
    timer.Simple 3, -> RunConsoleCommand('ppm2_require')

PPM_HINT_COLOR_FIRST = Color(255, 255, 255)
PPM_HINT_COLOR_SECOND = Color(0, 0, 0)

hook.Add 'HUDPaint', 'PPM2.EditorStatus', ->
    lply = LocalPlayer()
    lpos = lply\EyePos()
    for ply in *player.GetAll()
        if ply ~= lply
            if ply\GetNWBool('PPM2.InEditor')
                pos = ply\EyePos()
                dist = pos\Distance(lpos)
                if dist < 250
                    pos.z += 10
                    alpha = math.Clamp(1.3 - dist / 250, 0.1, 1) * 255
                    {:x, :y} = pos\ToScreen()
                    draw.DrawText('In PPM/2 Editor', 'HudHintTextLarge', x + 1, y + 1, Color(255, 255, 255, alpha), TEXT_ALIGN_CENTER)
                    draw.DrawText('In PPM/2 Editor', 'HudHintTextLarge', x, y, Color(0, 0, 0, alpha), TEXT_ALIGN_CENTER)

concommand.Add 'ppm2_cleanup', ->
    for ent in *ents.GetAll()
        if ent.isPonyPropModel and not IsValid(ent.manePlayer)
            ent\Remove()
    PPM2.Message('All unused models were removed')

timer.Create 'PPM2.ModelCleanup', 60, 0, ->
    for ent in *ents.GetAll()
        if ent.isPonyPropModel and not IsValid(ent.manePlayer)
            ent\Remove()


Fix minor scope mistake.

Fix minor scope mistake.

-- This Source Code Form is subject to the terms of the Mozilla Public
-- License, v. 2.0. If a copy of the MPL was not distributed with this
-- file, You can obtain one at http://mozilla.org/MPL/2.0/.
--
-- Copyright 2016 [bk]door.maus

Promise = require "glurg.common.Promise"
Filter = require "glurg.filters.Filter"
Call = require "glurg.trace.Call"
Trace = require "glurg.trace.Trace"

class Buffer
	new: (name) =>
		@name = name
		@data = false
		@is_deleted = false

	_update_data: (trace, call) =>
		if @data
			trace\delete_call(@data.index)
		@data = call

	dispose: (trace) =>
		if @data
			trace\delete_call(@data.index)
		@data = false

class BufferFilter extends Filter
	new: (target) =>
		@target = target
		@current_buffer = 0
		@_buffers = {}

	_get_buffer: (name) =>
		if @_buffers[name] == nil
			@_buffers[name] = Buffer(name)
		return @_buffers[name]

	get_current_buffer: =>
		return @\_get_buffer(@current_buffer)

	get_buffer: (name) =>
		Promise.keep("@_buffers[name] != nil", @_buffers[name] != nil)

		return @_buffers[name]

	glBindBuffer: (trace, call) =>
		Promise.keep("trace", Promise.IsClass(trace, Trace))
		Promise.keep("call", Promise.IsClass(call, Call))

		target = call\get_argument_by_name("target")\query!.value_name
		if target == @target then
			@current_buffer = call\get_argument_by_name("buffer")\query!

		return false

	glBufferData: (trace, call) =>
		Promise.keep("trace", Promise.IsClass(trace, Trace))
		Promise.keep("call", Promise.IsClass(call, Call))

		target = call\get_argument_by_name("target")\query!.value_name
		if target == @target then
			@\_get_buffer(@current_buffer)\_update_data(call)

		return true

	glDeleteBuffers: (trace, call) =>
		Promise.keep("trace", Promise.IsClass(trace, Trace))
		Promise.keep("call", Promise.IsClass(call, Call))

		deleted_buffers = call\get_argument_by_name("buffers")\query!
		for i = 1, #deleted_buffers
			if @_buffers[deleted_buffers[i]]
				@_buffers[deleted_buffers[i]].is_deleted = true

		return false

	dispose: (trace) =>
		for _, buffer in pairs(@_buffers)
			buffer\dispose(trace)

return BufferFilter

-- This Source Code Form is subject to the terms of the Mozilla Public
-- License, v. 2.0. If a copy of the MPL was not distributed with this
-- file, You can obtain one at http://mozilla.org/MPL/2.0/.
--
-- Copyright 2016 [bk]door.maus

Promise = require "glurg.common.Promise"
Filter = require "glurg.filters.Filter"
Call = require "glurg.trace.Call"
Trace = require "glurg.trace.Trace"

class Buffer
	new: (name) =>
		@name = name
		@data = false
		@is_deleted = false

	_update_data: (trace, call) =>
		if @data
			trace\delete_call(@data.index)
		@data = call

	dispose: (trace) =>
		if @data
			trace\delete_call(@data.index)
		@data = false

class BufferFilter extends Filter
	new: (target) =>
		@target = target
		@current_buffer = 0
		@_buffers = {}

	_get_buffer: (name) =>
		if @_buffers[name] == nil
			@_buffers[name] = Buffer(name)
		return @_buffers[name]

	get_current_buffer: =>
		return @\_get_buffer(@current_buffer)

	get_buffer: (name) =>
		Promise.keep("@_buffers[name] != nil", @_buffers[name] != nil)

		return @_buffers[name]

	glBindBuffer: (trace, call) =>
		Promise.keep("trace", Promise.IsClass(trace, Trace))
		Promise.keep("call", Promise.IsClass(call, Call))

		target = call\get_argument_by_name("target")\query!.value_name
		if target == @target then
			@current_buffer = call\get_argument_by_name("buffer")\query!

		return false

	glBufferData: (trace, call) =>
		Promise.keep("trace", Promise.IsClass(trace, Trace))
		Promise.keep("call", Promise.IsClass(call, Call))

		target = call\get_argument_by_name("target")\query!.value_name
		if target == @target then
			_get_buffer(@current_buffer)\_update_data(call)

		return true

	glDeleteBuffers: (trace, call) =>
		Promise.keep("trace", Promise.IsClass(trace, Trace))
		Promise.keep("call", Promise.IsClass(call, Call))

		deleted_buffers = call\get_argument_by_name("buffers")\query!
		for i = 1, #deleted_buffers
			if @_buffers[deleted_buffers[i]]
				@_buffers[deleted_buffers[i]].is_deleted = true

		return false

	dispose: (trace) =>
		for _, buffer in pairs(@_buffers)
			buffer\dispose(trace)

return BufferFilter


dont translate language names

dont translate language names

html = require "lapis.html"

class extends html.Widget
  content: =>
    html_5 ->
      head ->
        meta charset: 'utf-8'
        link
          rel: "icon", type: "image/x-icon",
          href: "/favicon.ico"
        title @title or @_ "Kodomo Quiz"
      body ->
        h1 class: "header", @_("Kodomo Quiz")
        a href: @url_for('index'), ->
          text @_ "Main page"
        text " | "
        a href: @url_for('russian'), ->
          text "Русский"
        text " | "
        a href: @url_for('english'), ->
          text "English"
        raw '<br/>'
        @content_for "inner"

html = require "lapis.html"

class extends html.Widget
  content: =>
    html_5 ->
      head ->
        meta charset: 'utf-8'
        link
          rel: "icon", type: "image/x-icon",
          href: "/favicon.ico"
        title @title or @_ "Kodomo Quiz"
      body ->
        h1 class: "header", @_("Kodomo Quiz")
        a href: @url_for('index'), ->
          text @_ "Main page"
        text " | "
        a href: @url_for('russian'), ->
          text @_ "Русский"
        text " | "
        a href: @url_for('english'), ->
          text @_ "English"
        raw '<br/>'
        @content_for "inner"


Redo moonscript to support v0.2.0

Redo moonscript to support v0.2.0


Add arbitrary remove to utils.List

Add arbitrary remove to utils.List

export ^

class List
	new: =>
		@__list = {}

	-- Add an item to the end of the list
	push: (value) => @__list[@len! + 1] = value

	-- Remove an item from the end of the list
	pop: => table.remove @__list, @len!

	-- Look at the item at the end of the list
	peek: => @__list[@len!]

	-- The last item in the list
	last: => @peek!

	-- Add an item to the begining of the list
	unshift: (value) => table.insert @__list, 1, value

	-- Remove an item from the begining of the list
	shift: => table.remove @__list, 1

	-- Remove an item at any point
	remove: (i) => table.remove @__list, i

	-- Look at the item at the begining of the list
	first: => @__list[1]

	len: => #@__list

	index: (i) => @__list[i]

	-- Iterate over the list
	-- Removing items during iteration may cause unexpected results
	pairs: =>
		n, len = 0, @len!
		->
			n += 1
			return nil if n > len
			@__list[n]

	-- Reverse iterate over the list
	-- Removing items during iteration may cause unexpected results
	rpairs: =>
		n = @len! + 1
		->
			n -= 1
			return nil if n < 1
			@__list[n]

	-- Iterate over the list returning the index as well
	-- Removing items during iteration may cause unexpected results
	ipairs: =>
		n, len = 0, @len!
		->
			n += 1
			return nil if n > len
			n, @__list[n]

	-- Reverse iterate over the list returning the index as well
	-- Removing items during iteration may cause unexpected results
	ripairs: =>
		n = @len! + 1
		->
			n -= 1
			return nil if n < 1
			n, @__list[n]

export ^

class List
	new: =>
		@__list = {}

	-- Add an item to the end of the list
	push: (value) => @__list[@len! + 1] = value

	-- Remove an item from the end of the list
	pop: => table.remove @__list, @len!

	-- Look at the item at the end of the list
	peek: => @__list[@len!]

	-- The last item in the list
	last: => @peek!

	-- Add an item to the begining of the list
	unshift: (value) => table.insert @__list, 1, value

	-- Remove an item from the begining of the list
	shift: => table.remove @__list, 1

	-- Look at the item at the begining of the list
	first: => @__list[1]

	len: => #@__list

	index: (i) => @__list[i]

	-- Iterate over the list
	-- Removing items during iteration may cause unexpected results
	pairs: =>
		n, len = 0, @len!
		->
			n += 1
			return nil if n > len
			@__list[n]

	-- Reverse iterate over the list
	-- Removing items during iteration may cause unexpected results
	rpairs: =>
		n = @len! + 1
		->
			n -= 1
			return nil if n < 1
			@__list[n]

	-- Iterate over the list returning the index as well
	-- Removing items during iteration may cause unexpected results
	ipairs: =>
		n, len = 0, @len!
		->
			n += 1
			return nil if n > len
			n, @__list[n]

	-- Reverse iterate over the list returning the index as well
	-- Removing items during iteration may cause unexpected results
	ripairs: =>
		n = @len! + 1
		->
			n -= 1
			return nil if n < 1
			n, @__list[n]


github: add event pull_request_review_comment

Former-commit-id: e0db80dea68788836077661da6c27bc945fa15f9
Former-commit-id: 3ed3797777ec544dbd76d0c4a67235511a42302e

util = require 'util'

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

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

handlers = {
  push: (repo, destination, json) ->
    branch = util.bold(json.ref\gsub 'refs/heads/', '')
    for i, c in pairs(json.commits)
      if i > 3
        break
      message = c.message\gsub '\n.*', ''
      if i == 1
        message = message .. ' ' .. json.compare
      ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: #{branch}, #{util.nonickalertword c.author.username}: #{message}"
    if #json.commits >= 4
      ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: #{branch}, #{#json.commits-3} more commits not displayed."
  watch: (repo, destination, json) ->
    action = json.action
    if action == 'started'
      ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: #{util.nonickalertword json.sender.login}: +1 ★ (Total: #{json.repository.stargazers_count})"
    else
      ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: #{util.nonickalertword json.sender.login}: #{action} watching"
  ping: (repo, destination, json) ->
    ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: ping"
  commit_comment: (repo, destination, json) ->
    --commenter = json.comment.user.login
    body = json.comment.body
    ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: <#{util.nonickalertword json.sender.login}> #{body}"
  pull_request: (repo, destination, json) ->
    action = json.action
    number = util.bold json.number
    ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: #{util.nonickalertword json.sender.login}: #{action} PR ##{number}: #{json.pull_request.title} #{json.pull_request.html_url}"
  pull_request_review_comment: (repo, destination, json) ->
    body = json.comment.body
    number = util.bold json.pull_request.number
    ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: PR ##{number} <#{util.nonickalertword json.sender.login}> #{body}"
  issues: (repo, destination, json) ->
    action = json.action
    nr = util.bold json.issue.number
    ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: #{util.nonickalertword json.sender.login}: #{action} issue ##{nr}: #{json.issue.title} #{json.issue.html_url}"
  issue_comment: (repo, destination, json) ->
    action = json.action
    nr = util.bold json.issue.number
    ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: Issue ##{nr} <#{util.nonickalertword json.sender.login}> #{json.comment.body} #{json.issue.html_url}"
  fork: (repo, destination, json) ->
    ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: #{util.nonickalertword json.sender.login}: forked to #{json.forkee.html_url}"
  create: (repo, destination, json) ->
    ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: #{util.nonickalertword json.sender.login}: created #{json.ref_type} #{util.bold json.ref}"
  delete: (repo, destination, json) ->
    ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: #{util.nonickalertword json.sender.login}: deleted #{json.ref_type} #{util.bold json.ref}"
  gollum: (repo, destination, json) ->
    return
  release: (repo, destination, json) ->
    return
}

ivar2.webserver.regUrl '/github/(.*)', (req, res) ->
  destination = req.url\match('/github/(.+)/?$')
  destination = unescape(destination)
  json = util.json.decode(req.body)

  repo = json.repository.full_name

  event = req.headers['X-GitHub-Event']
  handler = handlers[event]
  if handler
    handler(repo, destination, json)
  else
    ivar2\Log('error', 'Unknown github event: %s', event)

  res\set_status(200)
  res\set_header('Content-Type', 'text/plain')
  res\set_body('ok')
  res\send()

return {}

util = require 'util'

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

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

handlers = {
  push: (repo, destination, json) ->
    branch = util.bold(json.ref\gsub 'refs/heads/', '')
    for i, c in pairs(json.commits)
      if i > 3
        break
      message = c.message\gsub '\n.*', ''
      if i == 1
        message = message .. ' ' .. json.compare
      ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: #{branch}, #{util.nonickalertword c.author.username}: #{message}"
    if #json.commits >= 4
      ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: #{branch}, #{#json.commits-3} more commits not displayed."
  watch: (repo, destination, json) ->
    action = json.action
    if action == 'started'
      ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: #{util.nonickalertword json.sender.login}: +1 ★ (Total: #{json.repository.stargazers_count})"
    else
      ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: #{util.nonickalertword json.sender.login}: #{action} watching"
  ping: (repo, destination, json) ->
    ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: ping"
  commit_comment: (repo, destination, json) ->
    --commenter = json.comment.user.login
    body = json.comment.body
    ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: <#{util.nonickalertword json.sender.login}> #{body}"
  pull_request: (repo, destination, json) ->
    action = json.action
    number = util.bold json.number
    ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: #{util.nonickalertword json.sender.login}: #{action} PR ##{number}: #{json.pull_request.title} #{json.pull_request.html_url}"
  issues: (repo, destination, json) ->
    action = json.action
    nr = util.bold json.issue.number
    ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: #{util.nonickalertword json.sender.login}: #{action} issue ##{nr}: #{json.issue.title} #{json.issue.html_url}"
  issue_comment: (repo, destination, json) ->
    action = json.action
    nr = util.bold json.issue.number
    ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: Issue ##{nr} <#{util.nonickalertword json.sender.login}> #{json.comment.body} #{json.issue.html_url}"
  fork: (repo, destination, json) ->
    ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: #{util.nonickalertword json.sender.login}: forked to #{json.forkee.html_url}"
  create: (repo, destination, json) ->
    ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: #{util.nonickalertword json.sender.login}: created #{json.ref_type} #{util.bold json.ref}"
  delete: (repo, destination, json) ->
    ivar2\Msg 'privmsg', destination, nil, "[#{repo}]: #{util.nonickalertword json.sender.login}: deleted #{json.ref_type} #{util.bold json.ref}"
  gollum: (repo, destination, json) ->
    return
  release: (repo, destination, json) ->
    return
}

ivar2.webserver.regUrl '/github/(.*)', (req, res) ->
  destination = req.url\match('/github/(.+)/?$')
  destination = unescape(destination)
  json = util.json.decode(req.body)

  repo = json.repository.full_name

  event = req.headers['X-GitHub-Event']
  handler = handlers[event]
  if handler
    handler(repo, destination, json)
  else
    ivar2\Log('error', 'Unknown github event: %s', event)

  res\set_status(200)
  res\set_header('Content-Type', 'text/plain')
  res\set_body('ok')
  res\send()

return {}