Добавлен Buulichkaa,
опубликован
Раз уж я решил взяться за это дерьмо, то постарался сделать все на нормальном уровне, мб кто научится чему.
Суть спелла:
Герой запускает молот, который летит в заданном направлении и дамажит все, что попадается ему на пути, после того, как он пробежал заданное расстояние - он возвращается к кастеру.
Спелл легкий, можно было вставить понтов с молниями, притяжением юнитов, минимальной системой движения и взаимодействия с окружением и т. д., но заказчику нужен был лишь дмг в области действия.
Я не вставлял мини-систему отбивания от краев карты, как я люблю, об этом никто не просил, а жаль =(
Рельеф спецом кривой, поэтому может показаться, что молот иногда "не задевает" всех кого надо, это не более чем оптическая иллюзия, все работает как надо.
Суть спелла:
Герой запускает молот, который летит в заданном направлении и дамажит все, что попадается ему на пути, после того, как он пробежал заданное расстояние - он возвращается к кастеру.
Спелл легкий, можно было вставить понтов с молниями, притяжением юнитов, минимальной системой движения и взаимодействия с окружением и т. д., но заказчику нужен был лишь дмг в области действия.
Я не вставлял мини-систему отбивания от краев карты, как я люблю, об этом никто не просил, а жаль =(
Рельеф спецом кривой, поэтому может показаться, что молот иногда "не задевает" всех кого надо, это не более чем оптическая иллюзия, все работает как надо.
Присутствуют все настройки, которые смог придумать.
Стоит заметить, что количество дмг будет зависеть от предустановленных констант на урон.
Импорт стандартный - копипастим способность, триггер, даммик. После, устанавливаем в настройках свои равкоды, если они отличаются от моих. Для повторной компиляции требуется JNGP.
Вы безупречны!
Вы безупречны!
previous
v0.01
код
library hammer initializer Init{
/*
© XGM.GURU (28.09.2014)
By Buulichkaa
*/
define{
////////////
//SETTINGS//
////////////
DUMMY_ID = 'h001' //Равкод даммика
SPELL_ID = 'A000' //Равкод способности
SPEED = 15 //Скорость полета снаряда
MAX_DIST = 600 //Максимальная дистанция, которую сможет пролететь молот
RADIUS = 80 //Радиус, в котором наносится урон
MODEL = "Abilities\\Spells\\Human\\StormBolt\\StormBoltMissile.mdl" //Модель, которая создается на цели, при нанесении ей урона
AMOUNT = {(GetUnitAbilityLevel(damager, SPELL_ID)*50) + 50} //Количество урона
ATTACK_TYPE = ATTACK_TYPE_NORMAL //Тип атаки
DAMAGE_TYPE = DAMAGE_TYPE_NORMAL //Тип урона
WEAPON_TYPE = WEAPON_TYPE_WHOKNOWS //Тип оружия
//Keywords
int = integer
void = nothing
bool = boolean
func = function
class = struct
insert_class_funcs =
{//+class funcs
private static integer iC = 0
private static thistype r = 0
private thistype rN
static method New takes nothing returns thistype
thistype this
if (r == 0) {
++iC
this = iC
}else{
this = r
r = r.rN
}
return this
endmethod
method Remove takes nothing returns nothing
set rN = r
set r = this
endmethod
//-class funcs
}
//***************************************************************************
//Functions
msg(s) = DisplayTimedTextToPlayer(Player(0), 0, 0, 10, "|cFF00FFFFDEBUG|r " + s)
Sqrt(r) = SquareRoot(r)
GetX(u) = GetUnitX(u)
GetY(u) = GetUnitY(u)
SetXY(u, x, y) = { SetUnitX(u, x); SetUnitY(u, y) }
GetAng(x1, y1, x2, y2) = Atan2(y2 - y1, x2 - x1)
//***************************************************************************
}
globals
private player owner = Player(0) //Игрок-владелец кастера, который обрабатывается в циклах групп
private group enum_g = CreateGroup() //Группа в которую добавляются юниты в радиусе действия
private group damaged_g = CreateGroup() //Продамаженные юниты
private unit damager
private int stack[]
private int top = -1
private timer t = CreateTimer()
private real MaxX
private real MaxY
private real MinX
private real MinY
endglobals
private real SafeX(real x){
if (x > MaxX){return MaxX;}
elseif (x < MinX){return MinX;}
return x
}
private real SafeY(real y){
if (y > MaxY){return MaxY;}
elseif (y < MinY){return MinY;}
return y
}
private bool filter(){
return ((IsUnitEnemy(GetFilterUnit(), owner)) and (IsUnitInGroup(GetFilterUnit(), damaged_g) == false));
}
private void Group_Act(){
UnitDamageTarget(damager, GetEnumUnit(), AMOUNT, false, false, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE);
GroupAddUnit(damaged_g, GetEnumUnit());
DestroyEffect(AddSpecialEffect(MODEL, GetX(GetEnumUnit()), GetY(GetEnumUnit())));
}
private class spell extends array{
insert_class_funcs
unit caster
unit dummy
group g //Группа, где хранятся уже продамаженные юниты
real t_x //Координаты точки каста
real t_y
real add_x //Для движения "от" цели к точке каста
real add_y //
bool forward
bool active
static method Create takes unit c, real tx, real ty returns thistype
real x = tx - GetX(c);
real y = ty - GetY(c);
real mod = Sqrt(x * x + y * y);
if (mod > SPEED){
thistype new = thistype.New();
new.caster = c;
new.add_x = (x/mod)*SPEED;
new.add_y = (y/mod)*SPEED;
new.t_x = tx;
new.t_y = ty;
new.forward = true;
new.dummy = CreateUnit(GetOwningPlayer(c), DUMMY_ID, GetX(c), GetY(c), bj_RADTODEG*GetAng(GetX(c), GetY(c), tx, ty));
new.g = CreateGroup();
top++;
stack[top] = new;
new.active = true;
return new;
}else{
return -1;
}
endmethod
method Destroy takes void returns void
.caster = null;
RemoveUnit(.dummy);
DestroyGroup(.g)
.g = null
.dummy = null;
.Remove();
endmethod
method Exec takes void returns void
owner = GetOwningPlayer(.caster);
damaged_g = .g;
GroupEnumUnitsInRange(enum_g, GetX(.dummy), GetY(.dummy), RADIUS, Condition(func filter));
if (FirstOfGroup(enum_g) != null){
damager = .caster;
ForGroup(enum_g, func Group_Act);
GroupClear(enum_g);
}
if .forward{
real nx = GetX(.dummy)+add_x;
real ny = GetY(.dummy)+add_y;
SetXY(.dummy, SafeX(nx), SafeY(ny));
real x = GetX(.dummy) - GetX(.caster);
real y = GetY(.dummy) - GetY(.caster);
real mod = Sqrt(x * x + y * y);
if ((mod > MAX_DIST) or ((SafeX(nx)!= nx) or (SafeY(ny) != ny))){.forward = false;}
}else{
real nx = GetX(.caster)-GetX(.dummy);
real ny = GetY(.caster)-GetY(.dummy);
real mod = Sqrt(nx * nx + ny * ny);
if (mod < SPEED){
.active = false;
}else{
SetXY(.dummy, GetX(.dummy)+(nx/mod)*SPEED, GetY(.dummy)+(ny/mod)*SPEED);
SetUnitFacing(.dummy, bj_RADTODEG*GetAng(GetX(.dummy), GetY(.dummy), GetX(.caster), GetY(.caster)));
}
}
endmethod
}
private void main(){
int i = 0;
loop{
spell current;
exitwhen i > top
current = stack[i];
if (current.active){
current.Exec();
i++;
}else{
current.Destroy();
stack[i] = stack[top];
stack[top] = 0;
top--;
if(top == -1){
PauseTimer(t);
}
}
}
}
private void events(){
if (GetSpellAbilityId() == SPELL_ID){
if (top < 8192){
unit c = GetSpellAbilityUnit();
spell.Create(c, SafeX(GetSpellTargetX()), SafeY(GetSpellTargetY()));
if(top == 0){
TimerStart(t, .025, true, func main);
}
}//top < 8192
}
}
private void Init(){
int i = 0;
MaxX = GetRectMaxX(bj_mapInitialPlayableArea)
MaxY = GetRectMaxY(bj_mapInitialPlayableArea)
MinX = GetRectMinX(bj_mapInitialPlayableArea)
MinY = GetRectMinY(bj_mapInitialPlayableArea)
trigger t = CreateTrigger();
loop{
TriggerRegisterPlayerUnitEvent(t, Player(i++), ConvertPlayerUnitEvent(274), null); //spell
exitwhen i == 16;
}
TriggerAddAction(t, func events);
Preload(MODEL)
}
}
//***************************************************************************
v0.02
Изменения: по просьбе заказчика добавлено следующее:
- Молот при полете от кастера будет отталкивать противников
- Новые настройки
- Немножко пофикшен код
код
library hammer initializer Init{
/*
© XGM.GURU (30.09.2014)
By Buulichkaa
*/
define{
////////////
//SETTINGS//
////////////
DUMMY_ID = 'h001' //Равкод даммика
SPELL_ID = 'A000' //Равкод способности
SPEED = 15 //Скорость полета снаряда
MAX_DIST = 600 //Максимальная дистанция, которую сможет пролететь молот
RADIUS = 80 //Радиус вокруг молота, в котором наносится урон
MODEL = "Abilities\\Spells\\Human\\StormBolt\\StormBoltMissile.mdl" //Модель, которая создается на цели, при нанесении ей урона
ATTACK_TYPE = ATTACK_TYPE_NORMAL //Тип атаки
DAMAGE_TYPE = DAMAGE_TYPE_NORMAL //Тип урона
WEAPON_TYPE = WEAPON_TYPE_WHOKNOWS //Тип оружия
//advanced{
//Настройки, которые лучше не менять, если не знаешь что делаешь
T_PERIOD = .025 //Период таймера
AMOUNT = {(GetUnitAbilityLevel(damager, SPELL_ID)*50) + 50} //Количество урона
KNOCKBACK = MAX_DIST/2 //Расстояние, на которое будет отброшен юнит
KB_SPEED = 15. //Начальная скорость, с которой юнит будет отброшен
//Переменной ниже можно установить свое константное значение
//Оно будет отниматься от начальной скорости с каждым периодом
//Сейчас установлено уравнение, которое зависит от установленного вами расстояния
//Установив свое значение этой переменной вы игнорируете переменную KNOCKBACK
//А расстояние, которое сможет пролететь отброшенный юнит будет зависить от начальной скорости
KB_FADE_SPEED = KB_SPEED/((KNOCKBACK*2/KB_SPEED)-1) //Скорость затухания отбрасывания за каждый "тик" таймера
//}
//Keywords
int = integer
void = nothing
bool = boolean
func = function
class = struct
insert_class_funcs =
{//+class funcs
private static integer iC = 0
private static thistype r = 0
private thistype rN
static method New takes nothing returns thistype
thistype this
if (r == 0) {
++iC
this = iC
}else{
this = r
r = r.rN
}
return this
endmethod
method Remove takes nothing returns nothing
set rN = r
set r = this
endmethod
//-class funcs
}
//***************************************************************************
//Functions
msg(s) = DisplayTimedTextToPlayer(Player(0), 0, 0, 10, "|cFF00FFFFDEBUG|r " + s)
Sqrt(r) = SquareRoot(r)
GetX(u) = GetUnitX(u)
GetY(u) = GetUnitY(u)
SetXY(u, x, y) = { SetUnitX(u, x); SetUnitY(u, y) }
GetAng(x1, y1, x2, y2) = Atan2(y2 - y1, x2 - x1)
//***************************************************************************
}
globals
private player owner //Игрок-владелец кастера, который обрабатывается в циклах групп
private group enum_g = CreateGroup() //Группа в которую добавляются юниты в радиусе действия
private group kb_g
private group damaged_g //Продамаженные юниты
private bool forward_g
private real vec_x //Направление в котором отталкиваются юниты
private real vec_y
private unit damager
private int stack[]
private int top = -1
private timer t = CreateTimer()
private real MaxX
private real MaxY
private real MinX
private real MinY
endglobals
private real SafeX(real x){
if (x > MaxX){return MaxX;}
elseif (x < MinX){return MinX;}
return x
}
private real SafeY(real y){
if (y > MaxY){return MaxY;}
elseif (y < MinY){return MinY;}
return y
}
private bool filter(){
return ((IsUnitEnemy(GetFilterUnit(), owner)) and (IsUnitInGroup(GetFilterUnit(), damaged_g) == false));
}
private void Group_Act_Damage(){
UnitDamageTarget(damager, GetEnumUnit(), AMOUNT, false, false, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE);
GroupAddUnit(damaged_g, GetEnumUnit());
if forward_g{
GroupAddUnit(kb_g, GetEnumUnit());
}
DestroyEffect(AddSpecialEffect(MODEL, GetX(GetEnumUnit()), GetY(GetEnumUnit())));
}
private void Group_Act_Knockback(){
SetXY(GetEnumUnit(), SafeX(GetUnitX(GetEnumUnit())+vec_x), SafeY(GetUnitY(GetEnumUnit())+vec_y));
}
private class spell extends array{
insert_class_funcs
unit caster
unit dummy
group g //Группа, где хранятся уже продамаженные юниты (они же являются теми, кто обрабатывается в процессе отбрасывания)
group g_kb
real t_x //Координаты точки каста
real t_y
real add_x //Для движения "от" цели к точке каста
real add_y //
real fade_speed
bool dummy_active
bool forward
bool knockback
bool active
static method Create takes unit c, real tx, real ty returns thistype
real x = tx - GetX(c);
real y = ty - GetY(c);
real mod = Sqrt(x * x + y * y);
if (mod > SPEED){
thistype new = thistype.New();
new.caster = c;
new.add_x = (x/mod)*SPEED;
new.add_y = (y/mod)*SPEED;
new.t_x = tx;
new.t_y = ty;
new.forward = true;
new.dummy_active = true;
new.knockback = false;
new.fade_speed = KB_SPEED;
new.dummy = CreateUnit(GetOwningPlayer(c), DUMMY_ID, GetX(c), GetY(c), bj_RADTODEG*GetAng(GetX(c), GetY(c), tx, ty));
new.g = CreateGroup();
new.g_kb = CreateGroup();
top++;
stack[top] = new;
new.active = true;
return new;
}else{
return -1;
}
endmethod
method Destroy takes void returns void
.caster = null;
DestroyGroup(.g);
DestroyGroup(.g_kb);
.g = null;
.dummy = null;
.Remove();
endmethod
method Exec takes void returns void
owner = GetOwningPlayer(.caster);
damaged_g = .g;
kb_g = .g_kb;
forward_g = .forward;
GroupEnumUnitsInRange(enum_g, GetX(.dummy), GetY(.dummy), RADIUS, Condition(func filter));
if (FirstOfGroup(enum_g) != null){
damager = .caster;
ForGroup(enum_g, func Group_Act_Damage);
GroupClear(enum_g);
if .forward{
.knockback = true;
}
}
if .dummy_active{
if .forward{
real nx = GetX(.dummy)+add_x;
real ny = GetY(.dummy)+add_y;
SetXY(.dummy, SafeX(nx), SafeY(ny));
real x = GetX(.dummy) - GetX(.caster);
real y = GetY(.dummy) - GetY(.caster);
real mod = Sqrt(x * x + y * y);
if ((mod > MAX_DIST) or ((SafeX(nx)!= nx) or (SafeY(ny) != ny))){.forward = false;}
}else{
real nx = GetX(.caster)-GetX(.dummy);
real ny = GetY(.caster)-GetY(.dummy);
real mod = Sqrt(nx * nx + ny * ny);
if (mod < SPEED){
RemoveUnit(.dummy);
if (.knockback){
.dummy_active = false;
}else{
.active = false;
}
}else{
SetXY(.dummy, GetX(.dummy)+(nx/mod)*SPEED, GetY(.dummy)+(ny/mod)*SPEED);
SetUnitFacing(.dummy, bj_RADTODEG*GetAng(GetX(.dummy), GetY(.dummy), GetX(.caster), GetY(.caster)));
}
}
}
if (.knockback){
if (.fade_speed > 0){
.fade_speed = .fade_speed - KB_FADE_SPEED;
vec_x = .add_x/SPEED*.fade_speed;
vec_y = .add_y/SPEED*.fade_speed;
ForGroup(.g_kb, func Group_Act_Knockback);
}else{
if (.dummy_active){}else{
.active = false;
}
}
}
endmethod
}
private void main(){
int i = 0;
loop{
spell current;
exitwhen i > top
current = stack[i];
if (current.active){
current.Exec();
i++;
}else{
current.Destroy();
stack[i] = stack[top];
top--;
if(top == -1){
PauseTimer(t);
}
}
}
}
private void events(){
if (GetSpellAbilityId() == SPELL_ID){
if (top < 8192){
unit c = GetSpellAbilityUnit();
spell.Create(c, SafeX(GetSpellTargetX()), SafeY(GetSpellTargetY()));
if(top == 0){
TimerStart(t, T_PERIOD, true, func main);
}
}//top < 8192
}
}
private void Init(){
int i = 0;
MaxX = GetRectMaxX(bj_mapInitialPlayableArea)
MaxY = GetRectMaxY(bj_mapInitialPlayableArea)
MinX = GetRectMinX(bj_mapInitialPlayableArea)
MinY = GetRectMinY(bj_mapInitialPlayableArea)
trigger t = CreateTrigger();
loop{
TriggerRegisterPlayerUnitEvent(t, Player(i++), ConvertPlayerUnitEvent(274), null); //spell
exitwhen i == 16;
}
TriggerAddAction(t, func events);
Preload(MODEL)
}
}
//***************************************************************************
v0.03
Изменения:
- Прокомментирована каждая строка, которая, в теории, может вызывать вопросы.
- Код в некоторых местах переписан.
код
library hammer initializer Init{
/*
© XGM.GURU (01.10.2014)
By Buulichkaa
*/
define{
////////////
//SETTINGS//
////////////
private DUMMY_ID = 'h001' //Равкод даммика
private SPELL_ID = 'A000' //Равкод способности
private SPEED = 15. //Скорость полета снаряда
private MAX_DIST = 600. //Максимальная дистанция, которую сможет пролететь молот
private RADIUS = 80. //Радиус вокруг молота, в котором наносится урон
private MODEL = "Abilities\\Spells\\Human\\StormBolt\\StormBoltMissile.mdl" //Модель, которая создается на цели, при нанесении ей урона
private ATTACK_TYPE = ATTACK_TYPE_NORMAL //Тип атаки
private DAMAGE_TYPE = DAMAGE_TYPE_NORMAL //Тип урона
private WEAPON_TYPE = WEAPON_TYPE_WHOKNOWS //Тип оружия
//advanced{
//Настройки, которые лучше не менять, если не знаешь что делаешь
private MAX_PLAYERS = 16 //Количество возможных игроков карты
private T_PERIOD = .025 //Период таймера
private AMOUNT = {(GetUnitAbilityLevel(damager, SPELL_ID)*50.) + 50.} //Количество урона
private KNOCKBACK = MAX_DIST/2 //Расстояние, на которое будет отброшен юнит
private KB_SPEED = 15. //Начальная скорость, с которой юнит будет отброшен
//Переменной ниже можно установить свое константное значение
//Оно будет отниматься от начальной скорости с каждым периодом
//Сейчас установлено уравнение, которое зависит от установленного вами расстояния
//Установив свое значение этой переменной вы игнорируете переменную KNOCKBACK
//А расстояние, которое сможет пролететь отброшенный юнит, будет зависеть от начальной скорости
private KB_FADE_SPEED = KB_SPEED/((KNOCKBACK*2/KB_SPEED)-1) //Скорость затухания отбрасывания за каждый "тик" таймера
//}
//Keywords
private int = integer
private void = nothing
private bool = boolean
private func = function
private class = struct
private insert_class_funcs = //Вставка функций выделения свободной ячейки массива
{//+class funcs
//Может я немного криво объясню эту часть, если непонятно - запишите на бумажке результаты переменных после нескольких вызовов
//Говоря простым языком, это - генератор неповторяющихся чисел от 1 до (в данном случае) 8191
private static integer C = 0 //Вершина списка, формально - это переменная, обозначающая максимальное количество активных элементов
private static thistype r = 0 //Следующий элемент, который будет удален
private thistype Next //Массив, который хранит элементы в порядке удаления
static method New takes nothing returns thistype
thistype this
if (r != 0) {
this = r;
r = r.Next;
} else {
++C
this = C;
}
return this;
endmethod
method Remove takes nothing returns nothing
.Next = r;
r = this;
endmethod
//-class funcs
}
//***************************************************************************
//Functions
private msg(s) = DisplayTimedTextToPlayer(Player(0), 0, 0, 10, "|cFF00FFFFDEBUG|r " + s)
private Sqrt(r) = SquareRoot(r)
private GetX(u) = GetUnitX(u)
private GetY(u) = GetUnitY(u)
private SetXY(u, x, y) = { SetUnitX(u, x); SetUnitY(u, y) }
private GetAng(x1, y1, x2, y2) = Atan2(y2 - y1, x2 - x1) //радианы
//***************************************************************************
}
globals
//передача данных в цикл ForGroup
private player owner //Игрок-владелец кастера, который обрабатывается в циклах групп
private group enum_g = CreateGroup() //Группа в которую добавляются юниты в радиусе действия
private group kb_g //Юниты, которые отталкиваются
private group damaged_g //Продамаженные юниты
private bool forward_g
private real vec_x //Направление в котором отталкиваются юниты
private real vec_y
private unit damager
//
private int stack[] //Массив хранения всех элементов
private int top = -1 //Последний элемент
private timer t = CreateTimer()
//Границы игровой карты, для проверки координат
private real MaxX
private real MaxY
private real MinX
private real MinY
//
endglobals
//Проверка координат юнитов
private real SafeX(real x){
if (x > MaxX){return MaxX;}
elseif (x < MinX){return MinX;}
return x
}
private real SafeY(real y){
if (y > MaxY){return MaxY;}
elseif (y < MinY){return MinY;}
return y
}
//
private bool filter(){ //Для фильтрации пикаемых в группу юнитов, для дальнейшего нанесения им урона\отталкивания
return ((IsUnitEnemy(GetFilterUnit(), owner)) and (IsUnitInGroup(GetFilterUnit(), damaged_g) == false));
}
private void Group_Act_Damage(){ //Цикл нанесения урона юнитам
UnitDamageTarget(damager, GetEnumUnit(), AMOUNT, false, false, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE);
GroupAddUnit(damaged_g, GetEnumUnit());
if forward_g{ //Проверка в какую сторону движется молот, добавляем в группу для отталкивания лишь при условии, что молот движется вперед
GroupAddUnit(kb_g, GetEnumUnit());
}
DestroyEffect(AddSpecialEffect(MODEL, GetX(GetEnumUnit()), GetY(GetEnumUnit()))); //Добавление эффекта продамаженным юнитам
}
private void Group_Act_Knockback() { //Цикл отталкивания
SetXY(GetEnumUnit(), SafeX(GetUnitX(GetEnumUnit())+vec_x), SafeY(GetUnitY(GetEnumUnit())+vec_y));
}
private class spell extends array {
insert_class_funcs
unit caster
unit dummy
group g //Группа, где хранятся уже продамаженные юниты
group g_kb //Юниты, которых отталкивает молотом
real add_x //Вектор для движения от кастера к точке каста
real add_y
real fade_speed //Скорость затухания конкретного молота
bool dummy_active //Существует ли даммик, бывают случаи, когда даммик удалился, а юниты все ещё отталкиваются, все зависит от KNOCKBACK
bool forward //В какую сторону движется молот
bool knockback //Активно ли отталкивание
bool active //Активен ли экземпляр спелла
static method Create takes unit c, real tx, real ty returns thistype
real x = tx - GetX(c); //Получаем направление от точки каста к кастеру
real y = ty - GetY(c);
real mod = x * x + y * y;
if (mod > SPEED*SPEED){
thistype new = thistype.New();
new.caster = c;
new.add_x = (x/Sqrt(mod))*SPEED; //Записываем вектор для движения молота от кастера
new.add_y = (y/Sqrt(mod))*SPEED;
new.forward = true;
new.dummy_active = true;
new.knockback = false;
new.fade_speed = KB_SPEED;
new.dummy = CreateUnit(GetOwningPlayer(c), DUMMY_ID, GetX(c), GetY(c), bj_RADTODEG*GetAng(GetX(c), GetY(c), tx, ty));
new.g = CreateGroup();
new.g_kb = CreateGroup();
top++;
stack[top] = new; //Помещаем новосозданный спелл в вершину стека
new.active = true;
return new;
}else{
return -1;
}
endmethod
method Destroy takes void returns void
.caster = null;
DestroyGroup(.g);
DestroyGroup(.g_kb);
.g = null;
.dummy = null;
.Remove();
endmethod
method Exec takes void returns void
if .dummy_active {
owner = GetOwningPlayer(.caster);
damaged_g = .g;
GroupEnumUnitsInRange(enum_g, GetX(.dummy), GetY(.dummy), RADIUS, Condition(func filter)); //Пикаем юнитов
if (FirstOfGroup(enum_g) != null) {
forward_g = .forward;
damager = .caster;
kb_g = .g_kb;
ForGroup(enum_g, func Group_Act_Damage);
GroupClear(enum_g);
.knockback = .forward; //Если молот зацепил цель летя вперед, то активируется отталкивание
}
if .forward {
real nx = GetX(.dummy) + add_x; //Обсчитываем новые координаты даммика
real ny = GetY(.dummy) + add_y;
SetXY(.dummy, SafeX(nx), SafeY(ny));
real x = GetX(.dummy) - GetX(.caster);
real y = GetY(.dummy) - GetY(.caster);
real mod = x * x + y * y; //Обсчитываем расстояние от кастера к молоту
//Если оно больше чем максимальное или же молот коснулся границы карты, то устанавливаем движение назад
if ((mod > MAX_DIST*MAX_DIST) or ((SafeX(nx)!= nx) or (SafeY(ny) != ny))) {.forward = false;}
} else { //Молот движется назад
real nx = GetX(.caster)-GetX(.dummy); //Обсчитываем новые координаты даммика
real ny = GetY(.caster)-GetY(.dummy);
real mod = nx * nx + ny * ny;
if (mod < SPEED*SPEED) { //Если расстояние от даммика меньше скорости
RemoveUnit(.dummy);
if (.knockback) { //и включено отталкивание, то выключаем движение даммика, которого же и удаляем
.dummy_active = false;
} else {
.active = false; //если отталкивание неактивно, то помечаем экземпляр как готовый к удалению
}
} else {
SetXY(.dummy, GetX(.dummy)+(nx/Sqrt(mod))*SPEED, GetY(.dummy)+(ny/Sqrt(mod))*SPEED); //Если с расстоянием все впорядке, то двигаем даммик
SetUnitFacing(.dummy, bj_RADTODEG*GetAng(GetX(.dummy), GetY(.dummy), GetX(.caster), GetY(.caster))); //И разворачиваем его "лицом" к кастеру
}
}
}
if (.knockback){ //Активно ли отталкивание
if (.fade_speed > 0) { //Не иссяк ли импульс от отталкивания
.fade_speed = .fade_speed - KB_FADE_SPEED; //Отнимаем ещё "часть" импульса
vec_x = .add_x/SPEED*.fade_speed; //Обсчитываем координаты для всех отталкиваемых юнитов
vec_y = .add_y/SPEED*.fade_speed;
ForGroup(.g_kb, func Group_Act_Knockback); //Обрабатываем их в цикле
} else {
if (.dummy_active){}else { //Если импульс иссяк и даммик уже неактивен, то помечаем экземпляр спелла как неактивный
.active = false;
}
}
}
endmethod
}
private void main(){ //Функция обработки всех экземлпяров спелла
int i = 0; //текущий обрабатываемый элемент в стеке
loop{
spell current; //текущий экземпляр спелла
exitwhen i > top //выход, когда мы прошли весь стек
current = stack[i];
if (current.active) {
current.Exec();
i++;//важная часть, переходим к следующему элементу, лишь когда обработали предыдущий, при условии что мы нашли удаленный элемент
//переменная не увеличется, иначе мы не обработаем верхний элемент стека, которым закрыли дырку
} else { //Если мы нашли удаленный изнутри элемент, то удаляем текущий, устанавливаем в текущую ячейку стека верхний, а также уменьшаем счетчик вершины на 1
current.Destroy();
stack[i] = stack[top];
top--;
if(top == -1){ //Паузим таймер, если экземпляры кончились
PauseTimer(t);
}
}
}
}
private void events(){
if (GetSpellAbilityId() == SPELL_ID) {
if (top < 8192) { //все же для приличия
unit c = GetSpellAbilityUnit(); //получаем кастера
spell.Create(c, SafeX(GetSpellTargetX()), SafeY(GetSpellTargetY())); //создаем новый экземпляр
if (top == 0) { //если это первый элемент в стеке, то запускаем таймер
TimerStart(t, T_PERIOD, true, func main);
}
}//top < 8192
}
}
private void Init(){
int i = 0;
MaxX = GetRectMaxX(bj_mapInitialPlayableArea) //Установка значений границ карты
MaxY = GetRectMaxY(bj_mapInitialPlayableArea)
MinX = GetRectMinX(bj_mapInitialPlayableArea)
MinY = GetRectMinY(bj_mapInitialPlayableArea)
trigger t = CreateTrigger();
loop{
TriggerRegisterPlayerUnitEvent(t, Player(i++), ConvertPlayerUnitEvent(274), null); //Событие, что юнит скастовал абилку, мана снята, кд запущен
exitwhen i == MAX_PLAYERS;
}
TriggerAddAction(t, func events);
Preload(MODEL); //загружаем нашу модель во время полосы загрузки, чтобы избежать минилага при первом касте
}
}
//***************************************************************************
`
ОЖИДАНИЕ РЕКЛАМЫ...
Чтобы оставить комментарий, пожалуйста, войдите на сайт.
Отредактирован Buulichkaa
а вообще - защита от повторного освобождения (и ещё некоторые методы) мне там нафиг не нужны, либа же полностью запривачена, даже таймер внутри :D
Это я ещё на чистом джассе не писал, времени не было особо =)
кстати, в v0.01 там при инициализации глобалки группа утекает, я, видимо копировал строку с предыдущей группой.
damaged_g сделана для передачи данных в forgroup цикл, а я ей значение присвоил)
и если тебя так волнует оптимизация кода(что ты переписал 2 функции ради целого ифа) то вот те интересная инфа
квадратный корень высчитывается в 10 раз медленнее чем квадрат числа(в проверке что расстояние больше скорости выгоднее было бы возвести скорость в квадрат)