[#=contents]//=============================================
[goto=intro]1. Что такое GetLocalPlayer()?[/goto]
[goto=desync]2. GetLocalPlayer() и десинхронизации.[/goto]
[goto=players]3. Игроки в JASS.[/goto]
[goto=purpose]4. Основное назначение GetLocalPlayer().[/goto]
[goto=handles]5. Рассинхронизация хэндлов.[/goto]
[goto=manipulating]6. Управление системой игры.[/goto]
[goto=usage]7. Обычное использование.[/goto]
[goto=forces]8. Выполнение действий для кланов.[/goto]
[goto=outro]9. Заключение.[/goto]
//=============================================
[#=intro]
1. Что такое GetLocalPlayer()? [goto=contents][ent=#x2191][/goto] [code=jass]constant native GetLocalPlayer takes nothing returns player[/code]
GetLocalPlayer() - одна из полезнейших функций common.j, однако также одна из опаснейших. GetLocalPlayer() - функция, которая запускает часть действий для конкретного игрока. Поэтому при правильном её использовании можно совершить действие для конкретного игрока, для остальных же это действие совершено не будет.
[#=desync]
2. GetLocalPlayer() и десинхронизации. [goto=contents][ent=#x2191][/goto] GetLocalPlayer() - функция, которую можно назвать десинхронизирующей. Десинхронизации - это ошибки, которые при многопользовательской игре могут отсоединять всех игроков от игры (за исключением, может быть, хоста). В этой статье я расскажу, как следует использовать GetLocalPlayer(), чтобы не было никаких проблем.
[#=players]
3. Игроки в JASS. [goto=contents][ent=#x2191][/goto] В JASS номера игроков имеют диапазон от 0 до 11, а не от 1 до 12.
Вообще-то, от 0 до 15, если учитывать нейтральных. Помните об этом, когда будете делать что-либо подобное:
[code=jass]if GetLocalPlayer() == Player(7) then
//Player(7) - это Игрок 8 (Розовый)
endif[/code]
Также часто встречаются следующие виды игроков:
[code=jass]GetTriggerPlayer()
GetOwningPlayer(GetTriggerUnit())[/code]
Первый - это игрок, реагирующий на событие триггера, а второй - это владелец реагирующей на событие триггера боевой единицы.
[#=purpose]
4. Основное назначение GetLocalPlayer(). [goto=contents][ent=#x2191][/goto] GetLocalPlayer() может совершать действие для определённого игрока, как было сказано ранее. А сейчас давайте посмотрим на простой пример блока GetLocalPlayer():
[code=jass]function Test takes nothing returns nothing
if GetLocalPlayer() == Player(0) then
//Действия
endif
endfunction[/code]
Давайте проведём то, что я называю разбором полётов. Мы разобьём функцию на части и покажем, что они делают. Затем соберем части воедино и получим общий смысл функции.
function Test takes nothing returns nothing - Функция Test ничего не берёт и ничего не возвращает.
if GetLocalPlayer() - Если игрок, у которого запущен этот триггер...
== Player(0) then - ... - это Игрок 1 (Красный), тогда...
//Действия - ... совершаем эти действия.
endif/endfunction - Закрываем блок условия и блок функции.
Отсюда следует, что действия, которые находятся в этом блоке запустятся только для Игрока 1 (Красного).
[#=handles]
5. Рассинхронизация хэндлов. [goto=contents][ent=#x2191][/goto] Сначала покажу вам пример:
[code=jass]function Test takes nothing returns nothing
if GetLocalPlayer() == Player(0) then
call AddSpecialEffect("none.mdl", .0, .0)
//Будет ли десинхронизация?
endif
endfunction[/code]
Это десинхронизирующий код, так как:
[code=jass]native AddSpecialEffect takes string modelName, real x, real y returns effect[/code]
Эта функция возвращает effect...
[code=jass]type effect extends handle[/code]
... а effect наследуется от handle.
Примечание. Начиная с патча 1.24[code=jass]type effect extends agent[/code]эффект наследуется от agent,[code=jass]type agent extends handle // all reference counted objects[/code]а agent наследуется от handle.
Это значит, что вы создадите хэндл. Создание хэндлов для игроков очень опасно и почти всегда ведёт к десинхронизации.
Существует особая функция, которая называется "Typecasting - Handle to Integer". Конвертирование хэндла в целочисленную вернёт нам значение хэндла. Итак, давайте посмотрим на функцию:
[code=jass]function H2I takes handle h returns integer
return h
return 0
endfunction
//Примечание: функция выше не работает на патчах 1.24 и выше. Используйте вместо нее следующую функцию:
native GetHandleId takes handle h returns integer[/code]
Это простой трюк, парсер JASS проверяет только последнее значение return. Вот в чём состоит трюк - мы даём функции хэндл, хотя на самом деле нужно дать ей целочисленную. Используя эту функцию, мы можем легко получить значение хэндла. Если оно будет больше, чем 0х100000 ("0x" означает, что число записано в шестнадцатеричной системе счисления. 100000
16 == 1048576
10), то функция вызовет десинхронизацию при создании в блоке. После проверки многих хэндлов вы можете получить значения типа 1048670 или 1048576 (в зависимости от того, сколько объектов вы создали). Чтобы проверить полученное значение, можно использовать что-то на манер этого:
[code=jass]function Wootage takes nothing returns nothing
local location l = Location(.0, .0)//Создадим хэндл.
call BJDebugMsg(I2S(GetHandleId(l)))//Получим его ID и выведем на экран.
call RemoveLocation(l)//Удалим его.
set l = null//Обнулим переменную, чтобы хэндл мог быть удален из памяти.
endfunction[/code]
И значение будет показано в игре.
Но как насчет "особенных" хэндлов?
[code=jass]function Wootage takes nothing returns nothing
local texttag t = CreateTextTag()
call BJDebugMsg(I2S(GetHandleId(t)))
call DestroyTextTag(t)
set t = null
endfunction[/code]
Скорее всего, функция вернёт число
99, если больше не будет всплывающих текстов.
Механизм выделения некоторых хэндлов отличается от обычного. Почему 0х100000? Обычно хэндлы создаются с внутренним ID (порядковым номером) 0x100000. Это откуда они начинаются. Каждый новый хэндл получает ID на единицу больше предыдущего. Однако такие объекты, как тексттэги, начинаются с 99, и каждый последующий получает идентификатор на единицу
меньше предыдущего, пока они не достигнут 0. А если такое случится, будет возвращен нулевой хэндл, так что старайтесь избегать достижения этого лимита.
Так или иначе, если вы создаете юнита (который является хэндлом с нормальным типом выделения памяти), вы вызовете десинхронизацию, поскольку его ID > 0x100000.
[#=manipulating]
6. Управление системой игры. [goto=contents][ent=#x2191][/goto] Скажем, вы хотите создать спецэффект для определённого игрока. Как вы это сделаете? Так, как описано ниже?
[code=jass]function Test takes nothing returns nothing
if GetLocalPlayer() == Player(0) then
call AddSpecialEffect("war3mapImported\\FX.mdl", .0, .0)
endif
endfunction[/code]
Неверно! Вы не можете создать спецэффект, т.к. его значение > 0x100000. Но как тогда это сделать? Во многих случаях вам придётся что-то скрывать и показывать для определённых игроков. Но у спецэффектов нет функции скрытия/показа. А значит, мы создадим ее сами!
[spoiler="Не самый хороший способ"][code=jass]function Test takes nothing returns nothing
local string s = ""
//Спецэффект с пустым путем не будет показан вообще.
if GetLocalPlayer() == Player(0) then
set s = "war3mapImported\\FX.mdl"
//Эффект будет иметь нужный путь для нужного игрока и пустой - для всех других.
endif
call DestroyEffect(AddSpecialEffect(s, .0, .0))
//Однако не используйте эту функцию, чуть ниже показан лучший вариант.
endfunction[/code][/spoiler]
Мои поздравления, мы всё сделали правильно!
Однако эта функция вызывает десинхронизацию таблицы строк: строка заносится в таблицу только у одного человека (подробнее о таблице строк можно прочитать
здесь).
[code=jass]function Test takes nothing returns nothing
//Вот правильный метод.
local string s = "war3mapImported\\FX.mdl"
if GetLocalPlayer() != Player(0) then
set s = ""
endif
call DestroyEffect(AddSpecialEffect(s, .0, .0))
endfunction[/code]
[#=usage]
7. Обычное использование [goto=contents][ent=#x2191][/goto] Скажем, у вас есть мультиборд, но вы хотите показать его только для конкретного игрока. Запомните, нельзя создавать мультиборд для конкретного игрока, у мультибордов нет строк-директорий (которые можно оставить пустыми), но можно просто спрятать или показать его.
[code=jass]function Test takes multiboard mb returns nothing
call MultiboardDisplay(mb, GetLocalPlayer() == Player(0))
endfunction[/code]
В результате мультиборд будет показан только красному игроку.
[#=forces]
8. Выполнение действий для кланов. [goto=contents][ent=#x2191][/goto] Существует свой способ выполнения определенных действий для тех игроков, которые содержатся в клане. Вместо того, чтобы снова и снова вызывать GetLocalPlayer(), можно использовать функцию IsPlayerInForce(). Вот пример такого использования:
[code=jass]function DisplayTextToForce takes force toForce, string message returns nothing
if IsPlayerInForce(GetLocalPlayer(), toForce)
call DisplayTextToPlayer(GetLocalPlayer(), .0, .0, message)
endif
endfunction[/code]
Видите? toForce - это клан, для которого вы показываете сообщение, а message - это показываемое сообщение.
IsPlayerInForce() проверяет, есть ли игрок (первый параметр) в нужном клане (второй параметр). Так как GetLocalPlayer() возвращает игрока (у которого в этот момент запущен триггер), можно проверить, состоит ли игрок в нужном нам клане, затем применить действия к этому игроку. Триггер запустится для всех игроков, и те, кто будут в нужном клане, получат на экран сообщение, другие же не получат ничего.
Эта техника полезна и может сэкономить много времени.
[#=outro]
9. Заключение. [goto=contents][ent=#x2191][/goto] Теперь вы знаете, как показывать что-либо определённым игрокам. В GUI можно просто использовать команду "Custom Script". Но будьте осторожны, ведь многие GUI-функции могут содержать такие вещи, о которых вы даже не догадываетесь!
Автор: PurgeandFire
Источник.