Можно добавить еще VHS фильтр, например вот
И эффект “рыбьего глаза”, гайд
гайд полностью написан мной (t1m1yep) при помощи своих знаний и документации Lua для octothorp team и его сообщества 
обязательно изучи прошлую часть, перед изучением второй!
еще раз привет! меня зовут тимофей и во второй части Луа для чайников мы изучим:
таблица представляет из себя “массив”, который вместо индекса имеет ключ. рассмотрим на примере:
local mytable = {} -- инициализируем пустую таблицу
local key = "taiwan" -- создаем переменную-строку "ключ"
mytable[key] = "roobys" - задаем значение обьекту таблицы с ключом который мы создали ранее
print(mytable[key]) -- выводим значение обьекта таблицы с ключом key!
этот код выведет строку “roobys”. давайте немного изменим этот код, в частности, последнюю строку:
local mytable = {} -- инициализируем пустую таблицу
local key = "taiwan" -- создаем переменную-строку "ключ"
mytable[key] = "roobys" - задаем значение обьекту таблицы с ключом который мы создали ранее
print(mytable) -- выводим таблицу без ключа! саму переменную
выведется что то по типу “table: 0x158e09d80”
что это?!
это адрес таблицы в памяти компьютера. ее местоположение, ячейка, которую она занимает в ОЗУ
мы можем инициализировать таблицу по другому:
local mytable = {["skumbri"]="скумбри", ["р12"]="r12", ["zverok99"]="зверек99"}
в этом случае мы заранее инициализировали обьекты нашей таблицы и ключи к ним. mytable с ключом “skumbri” хранит значение “скумбри”!
также мы можем создать таблицу-матрешку:
local octothorp_team = {
managers = {["inquizzy"]="инквиззи", ["vondik"]="вондик"},
admins = {["skumbri"]="скумбри", ["campot"]="кампот"}
}
print(octothorp_team.managers["inquizzy"])
print(octothorp_team.admins["campot"])
только в этом случае нам надо будет обращаться к под-таблицам через точку “.”
примечание: ключи могут быть как и строками, так и числами и даже boolean’ами
примечание: ключи в таблицах указываются в квадратных скобках, а после, через равно идет значение
пример итерации по обьектам таблицы:
local octothorp_team = {["doctor"]="доктор",["kilo7"]="кило-семь", ["polkin"]="полкин"}
for key, value in pairs(octothorp_team) do
print(key, value)
end
в этом случае я использовал функцию pairs()
этот код выведет:
polkin полкин
kilo7 кило-семь
doctor доктор
замыкания - “мини функции”
рассмотрим на примере:
local myfunction = function (a, b)
return a + b
end
print(myfunction(10, 10))
для удобства и чистоты кода - сделаем обьявление функции-замыкания однострочным
local myfunction = function (a, b) return a + b end
print(myfunction(10, 10))
получается, что мы задаем нашей переменной myfunction значение функции. уже забыл?! функция - это тоже тип данных! я говорил об этом в первой части.
мы можем вызывать эту переменную точно также как и функцию. рассмотрим еще один пример:
function create_closure()
return function(a, b) return a + b end
end
local closure_function = create_closure()
print(closure_function(1, 2))
closure - замыкание по английски.
мы создаем функцию, которая возвращает функцию-замыкание, а эта функция-замыкания суммирует два числа. получается, что функции точно также могут возвращать функции-замыкания с помощью return. прямо как обычные числа и строки!
был бы это си… ой, что-то я замечался, продолжим!
строки имеют свою собственную библиотеку! как бы это банально не звучало, звать ее - string!
рассмотрим функцию gsub библиотеки string. она может заменить часть строки!
local a = "доброград плохой сервер" -- создаем строку
local b = string.gsub(a, "плохой", "крутой") -- меняем часть строки и записываем в другую переменную
print(a) -- неправильная строка
print(b) -- правильная строка
**выводом будет: **
доброград плохой сервер
доброград крутой сервер
аргументы функции gsub() - первоначальная строка, с которой будут проводится манипуляции; слово которое должно быть изменено; слово НА которое надо изменить
функция gsub() возвращает обновленную строку
задний слэш - “” в составе строки может иметь после себя определенную букву. каждая строка заканчивается на “\0” - nil символ, он обозначает конец строки. ты его даже не замечаешь! но запомни это, ведь любой инструмент может тебе пригодится (даже старая мышь, вдруг новая сломается!)
\n - знак новой строки. все что будет после него - с новой строки
\t - табуляция
\r - очистить всю консоль! (не ставь это в конце, иначе ничего не увидишь
лучше ставь в начале!)
также имеется большое количество таких операций, их ты можешь найти в интернете.
наверняка многие из вас видели этот мем

это происходит из за сложения строк
local яблоко = "яблоко"
local одно = "одно"
local одно_яблоко = одно + яблоко
да, баян, но я считаю что стоит осветить эту тему 
также мы получим ошибку если попытаемся провести операцию с двумя разными типами:
local chelog = "Дмитрий Антонов"
local pi = 3.14
local pichelog = chelog + pi -- выдаст ошибку, мы не можем сложить Дмитрия Антонова и 3.14
print(pichelog)

– таинственный кодер
ты до этого применял конструкторы, с таблицами и массивами! да-да, те самые фигурные скобки при создании таблиц и массивов - конструкторы. давай посмотрим пример:
local массив_админов = {"r12", "skumbri", "campot", "timetocoffee", "what"}
local таблица_админов = {["рубус"]="roobys", ["эр12"]="r12", ["скумбре"]="skumbri", ["кампот"]="campot", ["кофейня"]="timetocoffee"}
print(массив_админов[3]) -- выведет timetocoffee
print(таблица_админов["эр12"]) -- выведет r12
чтобы создавать чистый и красивый код в больших проектах, скорее всего, тебе придется прибегать к разделению кода по разным категориям
представим такую ситуацию: ты вывел в отдельный файл одну очень сложную функцию (нет) которая возвращает строку “Дмитрий Антонов” и теперь хочешь использовать эту функцию и библиотеку в основном файле. тут тебе поможет require:
файл chelog_library.lua
function dmitry_antonov()
return "Дмитрий Антонов"
end
файл main.lua
require "chelog_library"
local dima = dmitry_antonov()
print(dima)
почему ты написал только название файла в require? где расширение .lua??
если вы импортируете локальный файл, которого нет папке всех библиотек lua, указывайте только название файла, иначе компьютер будет искать его в корне библиотек и он ее просто не найдет!
также вы можете импортировать из папки:

в таком случае понадобится указать дочернюю папку в main.lua:
require "libs/chelog_library"
local dima = dmitry_antonov()
print(dima)
в файле библиотеки ничего менять не нужно.
но что если main.lua тоже находится в папке?

в таком случае нам надо задать package.path перед require:
package.path = package.path .. ";../libs/chelog_library.lua"
require("chelog_library")
local dima = dmitry_antonov()
print(dima)

а если библиотека находится вне папки libs, а просто папкой выше main.lua, мы можем убрать из package.path путь в папку “/libs”:
package.path = package.path .. ";../chelog_library.lua"
require("chelog_library")
local dima = dmitry_antonov()
print(dima)
рассмотрим несколько условий:
local lovechelog = true
if lovechelog then
print("i love chelog")
elseif not lovechelog then
print("deleting system...")
end
выведется “i love chelog”, а если заменить lovechelog на false, выведется “deleting system…”
ключевое слово “not” буквально обозначает “не”
в случае с булевым значениями не обязательно указывать сравнение по типу: “if boolean == true …”, можно просто написать “if boolean …”, это будет означать одно и тоже. а если надо указать “if boolean == false …”, можно написать “if not boolean”, это означает тоже самое.
elseif входит в состав конструкции if, так как end у них общий. elseif используется только в случае повторения условия с участием одной и той же переменной.
|| - “или”
if 10 > 5 || 20 > 21 then -- выполнится только первая часть условия, но само условие выполнится
print("octothorp team") -- надпись выведется
end
if 10 < 5 || 20 < 21 then -- выполнится только вторая часть условия, но само условие выполнится
print("octothorp team") -- надпись выведется
end
&& - “также”
if 10 > 5 && 20 > 10 then -- условие выполнится
print("octothorp team") -- надпись выведется
end
if 10 > 5 && 20 < 10 then -- условие не выполнится, так как вторая часть не выполнена
print("octothorp team") -- надпись НЕ выведется
end
каждый разработчик имеет дело с ошибками и удерживает их (нервно пытается)
функция error() принимает строку, которую будет печатать в консоль
error("ошибка!")
выведет:

давайте напишем простенькую программу, которая будет выдавать ошибку если мы будем пытаться прибавить число к строке:
local dima = "dima"
local num1 = 10
local numdima = assert(type(num1) == "string", "num1 не должно быть числом") -- assert() вернет false и выключит программу
print(numdima) -- мы никогда не узнаем...
print(dima, num1) -- мы никогда не узнаем...

поменяем переменную num1 на строку:
local dima = "dima"
local num1 = "antonov"
local numdima = assert(type(num1) == "string", "num1 не должно быть числом") -- assert() вернет true
print(numdima) -- выведет true
print(dima, num1) -- выведет "dima antonov"

корутина - асинхронный блок кода (по очереди), мы можем в любой момент остановить ее выполнение, создать другую. они позволяют нам выполнять много кода одновременно, не замедляя выполнение одного другим
создадим корутину:
корутина = coroutine.create(function ()
print("привет!") -- не выведется, так как горутина запускается в другом потоке!
end)
print(корутина) -- выведет thread: <адрес потока в котором запускается горутина>
print(coroutine.status(co)) -- выведет suspended, корутина приостановлена
coroutine.resume(co) -- выведет тот самый "привет!" в консоль, однако пожертвует своей жизнью (я не шучу)
print(coroutine.status(co)) -- выведет dead... корутина умерла..
немного исправим код и добавим coroutine.yield():
корутина = coroutine.create(function () -- создаем корутину
for i=1,3 do -- создаем цикл, он запустится три раза
print("корутина с числом", i) -- печатаем номер итерации цикла
coroutine.yield() -- функция yield() делает статус suspended, тоесть приостановлена
end
end)
coroutine.resume(корутина) -- теперь мы возобновим коротину. три раза. выведет число 1
print(coroutine.status(корутина)) -- статус suspended, так как после каждой итерации корутина приостанавливает себя и ждет возобновления
coroutine.resume(корутина) -- выведет число 2
print(coroutine.status(корутина)) -- suspended!
coroutine.resume(корутина) -- выведет число 3
print(coroutine.status(корутина)) -- suspended!
если мы попытаемся возобновить коротину через coroutine.resume() которая уже мертва, мы получим ошибку
мы также можем приостанавливать и возобновлять корутину с аргументами:
корутина = coroutine.create(function (a,b) -- коротина-замыкание с двумя аргументами
coroutine.yield(a + b, a - b) -- приостанавливаем корутину с аргументами для возобновления
end)
print(coroutine.resume(корутина, 20, 10)) -- даем те самые аргументы из yield(). выведет 30
также коротина может возвращать значения как обычная функция:
корутина = coroutine.create(function ()
return 6, 7 -- возвращаем числа 6 и 7
end)
print(coroutine.resume(корутина)) -- выведет "6 7"
глаза сильно болят и я уже хочу спать, 11 вечера по моему времени я сейчас лопну
(если что, я встал в 6)
@тимиеп Пиздануться можно, но прикольно!