entities are not affected by "fake-isometric" scaling + better comments in that regard

export ^

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

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

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

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

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

    draw: =>
        @\draw_starfield()
        love.graphics.scale(1, 0.5) -- fake-isometric squish
        -- draw spacebase (rotated and squished)
        @cam\draw(@spacebase\draw)
        -- draw entities (minions and items) (un-rotated and un-squished)
        love.graphics.scale(1, 2)
        for minion in *@spacebase.crew
            sx, sy = @cam\toScreen(minion.x, minion.y)
            sy /= 2 -- account for squishiness
            love.graphics.push()
            scale = @cam\getScale()
            love.graphics.scale(scale, scale)
            love.graphics.translate(sx / scale, sy / scale)
            minion\draw()
            love.graphics.pop()

        for room in *@spacebase.rooms
            for tile in *room.tiles
                item = tile.itemContained
                if item
                    {wx, wy} = @spacebase\tileToWorld(tile.row, tile.col)
                    sx, sy = @cam\toScreen(wx, wy)
                    sy /= 2 -- account for squishiness
                    love.graphics.push()
                    scale = @cam\getScale()
                    love.graphics.scale(scale, scale)
                    love.graphics.translate(sx / scale, sy / scale)
                    item\draw()
                    love.graphics.pop()

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

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

    keyreleased: (key) =>

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

export ^

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

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

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

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

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

    draw: =>
        @\draw_starfield()
        love.graphics.scale(1, 0.5)
        -- draw spacebase (rotated)
        @cam\draw(@spacebase\draw)
        -- draw entities (minions and items) (not rotated)
        for minion in *@spacebase.crew
            sx, sy = @cam\toScreen(minion.x, minion.y)
            love.graphics.push()
            scale = @cam\getScale()
            love.graphics.scale(scale, scale)
            love.graphics.translate(sx / scale, sy / scale)
            minion\draw()
            love.graphics.pop()

        for room in *@spacebase.rooms
            for tile in *room.tiles
                item = tile.itemContained
                if item
                    {wx, wy} = @spacebase\tileToWorld(tile.row, tile.col)
                    sx, sy = @cam\toScreen(wx, wy)
                    love.graphics.push()
                    scale = @cam\getScale()
                    love.graphics.scale(scale, scale)
                    love.graphics.translate(sx / scale, sy / scale)
                    item\draw()
                    love.graphics.pop()

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

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

    keyreleased: (key) =>

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


Fix issue with LP.point2

Fix issue with LP.point2

* Also make camera a new point (though it may need to actually be equal
  to the table that point2 uses.)
* Add a clear (table) function

require "LunoPunk.geometry.Point"
require "LunoPunk.geometry.Rectangle"
require "LunoPunk.geometry.Matrix"
require "LunoPunk.Scene"
require "LunoPunk.Tweener"

export ^

class lp
	-- Private
	BASELAYER = 10
	DEG = -180 / math.pi
	INT_MAX_VALUE = nil
	NUMBER_MAX_VALUE = nil
	RAD = math.pi / -180
	VERSION = "0.0.1"
	__scene = nil

	_gameTime: nil
	_renderTime: nil
	_systemTime: nil
	_updateTime: nil
	assignedFrameRate: nil
	blackColor: 0x00000000
	bounds: nil
	buffer: nil
	camera: Point!
	console: nil
	defaultFont: "default"
	elapsed: 0
	engine: nil
	entity: nil
	fixed: false
	focused: nil
	frameRate: 0
	log: nil
	matrix: Matrix!
	orientations: nil
	pan: nil
	point: Point!
	point2: Point!
	random: -> math.random!
	randomSeed: nil
	rate: 0
	rect: Rectangle!
	renderMode: nil
	scene: Scene!
	screen: nil
	sprite: nil
	tweener: Tweener!
	volume: nil
	watch: nil
	world: nil
	zero: Point!

	-- Window/resolution related fields
	fullscreen: false
	halfHeight: -> LP.height/2
	halfWidth: -> LP.width/2
	height: 0
	width: 0
	windowHeight: 0
	windowWidth: 0

	alarm: (delay, complete, typeweenType, tweener) ->
	anchorTo: (object, anchor, distance) ->
	angle: (x1, y1, x2, y2) ->
	angleDifference: (angle1, angle2) ->
	angleXY: (object, angle, length, x, y) ->
	approach: (value, target, amount) ->
	choose: (objs) ->
	clamp: (value, min, max) ->
	clampInRect: (object, x, y, width, height, padding) ->
	clear: (t) -> while #t > 0 do table.remove t
	colorLerp: (fromColor, toColor, t) ->
	consoleEnabled: ->
	createBitmap: (width, height, transparent, color) ->
	distance: (x1, y1, x2, y2) ->
	istanceRectPoint: (px, py, rx, ry, rw, rh) ->
	distanceRects: (x1, y1, w1, h1, x2, y2, w2, h2) ->
	distanceSquared: (x1, y1, xprint2, y2) ->
	frames: (from_frame, to_frame, skip) ->
	getImage: (source) -> love.graphics.newImage source
	getColorHSV: (h, s, v) ->
	getColorHue: (color) ->

	getColorSaturation: (color) ->
	getColorValue: (color) ->

	convertColor: (color) -> { lp.getRed(color), lp.getGreen(color), lp.getBlue(color) }
	getColorRGB: (r, g, b) -> r * 0x10000 + g * 0x100 + b
	getRed: (color) -> math.floor color / 0x10000
	getGreen: (color) -> math.floor color / 0x100 % 0x100
	getBlue: (color) -> math.floor color % 0x100

	-- read-only
	DEG: -> DEG

	-- read-only
	NUMBER_MAX_VALUE: -> NUMBER_MAX_VALUE

	-- read-only
	RAD: -> RAD

	-- read-only
	VERSION: -> VERSION

	-- read-only
	BASELAYER: -> BASELAYER

	sceneIsNull: => @scene != @__scene or @__scene == nil

	lerp: (a, b, t) ->
	next: (current, options, loop) ->
	prev: (current, options, loop) ->

	rand: (amount) -> math.random(amount)
	randomizeSeed: -> math.randomseed os.time()

	resetCamera: -> camera.x, camera.y = 0, 0

	resize: (width, height) ->
		-- resize scene to scale
		width /= LP.screen\fullScaleX!
		height = height / LP.screen\fullScaleY!
		LP.width, LP.height = width, height
		LP.bounds.width, LP.bounds.height = width, height
		LP.screen\resize!

	rotateAround: (object, anchor, angle, relative) ->
	round: (num, precision) ->
	scale: (value, min, max, min2, max2) ->
	scaleClamp: (value, min, max, min2, max2) ->
	setCamera: (x, y) -> LP.camera.x, LP.camera.y = x, y
	shuffle: (a) ->

	-- Finds the sign of the provided value.
	-- @param	value		The Float to evaluate.
	-- @return	1 if value > 0, -1 if value < 0, and 0 when value == 0.
	sign: (value) -> if value < 0 then -1 else if value == 0 then 0 else 1

	stepTowards: (object, x, y, distance) ->
	swap: (current, a, b) ->
	swapScene: => @__scene = @scene
	timeFlag: ->
	tween: (object, values, duration, options) ->

LP = lp!

require "LunoPunk.geometry.Point"
require "LunoPunk.geometry.Rectangle"
require "LunoPunk.geometry.Matrix"
require "LunoPunk.Scene"
require "LunoPunk.Tweener"

export ^

class lp
	-- Private
	BASELAYER = 10
	DEG = -180 / math.pi
	INT_MAX_VALUE = nil
	NUMBER_MAX_VALUE = nil
	RAD = math.pi / -180
	VERSION = "0.0.1"
	__scene = nil

	_gameTime: nil
	_renderTime: nil
	_systemTime: nil
	_updateTime: nil
	assignedFrameRate: nil
	blackColor: 0x00000000
	bounds: nil
	buffer: nil
	camera: nil
	console: nil
	defaultFont: "default"
	elapsed: 0
	engine: nil
	entity: nil
	fixed: false
	focused: nil
	frameRate: 0
	log: nil
	matrix: Matrix!
	orientations: nil
	pan: nil
	point: Point!
	point2: Point
	random: -> math.random!
	randomSeed: nil
	rate: 0
	rect: Rectangle!
	renderMode: nil
	scene: Scene!
	screen: nil
	sprite: nil
	tweener: Tweener!
	volume: nil
	watch: nil
	world: nil
	zero: Point!

	-- Window/resolution related fields
	fullscreen: false
	halfHeight: -> LP.height/2
	halfWidth: -> LP.width/2
	height: 0
	width: 0
	windowHeight: 0
	windowWidth: 0

	alarm: (delay, complete, typeweenType, tweener) ->
	anchorTo: (object, anchor, distance) ->
	angle: (x1, y1, x2, y2) ->
	angleDifference: (angle1, angle2) ->
	angleXY: (object, angle, length, x, y) ->
	approach: (value, target, amount) ->
	choose: (objs) ->
	clamp: (value, min, max) ->
	clampInRect: (object, x, y, width, height, padding) ->
	colorLerp: (fromColor, toColor, t) ->
	consoleEnabled: ->
	createBitmap: (width, height, transparent, color) ->
	distance: (x1, y1, x2, y2) ->
	istanceRectPoint: (px, py, rx, ry, rw, rh) ->
	distanceRects: (x1, y1, w1, h1, x2, y2, w2, h2) ->
	distanceSquared: (x1, y1, xprint2, y2) ->
	frames: (from_frame, to_frame, skip) ->
	getImage: (source) -> love.graphics.newImage source
	getColorHSV: (h, s, v) ->
	getColorHue: (color) ->

	getColorSaturation: (color) ->
	getColorValue: (color) ->

	convertColor: (color) -> { lp.getRed(color), lp.getGreen(color), lp.getBlue(color) }
	getColorRGB: (r, g, b) -> r * 0x10000 + g * 0x100 + b
	getRed: (color) -> math.floor color / 0x10000
	getGreen: (color) -> math.floor color / 0x100 % 0x100
	getBlue: (color) -> math.floor color % 0x100

	-- read-only
	DEG: -> DEG

	-- read-only
	NUMBER_MAX_VALUE: -> NUMBER_MAX_VALUE

	-- read-only
	RAD: -> RAD

	-- read-only
	VERSION: -> VERSION

	-- read-only
	BASELAYER: -> BASELAYER

	sceneIsNull: => @scene != @__scene or @__scene == nil

	lerp: (a, b, t) ->
	next: (current, options, loop) ->
	prev: (current, options, loop) ->

	rand: (amount) -> math.random(amount)
	randomizeSeed: -> math.randomseed os.time()

	resetCamera: -> camera.x, camera.y = 0, 0

	resize: (width, height) ->
		-- resize scene to scale
		width /= LP.screen\fullScaleX!
		height = height / LP.screen\fullScaleY!
		LP.width, LP.height = width, height
		LP.bounds.width, LP.bounds.height = width, height
		LP.screen\resize!

	rotateAround: (object, anchor, angle, relative) ->
	round: (num, precision) ->
	scale: (value, min, max, min2, max2) ->
	scaleClamp: (value, min, max, min2, max2) ->
	setCamera: (x, y) -> LP.camera.x, LP.camera.y = x, y
	shuffle: (a) ->

	-- Finds the sign of the provided value.
	-- @param	value		The Float to evaluate.
	-- @return	1 if value > 0, -1 if value < 0, and 0 when value == 0.
	sign: (value) -> if value < 0 then -1 else if value == 0 then 0 else 1

	stepTowards: (object, x, y, distance) ->
	swap: (current, a, b) ->
	swapScene: => @__scene = @scene
	timeFlag: ->
	tween: (object, values, duration, options) ->

LP = lp!


utf8: new function zalgo

utf8: new function zalgo

html2unicode = require'html'
math = require'math'

an = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
ci = 'ⒶⒷⒸⒹⒺⒻⒼⒽⒾⒿⓀⓁⓂⓃⓄⓅⓆⓇⓈⓉⓊⓋⓌⓍⓎⓏⓐⓑⓒⓓⓔⓕⓖⓗⓘⓙⓚⓛⓜⓝⓞⓟⓠⓡⓢⓣⓤⓥⓦⓧⓨⓩ⓪①②③④⑤⑥⑦⑧⑨'
bl = '𝔄𝔅ℭ𝔇𝔈𝔉𝔊ℌℑ𝔍𝔎𝔏𝔐𝔑𝔒𝔓𝔔ℜ𝔖𝔗𝔘𝔙𝔚𝔛𝔜ℨ𝔞𝔟𝔠𝔡𝔢𝔣𝔤𝔥𝔦𝔧𝔨𝔩𝔪𝔫𝔬𝔭𝔮𝔯𝔰𝔱𝔲𝔳𝔴𝔵𝔶𝔷'

an2ci = {}
-- Circled letters are 3 bytes, just use sub string
for i=1, #an
  f = i*3+1-3
  t = i*3
  an2ci[an\sub(i,i)] = ci\sub(f, t)

an2bl = {}
i=1
-- Since blackletters have varying byte length, use the common lua pattern to find multibyte chars
for uchar in string.gfind(bl, "([%z\1-\127\194-\244][\128-\191]*)")
  an2bl[an\sub(i,i)] = uchar
  i = i +1

codepoints = (str) ->
  str\gmatch("[%z\1-\127\194-\244][\128-\191]*")

unichr = (n) ->
  html2unicode('&#x%x;'\format(n))

wireplace = (offset, arg) ->
    s = arg or ''
    t = {}
    for i = 1, #s
      bc = string.byte(s, i, i)
      -- Replace space width ideographic space for fullwidth offset
      if bc == 32 and offset == 0xFEE0
        t[#t + 1] = '\227\128\128'
      elseif bc == 32
        t[#t + 1] = ' '
      elseif bc < 0x80 then
        t[#t + 1] = html2unicode("&#" .. (offset + bc) .. ";")
      else
        t[#t + 1] = s\sub(i, i)

    table.concat(t, "")

remap = (map, s) ->
  table.concat [map[s\sub(i,i)] or s\sub(i,i) for i=1, #s], ''

zalgo = (text, intensity=50) ->
  zalgo_threshold = intensity
  zalgo_chars = {}
  for i=0x0300, 0x036
    zalgo_chars[i-0x2ff] = unichr(i)

  zalgo_chars[#zalgo_chars + 1] = unichr(0x0488)
  zalgo_chars[#zalgo_chars + 1] = unichr(0x0489)

  source = text\upper()
  --source = _insert_randoms(source)

  zalgoized = {}
  for letter in codepoints(source)
    zalgoized[#zalgoized + 1] = letter
    zalgo_num = math.random(1, zalgo_threshold)
    for i=1, zalgo_num
      zalgoized[#zalgoized + 1] = zalgo_chars[math.random(1, #zalgo_chars)]
  table.concat(zalgoized)

PRIVMSG:
  '^%pwide (.+)$': (source, destination, arg) =>
    @Msg 'privmsg', destination, source, wireplace(0xFEE0, arg)
  '^%pblackletter (.+)$': (source, destination, arg) =>
    @Msg 'privmsg', destination, source, remap(an2bl, arg)
  '^%pcircled (.+)$': (source, destination, arg) =>
    @Msg 'privmsg', destination, source, remap(an2ci, arg)
  '^%pzalgo (.+)$': (source, destination, arg) =>
    @Msg 'privmsg', destination, source, zalgo(arg, 10)

an = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
ci = 'ⒶⒷⒸⒹⒺⒻⒼⒽⒾⒿⓀⓁⓂⓃⓄⓅⓆⓇⓈⓉⓊⓋⓌⓍⓎⓏⓐⓑⓒⓓⓔⓕⓖⓗⓘⓙⓚⓛⓜⓝⓞⓟⓠⓡⓢⓣⓤⓥⓦⓧⓨⓩ⓪①②③④⑤⑥⑦⑧⑨'
bl = '𝔄𝔅ℭ𝔇𝔈𝔉𝔊ℌℑ𝔍𝔎𝔏𝔐𝔑𝔒𝔓𝔔ℜ𝔖𝔗𝔘𝔙𝔚𝔛𝔜ℨ𝔞𝔟𝔠𝔡𝔢𝔣𝔤𝔥𝔦𝔧𝔨𝔩𝔪𝔫𝔬𝔭𝔮𝔯𝔰𝔱𝔲𝔳𝔴𝔵𝔶𝔷'

an2ci = {}
-- Circled letters are 3 bytes, just use sub string
for i=1, #an
  f = i*3+1-3
  t = i*3
  an2ci[an\sub(i,i)] = ci\sub(f, t)

an2bl = {}
i=1
-- Since blackletters have varying byte length, use the common lua pattern to find multibyte chars
for uchar in string.gfind(bl, "([%z\1-\127\194-\244][\128-\191]*)")
  an2bl[an\sub(i,i)] = uchar
  i = i +1

wireplace = (offset, arg) ->
    html2unicode = require'html'
    s = arg or ''
    t = {}
    for i = 1, #s
      bc = string.byte(s, i, i)
      -- Replace space width ideographic space for fullwidth offset
      if bc == 32 and offset == 0xFEE0
        t[#t + 1] = '\227\128\128'
      elseif bc == 32
        t[#t + 1] = ' '
      elseif bc < 0x80 then
        t[#t + 1] = html2unicode("&#" .. (offset + bc) .. ";")
      else
        t[#t + 1] = s\sub(i, i)

    table.concat(t, "")

remap = (map, s) ->
  table.concat [map[s\sub(i,i)] or s\sub(i,i) for i=1, #s], ''

PRIVMSG:
  '^%pwide (.+)$': (source, destination, arg) =>
    @Msg 'privmsg', destination, source, wireplace(0xFEE0, arg)
  '^%pblackletter (.+)$': (source, destination, arg) =>
    @Msg 'privmsg', destination, source, remap(an2bl, arg)
  '^%pcircled (.+)$': (source, destination, arg) =>
    @Msg 'privmsg', destination, source, remap(an2ci, arg)


translate: Switch to the util library.

translate: Switch to the util library.

Former-commit-id: 2f8fcb41ce5dcb2d20de3a0ea975e1fadf76221a [formerly 48f8a88e16c8516c85818bfd22659f4158b23177]
Former-commit-id: 438fd944d2bac80c2c6c7c673dd67678f515fa16

-- google translate
util = require'util'
json = util.json
simplehttp = util.simplehttp

languages =
  "af": "Afrikaans",
  "sq": "Albanian",
  "ar": "Arabic",
  "az": "Azerbaijani",
  "eu": "Basque",
  "bn": "Bengali",
  "be": "Belarusian",
  "bg": "Bulgarian",
  "ca": "Catalan",
  "zh-CN": "Simplified Chinese",
  "zh-TW": "Traditional Chinese",
  "hr": "Croatian",
  "cs": "Czech",
  "da": "Danish",
  "nl": "Dutch",
  "en": "English",
  "eo": "Esperanto",
  "et": "Estonian",
  "tl": "Filipino",
  "fi": "Finnish",
  "fr": "French",
  "gl": "Galician",
  "ka": "Georgian",
  "de": "German",
  "el": "Greek",
  "gu": "Gujarati",
  "ht": "Haitian Creole",
  "iw": "Hebrew",
  "hi": "Hindi",
  "hu": "Hungarian",
  "is": "Icelandic",
  "id": "Indonesian",
  "ga": "Irish",
  "it": "Italian",
  "ja": "Japanese",
  "kn": "Kannada",
  "ko": "Korean",
  "la": "Latin",
  "lv": "Latvian",
  "lt": "Lithuanian",
  "mk": "Macedonian",
  "ms": "Malay",
  "mt": "Maltese",
  "no": "Norwegian",
  "fa": "Persian",
  "pl": "Polish",
  "pt": "Portuguese",
  "ro": "Romanian",
  "ru": "Russian",
  "sr": "Serbian",
  "sk": "Slovak",
  "sl": "Slovenian",
  "es": "Spanish",
  "sw": "Swahili",
  "sv": "Swedish",
  "ta": "Tamil",
  "te": "Telugu",
  "th": "Thai",
  "tr": "Turkish",
  "uk": "Ukrainian",
  "ur": "Urdu",
  "vi": "Vietnamese",
  "cy": "Welsh",
  "yi": "Yiddish"

getCode = (language) ->
  for code, lang in pairs languages
    if lang\lower! == language\lower!
      return code
    else if language\lower! == code\lower!
      return code

urlEncode = (str, space) ->
  space = space or '+'
  str = tostring(str)

  str = str\gsub '([^%w ])', (c) ->
    string.format  "%%%02X", string.byte(c)
  return str\gsub(' ', space)

buildQueryStr = (tbl) ->
  out = {}
  for k,v in pairs tbl
    table.insert out, k..'='..urlEncode(v)
  table.concat out, '&'

translate = (origin, target, term, cb) ->
  origin = getCode(origin) or 'auto'
  target = getCode(target) or 'en'
  args =
    client: 'p'
    hl: 'en'
    multires: 1
    sc: 1
    sl: origin
    ssel: 0
    tl: target
    tsel: 0
    uptl: "en"
    text: term

  simplehttp {
    url:"http://translate.google.com/translate_a/t?" .. buildQueryStr(args)
    headers: {
      "User-Agent": "Mozilla/5.0"
      "Accept-Charset": "UTF-8"
    }
  }, (data) ->
    if #data > 4
      parsed = json.decode data
      language = parsed.src
      out = table.concat [k.trans for k in *parsed.sentences]
      if #out > 0
        cb(out)

PRIVMSG:
  '^%ptranslate ([%w%-]+) ([%w%-]+) (.*)$': (source, destination, origin, target, term) =>
    translate origin, target, term, (text) ->
      say text
  '^%ptr ([%w%-]+) ([%w%-]+) (.*)$': (source, destination, origin, target, term) =>
    translate origin, target, term, (text) ->
      say text
  '^%ptlolno (.*)$': (source, destination, text) =>
    translate 'auto', 'zh-TW', text, (text) ->
      translate 'zh-TW', 'no', text, (text) ->
        say text
  '^%ptlol (.*)$': (source, destination, text) =>
    translate 'auto', 'zh-CN', text, (text) ->
      translate 'zh-CN', 'no', text, (text) ->
        translate 'no', 'ja', text, (text) ->
          translate 'ja', 'en', text, (text) ->
            say text

-- google translate
json = require'json'
simplehttp = require'simplehttp'

languages =
  "af": "Afrikaans",
  "sq": "Albanian",
  "ar": "Arabic",
  "az": "Azerbaijani",
  "eu": "Basque",
  "bn": "Bengali",
  "be": "Belarusian",
  "bg": "Bulgarian",
  "ca": "Catalan",
  "zh-CN": "Simplified Chinese",
  "zh-TW": "Traditional Chinese",
  "hr": "Croatian",
  "cs": "Czech",
  "da": "Danish",
  "nl": "Dutch",
  "en": "English",
  "eo": "Esperanto",
  "et": "Estonian",
  "tl": "Filipino",
  "fi": "Finnish",
  "fr": "French",
  "gl": "Galician",
  "ka": "Georgian",
  "de": "German",
  "el": "Greek",
  "gu": "Gujarati",
  "ht": "Haitian Creole",
  "iw": "Hebrew",
  "hi": "Hindi",
  "hu": "Hungarian",
  "is": "Icelandic",
  "id": "Indonesian",
  "ga": "Irish",
  "it": "Italian",
  "ja": "Japanese",
  "kn": "Kannada",
  "ko": "Korean",
  "la": "Latin",
  "lv": "Latvian",
  "lt": "Lithuanian",
  "mk": "Macedonian",
  "ms": "Malay",
  "mt": "Maltese",
  "no": "Norwegian",
  "fa": "Persian",
  "pl": "Polish",
  "pt": "Portuguese",
  "ro": "Romanian",
  "ru": "Russian",
  "sr": "Serbian",
  "sk": "Slovak",
  "sl": "Slovenian",
  "es": "Spanish",
  "sw": "Swahili",
  "sv": "Swedish",
  "ta": "Tamil",
  "te": "Telugu",
  "th": "Thai",
  "tr": "Turkish",
  "uk": "Ukrainian",
  "ur": "Urdu",
  "vi": "Vietnamese",
  "cy": "Welsh",
  "yi": "Yiddish"

getCode = (language) ->
  for code, lang in pairs languages
    if lang\lower! == language\lower!
      return code
    else if language\lower! == code\lower!
      return code

urlEncode = (str, space) ->
  space = space or '+'
  str = tostring(str)

  str = str\gsub '([^%w ])', (c) ->
    string.format  "%%%02X", string.byte(c)
  return str\gsub(' ', space)

buildQueryStr = (tbl) ->
  out = {}
  for k,v in pairs tbl
    table.insert out, k..'='..urlEncode(v)
  table.concat out, '&'

translate = (origin, target, term, cb) ->
  origin = getCode(origin) or 'auto'
  target = getCode(target) or 'en'
  args =
    client: 'p'
    hl: 'en'
    multires: 1
    sc: 1
    sl: origin
    ssel: 0
    tl: target
    tsel: 0
    uptl: "en"
    text: term

  simplehttp {
    url:"http://translate.google.com/translate_a/t?" .. buildQueryStr(args)
    headers: {
      "User-Agent": "Mozilla/5.0"
      "Accept-Charset": "UTF-8"
    }
  }, (data) ->
    if #data > 4
      parsed = json.decode data
      language = parsed.src
      out = table.concat [k.trans for k in *parsed.sentences]
      if #out > 0
        cb(out)

PRIVMSG:
  '^%ptranslate ([%w%-]+) ([%w%-]+) (.*)$': (source, destination, origin, target, term) =>
    translate origin, target, term, (text) ->
      say text
  '^%ptr ([%w%-]+) ([%w%-]+) (.*)$': (source, destination, origin, target, term) =>
    translate origin, target, term, (text) ->
      say text
  '^%ptlolno (.*)$': (source, destination, text) =>
    translate 'auto', 'zh-TW', text, (text) ->
      translate 'zh-TW', 'no', text, (text) ->
        say text
  '^%ptlol (.*)$': (source, destination, text) =>
    translate 'auto', 'zh-CN', text, (text) ->
      translate 'zh-CN', 'no', text, (text) ->
        translate 'no', 'ja', text, (text) ->
          translate 'ja', 'en', text, (text) ->
            say text


Remove message about not opening a joystick

export ^

class JoyButtonState
	BUTTON_ON: 1
	BUTTON_OFF: 2
	BUTTON_PRESSED: 3
	BUTTON_RELEASED: 4

loveJoystick = nil

if LP.__love "0.8"
	loveJoystick = class
		new: =>
			@@joysticks = {}
			@joystick = nil

		__loveOpen: =>
			i = 1
			for k, v in pairs @@joysticks
				break if k != i
				i += 1

			return if i > love.joystick.getNumJoysticks!
			@@joysticks[i] = true
			@connected = true
			@joystick = i

		close: =>
			return if not @connected
			love.joystick.close @joystick
			@joystick = nil
			@connected = false

		__loveButton: (button) => love.joystick.isDown @joystick button

else if LP.__love "0.9"
	loveJoystick = class
		new: =>
			@@joysticks = love.joystick.getJoysticks! if @@joysticks == nil
			@@opened = {}

		__loveOpen: =>
			i = 1
			for k, v in pairs @@opened
				break if k != i
				i += 1

			return if i > #@@joysticks
			@@opened[i] = @@joysticks[i]
			@__number = i
			@joystick = @@joysticks
			@connected = true

			@buttons[i] = JoyButtonState.BUTTON_OFF for i=1, @joystick\getButtonCount!
			@__last_buttons = {k, v for k, v in pairs @buttons}

		close: =>
			@@opened[@__number] = nil
			@joystick = nil
			@__number = 0
			@connected = false

		__loveButton: (button) => @joystick\isDown button

class Joystick extends loveJoystick
	new: =>
		super!
		-- Each axis contained in an array
		@__axis = {}
		-- A point containing the joystick's ball value
		@ball = Point!
		-- A map of the buttons and their state
		@buttons = {}
		-- A map of the buttons and their state from the previous update
		@__last_buttons = {}
		-- A point containing the joystick's hat value
		@hat = {}
		-- Determines the joystick's deadZone.
		-- Anything under this value will be considered 0 to prevent jitter.
		@deadZone = 0
		-- If the joystick is currently connected.
		@connected = false

		@__loveOpen!

	-- If the joystick button is held down.
	-- @param button The button index to check.
	check: (button) => @buttons[button] == JoyButtonState.BUTTON_ON

	-- Returns the axis value (from 0 to 1)
	-- @param a The axis index to retrieve starting at 0
	getAxis: (a) => @__axis[a]

	-- If the joystick button was pressed this frame.
	-- @param button The button index to check.
	pressed: (button) => @buttons[button] == JoyButtonState.BUTTON_PRESSED

	-- If the joystick button was released this frame.
	-- @param button The button index to check.
	released: (button) => @buttons[button] == JoyButtonState.BUTTON_PRESSED

	-- Updates the joystick's state.
	update: =>
		updateButtons @
		updateAxes @
		updateBalls @
		updateHats @

	updateButtons = =>
		@__last_buttons = {k, v for k, v in pairs @buttons}
		for i=1, #@buttons
			button = @__loveButton i
			if button
				if @__last_buttons[i] == JoyButtonState.BUTTON_PRESSED or @__last_buttons[i] == JoyButtonState.BUTTON_ON
					@buttons[i] = JoyButtonState.BUTTON_ON
				else
					@buttons[i] = JoyButtonState.BUTTON_PRESSED
			else
				if @__last_buttons[i] == JoyButtonState.BUTTON_PRESSED or @__last_buttons[i] == JoyButtonState.BUTTON_ON
					@buttons[i] = JoyButtonState.BUTTON_RELEASED
				else
					@buttons[i] = JoyButtonState.BUTTON_OFF

	updateAxes = =>

	updateBalls = =>

	updateHats = =>

export ^

class JoyButtonState
	BUTTON_ON: 1
	BUTTON_OFF: 2
	BUTTON_PRESSED: 3
	BUTTON_RELEASED: 4

loveJoystick = nil

if LP.__love "0.8"
	loveJoystick = class
		new: =>
			@@joysticks = {}
			@joystick = nil

		__loveOpen: =>
			i = 1
			for k, v in pairs @@joysticks
				break if k != i
				i += 1
			return if i > love.joystick.getNumJoysticks!
			@@joysticks[i] = true
			@connected = true
			@joystick = i

		close: =>
			return if not @connected
			love.joystick.close @joystick
			@joystick = nil
			@connected = false

		__loveButton: (button) => love.joystick.isDown @joystick button

else if LP.__love "0.9"
	loveJoystick = class
		new: =>
			@@joysticks = love.joystick.getJoysticks! if @@joysticks == nil
			@@opened = {}

		__loveOpen: =>
			i = 1
			for k, v in pairs @@opened
				break if k != i
				i += 1

			if i > #@@joysticks
				print "No more joysticks"

			return if i > #@@joysticks
			@@opened[i] = @@joysticks[i]
			@__number = i
			@joystick = @@joysticks
			@connected = true

			@buttons[i] = JoyButtonState.BUTTON_OFF for i=1, @joystick\getButtonCount!
			@__last_buttons = {k, v for k, v in pairs @buttons}

		close: =>
			@@opened[@__number] = nil
			@joystick = nil
			@__number = 0
			@connected = false

		__loveButton: (button) => @joystick\isDown button

class Joystick extends loveJoystick
	new: =>
		super!
		-- Each axis contained in an array
		@__axis = {}
		-- A point containing the joystick's ball value
		@ball = Point!
		-- A map of the buttons and their state
		@buttons = {}
		-- A map of the buttons and their state from the previous update
		@__last_buttons = {}
		-- A point containing the joystick's hat value
		@hat = {}
		-- Determines the joystick's deadZone.
		-- Anything under this value will be considered 0 to prevent jitter.
		@deadZone = 0
		-- If the joystick is currently connected.
		@connected = false

		@__loveOpen!

	-- If the joystick button is held down.
	-- @param button The button index to check.
	check: (button) => @buttons[button] == JoyButtonState.BUTTON_ON

	-- Returns the axis value (from 0 to 1)
	-- @param a The axis index to retrieve starting at 0
	getAxis: (a) => @__axis[a]

	-- If the joystick button was pressed this frame.
	-- @param button The button index to check.
	pressed: (button) => @buttons[button] == JoyButtonState.BUTTON_PRESSED

	-- If the joystick button was released this frame.
	-- @param button The button index to check.
	released: (button) => @buttons[button] == JoyButtonState.BUTTON_PRESSED

	-- Updates the joystick's state.
	update: =>
		updateButtons @
		updateAxes @
		updateBalls @
		updateHats @

	updateButtons = =>
		@__last_buttons = {k, v for k, v in pairs @buttons}
		for i=1, #@buttons
			button = @__loveButton i
			if button
				if @__last_buttons[i] == JoyButtonState.BUTTON_PRESSED or @__last_buttons[i] == JoyButtonState.BUTTON_ON
					@buttons[i] = JoyButtonState.BUTTON_ON
				else
					@buttons[i] = JoyButtonState.BUTTON_PRESSED
			else
				if @__last_buttons[i] == JoyButtonState.BUTTON_PRESSED or @__last_buttons[i] == JoyButtonState.BUTTON_ON
					@buttons[i] = JoyButtonState.BUTTON_RELEASED
				else
					@buttons[i] = JoyButtonState.BUTTON_OFF

	updateAxes = =>

	updateBalls = =>

	updateHats = =>


Updated controller

Updated controller

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        @IGNORE_DRAW = false
        super(ent)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        @IGNORE_DRAW = false
        super(ent)

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


Added flee steering behavior.

Added flee steering behavior.

System = require('vendor/secs/lib/system')
Vector = require('lib/geo/vector')

class NpcSteeringSystem extends System

	@criteria: System.Criteria({ 'isNpc', 'position', 'maxSpeed', 'maxForce', 'target' })

	update: (dt) =>
		for entity in *@entities
			velocity = @flee(entity, dt)
			entity\set('velocity', velocity)

	-- Direct path to target
	naive: (entity, dt) =>
		{ :position, :maxSpeed, :target } = entity\get()
		return Vector(target.position - position, maxSpeed) * dt

	-- Steers toward target
	seek: (entity, dt) =>
		{ :position, :velocity, :maxSpeed, :target, :maxForce } = entity\get()
		desiredVelocity = @naive(entity, dt)
		if not velocity then velocity = Vector.ZERO
		steering = desiredVelocity - velocity
		steering = Vector\truncate(steering, maxForce)
		velocity = Vector\truncate(velocity + steering, maxSpeed)
		return velocity

	-- Steers away from target
	flee: (entity, dt) =>
		{ :position, :velocity, :maxSpeed, :target, :maxForce } = entity\get()
		desiredVelocity = -@naive(entity, dt)
		if not velocity then velocity = Vector.ZERO
		steering = desiredVelocity - velocity
		steering = Vector\truncate(steering, maxForce)
		velocity = Vector\truncate(velocity + steering, maxSpeed)
		return velocity

System = require('vendor/secs/lib/system')
Vector = require('lib/geo/vector')

class NpcSteeringSystem extends System

	@criteria: System.Criteria({ 'isNpc', 'position', 'maxSpeed', 'maxForce', 'target' })

	update: (dt) =>
		for entity in *@entities
			@seek(entity, dt)

	naive: (entity, dt) =>
		{ :position, :maxSpeed, :target } = entity\get()
		velocity = Vector(target.position - position, maxSpeed) * dt
		entity\set('velocity', velocity)

	seek: (entity, dt) =>
		{ :position, :velocity, :maxSpeed, :target, :maxForce } = entity\get()
		desiredVelocity = Vector(target.position - position, maxSpeed) * dt
		if not velocity then velocity = Vector.ZERO
		steering = desiredVelocity - velocity
		steering = Vector\truncate(steering, maxForce)
		velocity = Vector\truncate(velocity + steering, maxSpeed)
		entity\set('velocity', velocity)


Registers

Registers

bundle_load = bundle_load
print = print
pairs = pairs
append = table.insert

howl.util.lpeg_lexer ->
  c = capture

  id = (alpha + S'._?')^1 * (alpha + digit + S'_$#@~.?')^0
  ws = c 'whitespace', blank^0
  string_contents = any {
    span "'", "'"
    span '"', '"'
    span '`', '`', '\\'
  }

  identifier = c 'identifier', id

  ul = (c) -> P(c)+P(c\upper!)
  ult = (w) -> [ul c for c in w\gmatch '.']
  uls = (w) -> any ult w
  ulq = (w) -> sequence ult w
  case_word = (words) ->
    any [ulq w for w in *words]

  keyword = c 'keyword', case_word {
    'abs', 'alignb', 'align', 'at', 'byte', 'default', 'db', 'dd', 'do', 'dq',
    'dt', 'dword', 'dw', 'endstruc', 'equ', 'iend', 'incbin', 'istruc',
    'nosplit', 'opsize', 'oword', 'qword', 'rel', 'resb', 'resd', 'reso',
    'resq', 'rest', 'resw', 'resy', 'resz', 'sectalign', 'struc', 'strict',
    'times', 'seq', 'tword', 'word', 'wrt', 'yword', 'zword'
  }

  instrs = bundle_load 'instructions'
  instr = c 'keyword', P (file, pos) ->
    word = file\sub(pos)\match'^%a+'
    if word and instrs[word\lower!]
      pos + #word
    else
      false

  macro = c 'preproc', P'%' * any {
    span '[', ']'
    P'!' * (id + string_contents)^-1
    P'??'
    P'00'
    S'+?0'
    word {
      'arg', 'assign', 'define', 'defstr', 'deftok', 'depend', 'error', 'fatal',
      'ifctx', 'ifdef', 'ifempty', 'ifenv', 'ifidni', 'ifidn', 'ifmacro',
      'iftoken', 'if','include', 'line', 'local', 'macro', 'pathsearch', 'pop',
      'push', 'stacksize', 'strcat', 'strlen', 'substr', 'repl', 'rep', 'rotate',
      'xdefine', 'undef', 'unmacro', 'use', 'warning'
    }
  }

  comment = c 'comment', P';' * scan_until eol

  operator = c 'operator', any {
    S'\\:,()[]+*-/%|^&<>~!@'
    case_word {
      '__float8__', '__float16__', '__float32__', '__float64__', '__float80m__',
      '__float80e__', '__float128l__', '__float128h__',
      '__utf16__', '__utf32__'
    }
  }

  special = c 'special', (P'__USE_' * id * '__') + word {
    '__BITS__', '__DATE_NUM__', '__DATE__', '__FILE__', '__Infinity__',
    '__LINE__', '__NASM_VERSION_ID__', '__NASM_VER__', '__NaN__',
    '__POSIX_TIME__', '__PASS__', '__OUTPUT_FORMAT__', '__QNaN__', '__SNaN__',
    '__TIME_NUM__', '__TIME__', '__UTC_DATE_NUM__', '__UTC_DATE__',
    '__UTC_TIME_NUM__','__UTC_TIME__'
  }

  gen_regs = ->
    gen =
      ax: true
      cx: true
      dx: true
      bx: true
      sp: false
      bp: false
      si: false
      di: false

    res = {}
    ins = (p) -> append res, P(p)

    for regbase, hl in pairs gen
      ins S'erER'^-1 * ulq regbase
      ins ul(regbase\sub 1, 1) * S'hlHL' if hl

    ins S'sScCdDeEfFgG' * S'sS'
    for i=0,15
      ins S'rR' * P"#{i}" * S'dDwWlL'^-1

    for i=0,7
      ins S'xX'^-1 * S'mM' * S'mM' * P"#{i}"
      ins S'sS' * S'tT' * P"#{i}"

    any res

  reg = c 'special', gen_regs!

  make_num_set = (chr0, chr1, letters, bare_prefix, dec) ->
    chr = if chr1
      chr0 + chr1
    else
      chr0
    usc = chr + P'_'
    digit = chr * usc^0
    seq = digit^1
    oseq = digit^0
    float_suf = P'.' * oseq
    exp_suf = ul'e' * S'+-'^-1 * seq
    p_suf = ul'p' * S'+-'^-1 * oseq

    id_prefix = P'0' * letters
    id_prefix += bare_prefix * #chr if bare_prefix

    run = seq^-1 * float_suf^-1 * (exp_suf + p_suf)^-1

    if dec
      chr * run * letters^-1
    else
      (id_prefix * chr * run) + (chr0 * run * letters)

  number = c 'number', S'+-'^-1 * any {
    make_num_set R'01', nil, uls'by'
    make_num_set R'07', nil, uls'oq'
    make_num_set R'09', R'af' + R'AF', uls'hx', P'$'
    make_num_set R'09', nil, uls'dt', nil, true
  }

  string = c 'string', string_contents

  any {
    comment
    keyword
    instr
    special
    reg
    number
    macro
    operator
    identifier
  }

bundle_load = bundle_load
print = print

howl.util.lpeg_lexer ->
  c = capture

  id = (alpha + S'._?')^1 * (alpha + digit + S'_$#@~.?')^0
  ws = c 'whitespace', blank^0
  string_contents = any {
    span "'", "'"
    span '"', '"'
    span '`', '`', '\\'
  }

  identifier = c 'identifier', id

  ul = (c) -> P(c)+P(c\upper!)
  ult = (w) -> [ul c for c in w\gmatch '.']
  uls = (w) -> any ult w
  case_word = (words) ->
    any [sequence ult w for w in *words]

  keyword = c 'keyword', case_word {
    'abs', 'alignb', 'align', 'at', 'byte', 'default', 'db', 'dd', 'do', 'dq',
    'dt', 'dword', 'dw', 'endstruc', 'equ', 'iend', 'incbin', 'istruc',
    'nosplit', 'opsize', 'oword', 'qword', 'rel', 'resb', 'resd', 'reso',
    'resq', 'rest', 'resw', 'resy', 'resz', 'sectalign', 'struc', 'strict',
    'times', 'seq', 'tword', 'word', 'wrt', 'yword', 'zword'
  }

  instrs = bundle_load 'instructions'
  instr = c 'keyword', P (file, pos) ->
    word = file\sub(pos)\match'^%a+'
    if instrs[word]
      pos + #word
    else
      false

  macro = c 'preproc', P'%' * any {
    span '[', ']'
    P'!' * (id + string_contents)^-1
    P'??'
    P'00'
    S'+?0'
    word {
      'arg', 'assign', 'define', 'defstr', 'deftok', 'depend', 'error', 'fatal',
      'ifctx', 'ifdef', 'ifempty', 'ifenv', 'ifidni', 'ifidn', 'ifmacro',
      'iftoken', 'if','include', 'line', 'local', 'macro', 'pathsearch', 'pop',
      'push', 'stacksize', 'strcat', 'strlen', 'substr', 'repl', 'rep', 'rotate',
      'xdefine', 'undef', 'unmacro', 'use', 'warning'
    }
  }

  comment = c 'comment', P';' * scan_until eol

  operator = c 'operator', any {
    S'\\:,()[]+*-/%|^&<>~!@'
    case_word {
      '__float8__', '__float16__', '__float32__', '__float64__', '__float80m__',
      '__float80e__', '__float128l__', '__float128h__',
      '__utf16__', '__utf32__'
    }
  }

  special = c 'special', (P'__USE_' * id * '__') + word {
    '__BITS__', '__DATE_NUM__', '__DATE__', '__FILE__', '__Infinity__',
    '__LINE__', '__NASM_VERSION_ID__', '__NASM_VER__', '__NaN__',
    '__POSIX_TIME__', '__PASS__', '__OUTPUT_FORMAT__', '__QNaN__', '__SNaN__',
    '__TIME_NUM__', '__TIME__', '__UTC_DATE_NUM__', '__UTC_DATE__',
    '__UTC_TIME_NUM__','__UTC_TIME__'
  }

  make_num_set = (chr0, chr1, letters, bare_prefix, dec) ->
    chr = if chr1
      chr0 + chr1
    else
      chr0
    usc = chr + P'_'
    digit = chr * usc^0
    seq = digit^1
    oseq = digit^0
    float_suf = P'.' * oseq
    exp_suf = ul'e' * S'+-'^-1 * seq
    p_suf = ul'p' * S'+-'^-1 * oseq

    id_prefix = P'0' * letters
    id_prefix += bare_prefix * #chr if bare_prefix

    run = seq^-1 * float_suf^-1 * (exp_suf + p_suf)^-1

    if dec
      chr * run * letters^-1
    else
      (id_prefix * chr * run) + (chr0 * run * letters)

  number = c 'number', S'+-'^-1 * any {
    make_num_set R'01', nil, uls'by'
    make_num_set R'07', nil, uls'oq'
    make_num_set R'09', R'af' + R'AF', uls'hx', P'$'
    make_num_set R'09', nil, uls'dt', nil, true
  }

  string = c 'string', string_contents

  any {
    comment
    keyword
    instr
    special
    number
    macro
    operator
    identifier
  }