Форум администраторов игровых серверов

Форум администраторов игровых серверов (https://forum.zone-game.info/TT.php)
-   Игровой клиент (https://forum.zone-game.info/forumdisplay.php?f=54)
-   -   Фишки от ЛСа: добавляем в Interlude снятие баффов по клику (https://forum.zone-game.info/showthread.php?t=43301)

freelu 08.09.2018 18:00

Добавляем в Interlude снятие баффов по клику
 
Я пытался разместить это в обучающие статьи, но застрял на модерации, поэтому разместил сюда, поправив пару опечаток

https://s8.hostingkartinok.com/uploa...887b7aa915.gif

Возможность снять UD, Snipe, Stealth или CoV — отличная штука, особенно в Interlude, где эти умения не имеют заточки на штраф. Многие уже привыкли отменять Chant of Revenge перед нажатием Mirage или хилиться, снимая Celestial Shield

Нам понадобятся
  • исходники сервера
  • исходники interface.u с компилятором
Всё необходимое есть в свободном доступе


Серверная часть

https://s8.hostingkartinok.com/uploa...b58fdb8b78.png

Сервер в нашем случае — ACIS 36x, но подойдет любой (возможно и PTS). Всё, что потребуется — добавить команду, которая будет снимать указанный бафф. Для простоты примера обойдемся байпасом

Для снятия баффа более современные клиенты отправляют пакет RequestDispel, поэтому будем использовать термин dispel

Сперва в L2Character добавим метод диспела. По аналогии с более свежими версиями игры он не будет снимать эффекты, которые должны оставаться после смерти (напр., пенальти), дебаффы, денсы и сонги:

// L2Character.java
 
public final void dispelSkillEffect(int skillId, int skillLevel) {
	// Find skill with matching ID and level
	final L2Skill skill = SkillTable.getInstance().getInfo(skillId, skillLevel);
	// Skill wasn't found and can't be dispelled
	if (skill == null)
	{
		return;
	}
	// Penalty-like or debuff skill effect can't be dispelled
	if (skill.isStayAfterDeath() || skill.isDebuff())
	{
		return;
	}
	// Dance-like skill effect can't be dispelled
	if (skill.isDance())
	{
		return;
	}
	// Stop skill effect by ID
	_effects.stopSkillEffects(skill.getId());
}
 
Code: Java

Теперь добавим обработку байпаса в runImpl сетевого пакета RequestBypassToServer, который приходит от клиента. Поскольку метод dispelSkillEffect в качестве аргументов требует ID и уровень скилла, клиент должен передать их в качестве параметров к команде dispel:

// RequestBypassToServer.java
 
// Usage: _dispel:<int:skill_id>,<int:skill_level>
// Example: _dispel:313,8
else if (_command.startsWith("_dispel"))
{
	// Cut out command params
	String params = _command.substring(_command.indexOf(":") + 1);
	// Split params into tokens
	StringTokenizer st = new StringTokenizer(params, ",");
	// Get skill ID from first token
	int id = Integer.parseInt(st.nextToken());
	// Get skill level from second token
	int level = Integer.parseInt(st.nextToken());
	// Dispel skill effect on current character
	activeChar.dispelSkillEffect(id, level);
}
 
Code: Java

Пример вызова: _dispel:313,8

Рекомендую вместо байпаса сделать команду с аналогичными параметрами. Кроме того, тогда игроки смогут писать макросы на снятие баффа


Клиентская часть

https://s8.hostingkartinok.com/uploa...5f686a37ad.png

К сожалению, в клиенте Interlude нет простого способа отследить нажатие Alt+Click, поэтому используем для снятия баффа обычный двойной клик левой кнопки мыши. Обрабатывать событие будет окно AbnormalStatusWnd, которое отображает иконки баффов и дебаффов

Алгоритм:
  1. Слушаем в окне AbnormalStatusWnd событие двойного клика (OnLButtonDblClick)
  2. Определяем бафф, по которому кликнули (через StatusIcon.GetItem)
  3. Определяем ID и уровень скилла этого баффа (через GetSkillInfo)
  4. Отправляем запрос на сервер (через RequestBypassToServer или ExecuteCommand)
  5. Вызываем на сервере dispelSkillEffect с полученными ID и уровнем скилла
Событие двойного клика левой кнопкой мыши OnLButtonDblClick получает в качестве аргументов только координаты клика. При этом StatusIcon.GetItem требует указания ряда и столбца ячейки. Соответственно, необходимо определить, в какой ряд и в какой столбец наших баффов кликнул игрок

Поскольку мы знаем, что размер ячейки баффа 24 пикселя, а размер ручки, за которое перетаскивается окно — 12 пикселей, то вычислить ряд и ячейку легко: достаточно определить координаты окна с баффами, вычесть все значения и поделить остаток на размер ячейки. При приведении к int значения будут правильно округлены

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

// AbnormalStatusWnd.uc
 
class AbnormalStatusWnd extends UIScript;
 
const NSTATUSICON_FRAMESIZE = 12;
const NSTATUSICON_MAXCOL = 12;
const NSTATUSICON_SIZE = 24;
 
// ...
 
Code: Javascript

Теперь в любое место (например, сразу после функции OnEvent), добавим обработку события двойного клика:

// AbnormalStatusWnd.uc
 
function OnLButtonDblClick(int X, int Y) {
	local Rect windowBounds;
	local int targetRow;
	local int targetCol;
 
	local StatusIconInfo info;
	local SkillInfo skillInfo;
 
	// Find window position
	windowBounds = Me.GetRect();
 
	// Process clicks outside of window frame only
	if (X > (windowBounds.nX + NSTATUSICON_FRAMESIZE)) {
		// Calc row and col of targeted icon
		targetRow = (Y - windowBounds.nY) / NSTATUSICON_SIZE;
		targetCol = (X - windowBounds.nX - NSTATUSICON_FRAMESIZE) / NSTATUSICON_SIZE;
 
		// Store status info of targeted icon
		StatusIcon.GetItem(targetRow, targetCol, info);
 
		// Store actual skill info and make sure it is exists
		if (GetSkillInfo(info.ClassID, info.Level, skillInfo)) {
			// Request server to stop skill effect
			// Usage: _dispel:<int:skill_id>,<int:skill_level>
			// Example: _dispel:313,8
			RequestBypassToServer("_dispel:" $ string(skillInfo.SkillID) $ "," $ string(skillInfo.SkillLevel));
		}
	}
}
 
Code: Javascript

Компилируем interface.u, копируем в клиент, запускаем игру

Готово!


Текущее время: 09:51. Часовой пояс GMT +3.

Powered by vBulletin® Version 3.8.6
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd. Перевод: zCarot