Нам понадобится
исходники сервера
исходники interface.u с компилятором
Все, что вам нужно, находится в свободном доступе.
Cерверная часть
Сервер в нашем случае ACIS 36x, но подойдет любой (возможно PTS). Все, что требуется, это добавить команду, которая снимет указанный бафф. Чтобы не усложнять пример, давайте обойдемся обходом .
Чтобы снять бафф, более современные клиенты отправляют пакет RequestDispel , поэтому мы будем использовать термин dispel
Сначала добавим метод 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 ;
}
// Stop skill effect by ID
_effects. stopSkillEffects ( skill. getId ( ) ) ;
}
Теперь добавим обработку в to the runImpl RequestBypassToServer network пакета RequestBypassToServer, который приходит от клиента. Так как метод dispelSkillEffect требует ID навыка и уровень навыка в качестве аргументов, клиент должен передать их в качестве параметров команде dispel :
// RequestBypassToServer.java
// Usage: _dispel:<int:skill_id>,<int:skill_level>
// Example: _dispel:313,8
else if ( _command. startsWith ( "_dispel" ) )
{
String params = _command. substring ( _command. indexOf ( ":" ) + 1 ) ;
// Split params into tokens
StringTokenizer st = new StringTokenizer ( params, "," ) ;
// Get skill ID from first token
intid = Integer . parseInt ( st.nextToken ( ) ) ;
activeChar. dispelSkillEffect ( id, level ) ; }
Пример вызова: _dispel:313,8 I
рекомендую сделать команду с аналогичными параметрами вместо обхода. Кроме того, тогда игроки смогут писать макросы для снятия баффа.
Сторона клиента
К сожалению, простого способа отслеживания Alt+Click в клиенте Interlude нет, поэтому используем обычный двойной клик левой кнопки мыши для снятия баффа . Событие будет обрабатываться окном AbnormalStatusWnd , в котором отображаются иконки бафов и дебаффов
Алгоритм:
Слушаем в окне AbnormalStatusWnd событие двойного клика (OnLButtonDblClick)
Определить бафф, на который нажали (через StatusIcon.GetItem)
Определите идентификатор и уровень навыка этого баффа (через GetSkillInfo)
Отправляем запрос на сервер (через RequestBypassToServer или ExecuteCommand)
Вызываем 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 ;
// ...
Теперь в любом месте (например, сразу после функции 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 ) ) {
targetRow = ( Y - windowBounds. nY ) / NSTATUSICON_SIZE ;
targetCol = ( X - windowBounds. nX - NSTATUSICON_FRAMESIZE ) / NSTATUSICON_SIZE ;
StatusIcon. GetItem ( targetRow , targetCol , info ) ;
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 ) ) ) ;
}
}
}
Скомпилировать interface.u, скопировать в клиент, запустить игру
Готово!