Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
236 lines (179 sloc) 12.2 KB

Функции в Lua и квестах

Функции позволяют выполнять определенный набор или последовательность действий. Основное назначение встроенных функций — это совершение уникальных действий, а назначение самопальных функций — возможность сократить количество кода, пакуя повторящийся код в функции.

Встроенные функции

Основное назначение квестов — это использование квестовых функций. Квестовые функции вшиты в ядро сервера и могут сообщать ту или иную информацию. Например, функция pc.get_name() сообщает имя игрока:

quest example begin
	state start begin
	
		--[[
			Если ник игрока "terron", то представить в своей голове данную строку можно так:

			when login with "terron" == "terron" begin

			Вместо функции как бы подставляется значение, которое она сообщает.
		]]
		
		when login with pc.get_name() == "terron" begin
			syschat("Привет, terron! ")
		end
	end
end

На самом деле, правильнее говорить не «сообщают», а «возвращают», поэтому дальше мы будем придерживаться именно этого термина.

Встроенные функции могут возвращать данные любого типа. Вот несколько примеров:

quest example begin
	state start begin
		when login begin
			syschat("Привет, " .. pc.get_name() .. "! ")
			syschat("Ваш уровень - " .. pc.get_level()) -- сообщает уровень игрока (тип number)
			syschat("Ваш баланс - " .. pc.get_gold() .. " янг. ") -- сообщает количество янг игрока (тип number)

			if pc.is_gm() then -- сообщает, является ли игрок администратором (тип boolean)
				syschat("Хорошего рабочего дня, уважаемый администратор! ")
			else
				syschat("Отличного фарма и удачи, уважаемый игрок! ")
			end
		end
	end
end

Также с помощью квестовых функций можно менять информацию об игроке. В данном примере мы при каждом входе в игру функцией pc.change_gold() будем увеличивать баланс янг игрока на 500:

quest example begin
	state start begin
		when login begin
			local gold = 500

			syschat("Привет, " .. pc.get_name() .. "! Вам было начислено " .. gold .. " за то, что вы крутой! ")

			pc.change_gold(gold)
		end
	end
end

Т.к. функция pc.change_gold() ничего не возвращает, то бишь возвращает nil (вы не забыли, что nil — это «ничего» или просто «пустота»?), то заключать ее в переменную или объединять с какой-либо строкой смысла нет. Она просто меняет баланс игрока и всё.

Мы передали в данную функцию число 500 как параметр. Функции могут принимать так называемые параметры (также известны как «аргументы функции»). Параметры заключаются в скобки, идущие после названия функции. Если параметров несколько, то они разделяются запятыми:

quest example begin
	state start begin
		when login begin		
			syschat("Привет, " .. pc.get_name() .. "! Вы получили 5 красных зелий за то, что вы крутой! ")

			--[[
				27001 - это vnum красного зелья
				5 - это количество
			]]

			pc.give_item2(27001, 5) -- данная функция выдает игроку определенный предмет в определенном количестве
		end
	end
end

Некоторые функции возвращают не одно, а несколько значений. Это одна из особенностей языка Lua. Правда, подобных встроенных функций очень мало. Например, функция pc.get_start_location() сообщает индекс локации и координаты площади первого города игрока в зависимости от его империи. Работать с такими функциями нужно так:

quest example begin
	state start begin
		when login begin
			local index, coordinate_x, coordinate_y = pc.get_start_location()

			syschat("Индекс вашего первого города: " .. index)
			syschat("Координата по оси X: " .. coordinate_x)
			syschat("Координата по оси Y: " .. coordinate_y)
		end
	end
end

Подробнее о том, сколько значений и вообще что возвращает функция, можно узнать из статьи о ней — в этом репозитории задокументировано большинство квестовых функций.

Самопальные функции

Вы можете самостоятельно создавать функции в Lua, например, чтобы не писать один и тот же код по несколько раз. Самый простой способ создать функцию:

quest example begin
	state start begin
		function calculate_ab(a, b)
			return a + b
		end

		when login begin
			local beer, vodka = 500, 800
			syschat(example.calculate_ab(beer, vodka)) --> 1300
		end
	end
end

Правила именования функций такие же, как у переменных, ведь функции тоже являются переменными, просто вместо числел и строк они хранят в себе тип данных function. Внутри квестов функции могут задаваться только внутри state.

В примере выше мы задали функцию внутри state. Когда функция задается внутри state, то при ее вызове обязательно надо указывать перед ней название квеста (example.calculate_ab()). Область видимости у функций ограничивается всем квестом, независимо от того, в какой стадии была задана функция:

--[[
	При каждом входе в игру игрок будет видеть разные сообщения:
]]

quest example begin
	state start begin
		function calculate_ab(a, b)
			return a + b
		end

		when login begin	
			syschat("Start: " .. example.calculate_ab(1, 2)) --> Start 3

			set_state("test")
		end
	end

	state test begin
		when login begin	
			syschat("Test: " .. example.calculate_ab(3, 4)) --> Test 7

			set_state("start")
		end
	end
end

Функции создаются при помощи ключевого слова function. После ключевого слова идет название функции и в скобках заключаются параметры функции. Параметры указываются как переменные и область видимости у этих переменных будет локальной только внутри функции. Наша функция calculate_ab() принимает 2 числа и считает их, а затем возвращает значение ключевым словом return. Код, идущий внутри секции ниже return, уже не исполняется:

quest example begin
	state start begin
		function calculate_ab(a, b)
			local val = a + b

			return val

			syschat("Посчитали и вот: " .. val) -- данное сообщение мы не увидим, т.к. выполнение секции закончилось на return
		end

		when login begin		
			local beer, vodka = 500, 800
			syschat(example.calculate_ab(beer, vodka)) --> 1300
		end
	end
end

Если не передавать в return каких-либо значений, то функция ничего не вернет, то бишь nil:

quest example begin
	state start begin
		function calculate_ab(a, b)
			local val = a + b

			syschat("Посчитали и вот: " .. val)

			return

			syschat("Второе сообщение... ") -- это сообщение мы не увидим
		end

		when login begin		
			local beer, vodka = 500, 800

			local how_much = example.calculate_ab(beer, vodka) -- в этот момент появится сообщение "Посчитали и вот: 1300", так как в этот момент исполняется функция calculate_ab()

			if how_much then
				syschat(how_much) -- мы не увидим это сообщение т.к. how_much == nil
			end
		end
	end
end

В отличие от оригинального Lua, внутри квестов динамически создавать функции через переменные нельзя. Зато функции можно создавать глобально. Глобальные функции можно будет использовать во всех квестах, а не только в том, в котором она была создана. Такие функции создаются в файле questlib.lua. Особенность этого файла в том, что код, находящийся в нем, исполняется только один раз во время запуска сервера. То есть мы объявляем в этом файле функцию один раз, файл запускается сервером один раз и на время работы сервера он будет помнить о том, что существуют такие-то функции и переменные, заданные в questlib.lua. Добавьте в самый конец файла нашу функцию:

function calculate_ab(a, b)
	local val = a + b

	return val
end

Также функции в questlib.lua можно задавать как переменные (а в самих квестах нельзя!). Результат данного примера будет идентичен примеру выше:

local calculate_ab = function(a, b)
	local val = a + b

	return val
end

И чтобы функция начала работать в квестах, ее необходимо добавить в файл quest_functions (без расширения). Просто в конец файла добавьте calculate_ab и всё. Не забудьте про то, что последние строки в файлах должны быть пустыми! Теперь нашу функцию можно использовать в квестах:

quest example begin
	state start begin
		when login begin		
			local beer, vodka = 500, 800

			syschat(calculate_ab(beer, vodka)) --> 1300
		end
	end
end

Обратите внимание на то, что при использовании функций, заданных глобально, использовать приставку в виде названия квеста не нужно.