Инквизиция
Герой призывает архангела, который взмахом меча направляет святую силу в указанном направлении, что исцеляет союзников и наносит урон вражеской нежити
раскрыть
– Покайтесь и обратитесь от всех преступлений ваших, чтобы нечестие не было вам преткновением.
код
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 раз успеют задоджить, даже сели под себя, а куда-то в точку, так ваще изи
и указатель надо областью бы, чтобы видеть радиус
сколько частиц, как они наводятся, как приоритеты расставляет, как и сколько в целом спелл хилит дамажит и всё такое