Добавлен rsfghd,
опубликован
Алгоритмы, Наработки и Способности
Способ реализации:
vJass
Тип:
Способность
Версия Warcraft:
1.26+
Инквизиция
Герой призывает архангела, который взмахом меча направляет святую силу в указанном направлении, что исцеляет союзников и наносит урон вражеской нежити
раскрыть
– Покайтесь и обратитесь от всех преступлений ваших, чтобы нечестие не было вам преткновением.
код
library RandomIntGenMem
globals
private constant hashtable H = InitHashtable( )
constant key RandomIntKey
endglobals
function ClearRandomIntMem takes nothing returns nothing
call FlushChildHashtable( H, RandomIntKey )
endfunction
function GetRandomIntMem takes integer lowBound, integer highBound returns integer
local integer r
local integer simple
if highBound <= lowBound then
return highBound
endif
set simple = GetRandomInt( lowBound, highBound )
set r = simple
loop
exitwhen not HaveSavedBoolean( H, RandomIntKey, r )
if r < highBound and r >= simple then
set r = r + 1
elseif r == highBound and simple > lowBound then
set r = simple - 1
elseif r > lowBound and r < simple then
set r = r - 1
elseif r <= lowBound or r >= highBound then
set r = simple
exitwhen true
endif
endloop
if HaveSavedBoolean( H, RandomIntKey, r ) then
call FlushChildHashtable( H, RandomIntKey )
endif
call SaveBoolean( H, RandomIntKey, r, true )
return r
endfunction
endlibrary
library InquisitionLib requires RandomIntGenMem
globals
private constant hashtable H = InitHashtable( )
private constant group TempGroup = CreateGroup( )
private constant location LFZ = Location( 0.00, 0.00 )
private constant integer RessurectionID = 'u000'
private constant integer HealingID = 'u002'
private constant integer HolyID = 'u003'
private real MaxX
private real MinX
private real MaxY
private real MinY
endglobals
private function GetLocZ takes real x, real y returns real
call MoveLocation( LFZ, x, y )
return GetLocationZ( LFZ )
endfunction
private function SetUnitPositionEx takes unit u, real x, real y returns nothing
if x > MaxX then
set x = MaxX
elseif x < MinX then
set x = MinX
endif
if y > MaxY then
set y = MaxY
elseif y < MinY then
set y = MinY
endif
call SetUnitX( u, x )
call SetUnitY( u, y )
endfunction
private struct Point
real x
real y
real z
static method create takes real x, real y, real z returns thistype
local thistype this = thistype.allocate( )
set this.x = x
set this.y = y
set this.z = z
return this
endmethod
endstruct
private struct InquisitionS
unit caster
unit array dummy[20]
unit array target[20]
player p
boolexpr b
boolexpr b1
integer array dhType[20]
real x
real y
real damage
real heal
real radius
real d
real a
real time
Point p0
Point array pl[20]
Point array p1[20]
Point array p2[20]
Point array p3[20]
endstruct
private function Move takes nothing returns nothing
local InquisitionS A = LoadInteger( H, GetHandleId( GetExpiredTimer( ) ), 0 )
local real x
local real y
local real z
local integer i = 0
local unit u
set A.time = A.time + ( 0.03125 / 1.50 )
if A.time >= 1.00 then
set udg_TempUnit = A.caster
endif
loop
//(1-t)3*P0+3t(1-t)2P1+3t2(1-t)P2+t3P3 https://uk.wikipedia.org/wiki/Крива_Безьє
if A.target[i] != null then
set A.p3[i].x = GetUnitX( A.target[i] )
set A.p3[i].y = GetUnitY( A.target[i] )
set A.p3[i].z = GetUnitFlyHeight( A.target[i] ) + GetLocZ( A.p3[i].x, A.p3[i].y )
endif
set x = ( 1.00 - A.time ) * ( 1.00 - A.time ) * ( 1.00 - A.time ) * A.p0.x + 3.00 * A.time * ( ( 1.00 - A.time ) * ( 1.00 - A.time ) ) * A.p1[i].x + 3.00 * ( A.time * A.time ) * ( 1.00 - A.time ) * A.p2[i].x + ( A.time * A.time * A.time ) * A.p3[i].x
set y = ( 1.00 - A.time ) * ( 1.00 - A.time ) * ( 1.00 - A.time ) * A.p0.y + 3.00 * A.time * ( ( 1.00 - A.time ) * ( 1.00 - A.time ) ) * A.p1[i].y + 3.00 * ( A.time * A.time ) * ( 1.00 - A.time ) * A.p2[i].y + ( A.time * A.time * A.time ) * A.p3[i].y
set z = ( 1.00 - A.time ) * ( 1.00 - A.time ) * ( 1.00 - A.time ) * A.p0.z + 3.00 * A.time * ( ( 1.00 - A.time ) * ( 1.00 - A.time ) ) * A.p1[i].z + 3.00 * ( A.time * A.time ) * ( 1.00 - A.time ) * A.p2[i].z + ( A.time * A.time * A.time ) * A.p3[i].z
call SetUnitPositionEx( A.dummy[i], x, y )
call SetUnitFlyHeight( A.dummy[i], z - GetLocZ( x, y ), 0.00 )
call SetUnitFacing( A.dummy[i], Atan2( y - A.pl[i].y, x - A.pl[i].x ) * bj_RADTODEG )
// for Pitch = Atan2( z - A.pl[i].z, SquareRoot( ( x - A.pl[i].x ) * ( x - A.pl[i].x ) + ( y - A.pl[i].y ) * ( y - A.pl[i].y ) ) )
if A.time >= 1.00 then
if A.target[i] != null then
if A.dhType[i] == 0 then
if A.heal >= 0.00 then
call SetWidgetLife( A.target[i], GetWidgetLife( A.target[i] ) + A.heal )
else
call UnitDamageTarget( A.caster, A.target[i], -A.heal, false, false, null, null, null )
endif
elseif A.dhType[i] == 1 then
if A.damage >= 0.00 then
call UnitDamageTarget( A.caster, A.target[i], A.damage, false, false, null, null, null )
else
call SetWidgetLife( A.target[i], GetWidgetLife( A.target[i] ) - A.damage )
endif
endif
else
set udg_TempUnit = A.caster
call GroupEnumUnitsInRange( TempGroup, x, y, 250.00, A.b )
loop
set u = FirstOfGroup( TempGroup )
exitwhen u == null
call GroupRemoveUnit( TempGroup, u )
if IsUnitInRangeXY( u, x, y, 50.00 ) then
call GroupClear( TempGroup )
if A.heal >= 0.00 then
call SetWidgetLife( u, GetWidgetLife( u ) + A.heal )
else
call UnitDamageTarget( A.caster, u, -A.heal, false, false, null, null, null )
endif
endif
endloop
call GroupEnumUnitsInRange( TempGroup, x, y, 250.00, A.b1 )
loop
set u = FirstOfGroup( TempGroup )
exitwhen u == null
call GroupRemoveUnit( TempGroup, u )
if IsUnitInRangeXY( u, x, y, 50.00 ) then
call GroupClear( TempGroup )
if A.damage >= 0.00 then
call UnitDamageTarget( A.caster, u, A.damage, false, false, null, null, null )
else
call SetWidgetLife( u, GetWidgetLife( u ) - A.damage )
endif
endif
endloop
endif
call SetUnitAnimation( A.dummy[i], "death" )
call UnitApplyTimedLife( A.dummy[i], 'BTLF', 2.00 )
set A.dummy[i] = CreateUnit( A.p, HolyID, x, y, GetRandomReal( 0.00, 360.00 ) )
call SetUnitPositionEx( A.dummy[i], x, y )
call UnitApplyTimedLife( A.dummy[i], 'BTLF', 2.00 )
set A.dummy[i] = null
set A.target[i] = null
call A.pl[i].destroy( )
call A.p1[i].destroy( )
call A.p2[i].destroy( )
call A.p3[i].destroy( )
else
set A.pl[i].x = x
set A.pl[i].y = y
set A.pl[i].z = z
endif
set i = i + 1
exitwhen i >= 20
endloop
if A.time >= 1.00 then
call PauseTimer( GetExpiredTimer( ) )
call FlushChildHashtable( H, GetHandleId( GetExpiredTimer( ) ) )
call DestroyTimer( GetExpiredTimer( ) )
call A.p0.destroy( )
set A.caster = null
call A.destroy( )
endif
endfunction
private function Create takes nothing returns nothing
local timer t = GetExpiredTimer( )
local InquisitionS A = LoadInteger( H, GetHandleId( t ), 0 )
local integer i = 0
local integer k
local real a = A.a - 45.00 * bj_DEGTORAD
local real a1 = GetRandomReal( 0.00, 360.00 )
local unit u
set A.target[0] = null
set udg_TempUnit = A.caster
call GroupEnumUnitsInRange( TempGroup, A.x, A.y, A.radius + 200.00, A.b )
loop
set u = FirstOfGroup( TempGroup )
exitwhen u == null
call GroupRemoveUnit( TempGroup, u )
if IsUnitInRangeXY( u, A.x, A.y, A.radius ) then
set A.target[i] = u
set A.dhType[i] = 0
set i = i + 1
if i >= 20 then
call GroupClear( TempGroup )
endif
endif
endloop
if i <= 20 then
call GroupEnumUnitsInRange( TempGroup, A.x, A.y, A.radius + 200.00, A.b1 )
loop
set u = FirstOfGroup( TempGroup )
exitwhen u == null
call GroupRemoveUnit( TempGroup, u )
if IsUnitInRangeXY( u, A.x, A.y, A.radius ) then
set A.target[i] = u
set A.dhType[i] = 1
set i = i + 1
if i >= 20 then
call GroupClear( TempGroup )
endif
endif
endloop
if A.target[0] != null then
loop
exitwhen i >= 20
set k = GetRandomIntMem( 0, i - 1 )
set A.target[i] = A.target[k]
set A.dhType[i] = A.dhType[k]
set i = i + 1
endloop
endif
endif
set i = 0
loop
set A.dummy[i] = CreateUnit( A.p, HealingID, A.p0.x, A.p0.y, A.a * bj_RADTODEG )
call SetUnitAnimation( A.dummy[i], "birth" )
call QueueUnitAnimation( A.dummy[i], "stand" )
call UnitAddAbility( A.dummy[i], 'Arav' )
call SetUnitPositionEx( A.dummy[i], A.p0.x, A.p0.y )
call SetUnitFlyHeight( A.dummy[i], A.p0.z - GetLocZ( A.p0.x, A.p0.y ), 0.00 )
set A.pl[i] = Point.create( A.p0.x, A.p0.y, A.p0.z )
set A.p1[i] = Point.create( A.p0.x + ( A.d + 500.00 ) * Cos( A.a + GetRandomReal( -30.00, 30.00 ) * bj_DEGTORAD ), A.p0.y + ( A.d + 500.00 ) * Sin( A.a + GetRandomReal( -30.00, 30.00 ) * bj_DEGTORAD ), A.p0.z + GetRandomReal( 200.00, 500.00 ) )
set A.p2[i] = Point.create( A.p0.x + ( A.d + 500.00 ) * Cos( A.a + GetRandomReal( -90.00, 90.00 ) * bj_DEGTORAD ), A.p0.y + ( A.d + 500.00 ) * Sin( A.a + GetRandomReal( -90.00, 90.00 ) * bj_DEGTORAD ), A.p0.z + GetRandomReal( 500.00, 700.00 ) )
if A.target[0] != null then
set A.p3[i] = Point.create( GetUnitX( A.target[i] ), GetUnitY( A.target[i] ), GetUnitFlyHeight( A.target[i] ) )
else
set A.p3[i] = Point.create( A.x + GetRandomReal( 15.00, A.radius - 50.00 ) * Cos( a1 * bj_DEGTORAD ), A.y + GetRandomReal( 15.00, A.radius - 50.00 ) * Sin( a1 * bj_DEGTORAD ), 0.00 )
endif
set A.p3[i].z = A.p3[i].z + GetLocZ( A.p3[i].x, A.p3[3].y )
set i = i + 1
exitwhen i >= 20
set a = a + 90.00 / 20.00 * bj_DEGTORAD
set a1 = a1 + 360.00 / 20.00
endloop
call TimerStart( t, 0.03125, true, function Move )
set t = null
endfunction
private function SetAnim takes nothing returns nothing
local timer t = GetExpiredTimer( )
call SetUnitTimeScale( LoadUnitHandle( H, GetHandleId( t ), 0 ), 1.00 )
call FlushChildHashtable( H, GetHandleId( t ) )
call DestroyTimer( t )
set t = null
endfunction
function Inquisition_Actions takes unit caster, real damage, real heal, real radius, boolexpr b, boolexpr b1 returns nothing
local timer t = CreateTimer( )
local InquisitionS A = InquisitionS.create( )
set A.caster = GetTriggerUnit( )
set A.damage = damage
set A.radius = radius
set A.heal = heal
set A.x = GetSpellTargetX( )
set A.y = GetSpellTargetY( )
set A.b = b
set A.b1 = b1
set A.p = GetOwningPlayer( A.caster )
set A.p0 = Point.create( GetUnitX( A.caster ), GetUnitY( A.caster ), 400.00 )
set A.a = Atan2( A.y - A.p0.y, A.x - A.p0.x )
set A.d = SquareRoot( ( A.x - A.p0.x ) * ( A.x - A.p0.x ) + ( A.y - A.p0.y ) * ( A.y - A.p0.y ) )
set A.time = 0.00
set A.p0.z = A.p0.z + GetLocZ( A.p0.x, A.p0.y )
call SaveInteger( H, GetHandleId( t ), 0, A )
call TimerStart( t, 1.00, false, function Create )
set A.dummy[0] = CreateUnit( A.p, RessurectionID, A.p0.x, A.p0.y, A.a * bj_RADTODEG )
call SetUnitTimeScale( A.dummy[0], 1.70 )
call SetUnitPositionEx( A.dummy[0], A.p0.x, A.p0.y )
call UnitApplyTimedLife( A.dummy[0], 'BTLF', 5.00 )
set t = CreateTimer( )
call SaveUnitHandle( H, GetHandleId( t ), 0, A.dummy[0] )
call TimerStart( t, 1.00, false, function SetAnim )
set t = null
endfunction
//===========================================================================
function InitTrig_Inquisition takes nothing returns nothing
local rect r = GetWorldBounds( )
//set gg_trg_Inquisition = CreateTrigger( )
set MaxX = GetRectMaxX( r ) - 32.00
set MinX = GetRectMinX( r ) + 32.00
set MaxY = GetRectMaxY( r ) - 32.00
set MinY = GetRectMinY( r ) + 32.00
call RemoveRect( r )
set r = null
endfunction
endlibrary
инструкция по импорту
- скопировать триггер Inquisition и вставить в карту
- заполнить равкоды в 7-9 строках кода Inquisition в соответствии с объектами из ро
- создать переменную с названием TempUnit для гуи пользования
отделённые комментарием триггеры не нужны, один для гуи примера, другой по рофлу дугу пускает (мне было сложно подобрать/придумать что делать при взмахе меча)
если нужна дополнительная помощь, а-ля изменить точки полёта, формулу, эффект при уроне, время полёта, больше сгустков добавить, убрать какие-то лишние элементы и т.п., без проблем сделаю или поясню как сделать самому
используется немного отредактированная мной версия Генератора случайных чисел без повторений от ScorpioT1000
upd 13.01.2024: немного отредактированная версия, добавлен поиск целей
спасиб Maxlaid за помощь в нахождении идеи для этого спелла и PROSHELDOTU за замечание неэффективности (неиграбельности) данной недоспособности, что сподвигло добавить поиск цели
я не думаю что кто-то всерьёз будет этот спелл где-то использовать, так что просто демонстрирую идею
`
ОЖИДАНИЕ РЕКЛАМЫ...
Чтобы оставить комментарий, пожалуйста, войдите на сайт.
но это не играбельно судя по падению частиц, на дистанции ни своих толком не похилишь, ни вражескую нежить не ранишь, только если под себя бросать, и то противники ещё 10 раз успеют задоджить, даже сели под себя, а куда-то в точку, так ваще изи
и указатель надо областью бы, чтобы видеть радиус
сколько частиц, как они наводятся, как приоритеты расставляет, как и сколько в целом спелл хилит дамажит и всё такое
Отредактирован rsfghd
Не настраивается количество частиц, периодичность таймера, скорость полета, секунда на которой вылетают самонаводящиеся частицы, как именно они лететь будут, и нет расширенного приоритета (а-ля наводиться в первую очередь на самых раненых или здоровых). Сначала ищутся цели для урона, затем для хила (чтобы было наоборот достаточно инвертировать значения урона/хила), оставшиеся частицы распределяются поровну между пойманными целями. Если при спавне частиц в области каста никого не было, они падают рандомно по области, так же производя дамаг или хил рандомной цели вокруг падения
Мне лень было добавлять 999 настроек зная, что никто это использовать не будет и возьмёт лишь идею. Если кому-либо действительно понадобится это, но с небольшими изменениями, то всегда можно оставить комментарий с просьбой и я скину отредактированную версию
игроку банально нужно понимать сколько оно похилит или продамажит
каждый напишет своё описание на своём языке со своими настройками урона типа 25 + [Интеллект х 2.5], продвинутые сделают динамическое описание, короче это уже заморочки пользователей