library mylib
globals
constant hashtable H = InitHashtable()
private constant group TempG = CreateGroup()
private constant group TempG1 = CreateGroup()
private constant location LFZ = Location(0,0)
private conditionfunc Cond
private attacktype AttackType
private damagetype DamageType
private unit bj_lastFilterUnit
private unit TempUnit
private unit CUEX
private real TempReal
private real TempReal1
private real MaxX
private real MinX
private real MaxY
private real MinY
endglobals
native UnitAlive takes unit id returns boolean
private struct Phoenix
unit caster
unit dummy
real x
real y
real speed
real speedx
real speedy
real angle
real dist
real dist1
real dist2
real fly
real fly1
real height
real height1
real radius
real radius1
real dmg
real dmg1
real tm
real tm1
real tm2
real sc
real sc1
group g
effect Effect
integer count
attacktype AttackType
damagetype DamageType
endstruct
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 function CreateUnitEx takes player id, integer unitid, real x, real y, real face returns unit
set CUEX = CreateUnit(id,unitid,x,y,face)
call SetUnitPathing(CUEX,false)
call UnitAddAbility(CUEX,'Arav')
call SetUnitPositionEx(CUEX,x,y)
return CUEX
endfunction
private function GetLocZ takes real x, real y returns real
call MoveLocation(LFZ,x,y)
return GetLocationZ(LFZ)
endfunction
private function ParabolaZ2 takes real y0, real y1, real h, real d, real x returns real
return (2*(y0 + y1 - 2*h)*(x/d - 1) + (y1 - y0))*(x/d) + y0
endfunction
private function DamageCond takes nothing returns boolean
set bj_lastFilterUnit = GetFilterUnit()
if UnitAlive(bj_lastFilterUnit) and IsUnitEnemy(bj_lastFilterUnit,bj_groupEnumOwningPlayer) and not IsUnitInGroup(bj_lastFilterUnit,TempG1) then
call UnitDamageTarget(TempUnit,bj_lastFilterUnit,TempReal,false,false,AttackType,DamageType,null)
call GroupAddUnit(TempG1,bj_lastFilterUnit)
endif
return false
endfunction
private function Damage takes nothing returns nothing
call GroupEnumUnitsInRange(TempG,GetUnitX(GetEnumUnit()),GetUnitY(GetEnumUnit()),TempReal1,Cond)
endfunction
private function PeriodicDamage takes nothing returns nothing
local Phoenix A = LoadInteger(H,GetHandleId(GetExpiredTimer()),0)
set TempUnit = A.caster
set TempReal = A.dmg1
set TempReal1 = A.radius1
set AttackType = A.AttackType
set DamageType = A.DamageType
call ForGroup(A.g,function Damage)
call GroupClear(TempG1)
if not UnitAlive(FirstOfGroup(A.g)) then
call DestroyGroup(A.g)
call FlushChildHashtable(H,GetHandleId(GetExpiredTimer()))
call PauseTimer(GetExpiredTimer())
call DestroyTimer(GetExpiredTimer())
set A.caster = null
set A.dummy = null
set A.Effect = null
call A.destroy()
else
call TimerStart(GetExpiredTimer(),A.tm,false,function PeriodicDamage)
endif
endfunction
private function move takes nothing returns nothing
local Phoenix A = LoadInteger(H,GetHandleId(GetExpiredTimer()),0)
local boolean b
local real fly = GetUnitFlyHeight(A.dummy)+GetLocZ(A.x,A.y)
local real d
local real a
local real x
local real y
set A.x = A.x+A.speedx
set A.y = A.y+A.speedy
set A.dist = A.dist-A.speed
call SetUnitPositionEx(A.dummy,A.x,A.y)
call SetUnitFlyHeight(A.dummy,ParabolaZ2(A.fly,A.height,A.fly1,A.dist1,A.dist),0)
call SetUnitAnimationByIndex(A.dummy,R2I(Atan2((GetUnitFlyHeight(A.dummy)+GetLocZ(A.x,A.y))-fly,SquareRoot(((A.x-A.speedx)-A.x)*((A.x-A.speedx)-A.x)+((A.y-A.speedy)-A.y)*((A.y-A.speedy)-A.y)))*bj_RADTODEG+90.5))
if A.dist <= 0. then
call DestroyEffect(A.Effect)
call KillUnit(A.dummy)
set bj_groupEnumOwningPlayer = GetOwningPlayer(A.caster)
set TempUnit = A.caster
set TempReal = A.dmg
set AttackType = A.AttackType
set DamageType = A.DamageType
call GroupEnumUnitsInRange(TempG,A.x,A.y,A.radius,Cond)
set A.g = CreateGroup()
set a = A.angle-(90*bj_DEGTORAD)
set d = A.dist2
set x = A.x
set y = A.y
set b = false
call GroupAddUnit(A.g,CreateUnitEx(bj_groupEnumOwningPlayer,'u001',x,y,GetRandomReal(0,360)))
call UnitApplyTimedLife(CUEX,'BTLF',A.tm1)
call SetUnitScale(CUEX,A.sc,A.sc,A.sc)
loop
exitwhen A.count <= 0
set x = A.x+d*Cos(a)
set y = A.y+d*Sin(a)
call GroupAddUnit(A.g,CreateUnitEx(bj_groupEnumOwningPlayer,'u001',x,y,GetRandomReal(0,360)))
call UnitApplyTimedLife(CUEX,'BTLF',A.tm1)
call SetUnitScale(CUEX,A.sc,A.sc,A.sc)
if b then
set a = A.angle-(90*bj_DEGTORAD)
set d = d+A.dist2
set A.count = A.count-1
set b = false
else
set a = A.angle+(90*bj_DEGTORAD)
set b = true
endif
endloop
call CreateUnitEx(Player(0x0F),'u000',A.x,A.y,A.angle*bj_RADTODEG+90)
call SetUnitFlyHeight(CUEX,100,0)
call SetUnitScale(CUEX,A.sc1,A.sc1,A.sc1)
call SetUnitAnimationByIndex(CUEX,0)
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Other\\Doom\\DoomDeath.mdl",CUEX,"chest"))
call KillUnit(CUEX)
call CreateUnitEx(Player(0x0F),'u000',A.x,A.y,A.angle*bj_RADTODEG-90)
call SetUnitFlyHeight(CUEX,100,0)
call SetUnitScale(CUEX,A.sc1,A.sc1,A.sc1)
call SetUnitAnimationByIndex(CUEX,0)
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Other\\Doom\\DoomDeath.mdl",CUEX,"chest"))
call KillUnit(CUEX)
call CreateUnitEx(Player(0x0F),'u000',A.x,A.y,A.angle*bj_RADTODEG)
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Items\\AIfb\\AIfbSpecialArt.mdl",CUEX,"chest"))
call KillUnit(CUEX)
call CreateUnitEx(Player(0x0F),'u000',A.x,A.y,A.angle*bj_RADTODEG)
call SetUnitScale(CUEX,A.sc,A.sc,A.sc)
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Weapons\\PhoenixMissile\\Phoenix_Missile.mdl",CUEX,"chest"))
call KillUnit(CUEX)
call TimerStart(GetExpiredTimer(),0.,false,function PeriodicDamage)
endif
endfunction
private function Phoenix_Actions takes nothing returns nothing
local timer t = CreateTimer()
local Phoenix A = Phoenix.create()
local integer lvl
local real x = GetSpellTargetX()
local real y = GetSpellTargetY()
local real sc
set A.caster = GetTriggerUnit()
set A.x = GetUnitX(A.caster)
set A.y = GetUnitY(A.caster)
set A.angle = Atan2(y-A.y,x-A.x)
set A.x = A.x+50*Cos(A.angle)
set A.y = A.y+50*Sin(A.angle)
set A.dist = SquareRoot((A.x-x)*(A.x-x)+(A.y-y)*(A.y-y))
set A.dist1 = A.dist
set A.fly = GetLocZ(x,y)
set A.fly1 = A.dist/1.5
set A.height = GetLocZ(A.x,A.y)+GetUnitFlyHeight(A.caster)
set A.dummy = CreateUnitEx(GetOwningPlayer(A.caster),'u000',A.x,A.y,A.angle*bj_RADTODEG)
set lvl = GetUnitAbilityLevel(A.caster,'A000')
if lvl == 1 then // уровень
set A.sc = 1.00 // размер стены
set A.sc1 = 0.50 // размер эффектов
set sc = 0.70 // размер феникса
set A.count = 5 // кол-во стенок
set A.dist2 = 50.00 // дистанция между стенками
set A.dmg = 100.00 // урон взрыва феникса
set A.dmg1 = 25.00 // урон стенки
set A.radius = 125.00 // радиус взрыва феникса
set A.radius1 = 95.00 // радиус стенки
set A.tm1 = 2.00 // продолжительность существования стенки
elseif lvl == 2 then
set A.sc = 1.50
set A.sc1 = 0.70
set sc = 1.00
set A.count = 7
set A.dist2 = 50.00
set A.dmg = 150.00
set A.dmg1 = 40.00
set A.radius = 175.00
set A.radius1 = 105.00
set A.tm1 = 3.00
else
set A.sc = 1.90
set A.sc1 = 1.00
set sc = 1.30
set A.count = 10
set A.dist2 = 50.00
set A.dmg = 225.00
set A.dmg1 = 60.00
set A.radius = 250.00
set A.radius1 = 115.00
set A.tm1 = 5.00
if lvl > 3 then
call BJDebugMsg("Phoenix_Actions error: Ability level > 3")
endif
endif
set A.Effect = AddSpecialEffectTarget("units\\human\\phoenix\\phoenix.mdx",A.dummy,"chest") // эффект феникса
set A.AttackType = ATTACK_TYPE_NORMAL // тип атаки
set A.DamageType = DAMAGE_TYPE_NORMAL // тип урона
set A.speed = 15.00 // скорость полёта
set A.tm = 0.25 // периодичность урона стен
set A.speedx = A.speed*Cos(A.angle)
set A.speedy = A.speed*Sin(A.angle)
call SetUnitScale(A.dummy,sc,sc,sc)
call SaveInteger(H,GetHandleId(t),0,A)
call TimerStart(t,.03125,true,function move)
set t = null
endfunction
//===========================================================================
private function mycond takes nothing returns boolean
if GetSpellAbilityId() == 'A000' then
call Phoenix_Actions()
endif
return false
endfunction
function InitTrig_Phoenix takes nothing returns nothing
local rect r = GetWorldBounds()
set gg_trg_Phoenix = CreateTrigger( )
call TriggerRegisterPlayerUnitEvent(gg_trg_Phoenix,Player(0x00),EVENT_PLAYER_UNIT_SPELL_EFFECT,null)
call TriggerAddCondition( gg_trg_Phoenix, Condition(function mycond) )
call RemoveUnit(CreateUnit(Player(0x0F),'u000',0,0,0))
call RemoveUnit(CreateUnit(Player(0x0F),'u001',0,0,0))
set Cond = Condition(function DamageCond)
set MaxX = GetRectMaxX(r)
set MinX = GetRectMinX(r)
set MaxY = GetRectMaxY(r)
set MinY = GetRectMinY(r)
call RemoveRect(r)
set r = null
endfunction
endlibrary
Сорян за некропост, но я путаюсь порой из-за комментариев выше
y0 - высота конечной точки, y1 - начальная высота, h - максимальная высота, d - полное расстояние, x - текущее расстояние до цели
Nikolay36, в смысле булевая не работает?)
проверь вторую карту что я приложил с использованием булевой, всё работает, сообщение показывается только когда он перевоплощается обратно
возможно ты триггерно добавляешь абилку юниту и поэтому она после морфов пропадает? нужно после добавления сделать её перманентной через UnitMakeAbilityPermanent
Одна для всего само собой. Количество объявлений хэштаблиц всё равно ограничено, хотя от Vlod появились недавно ресурсы насчёт хэштаблиц, там много интересного, можешь заценить
В любом случае недавно столкнулся с проблемой сджасса, когда в колбеке переменные объявлены не в начале кода, оно вроде и должно переносить их в начало, но вот поток обрывался почему-то, ошибку парсер не выдал поэтому только дебагом узнал об этом
library mylib
globals
constant hashtable H = InitHashtable()
private constant group TempG = CreateGroup()
private real TempX
private real TempY
private real TempReal
private real TempReal1
private real TempReal2
private real MaxX
private real MinX
private real MaxY
private real MinY
endglobals
private struct mys
unit caster
group g
real x
real y
real dist
real speed
real speedr
real angle
integer count
endstruct
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 function move1 takes nothing returns nothing
call SetUnitPositionEx(GetEnumUnit(),TempX+TempReal2*Cos(TempReal*bj_DEGTORAD),TempY+TempReal2*Sin(TempReal*bj_DEGTORAD))
set TempReal = TempReal+TempReal1
endfunction
private function move takes nothing returns nothing
local mys A = LoadInteger(H,GetHandleId(GetExpiredTimer()),0)
local unit u
set A.angle = A.angle+A.speedr
set A.dist = A.dist-A.speed
set TempX = A.x
set TempY = A.y
set TempReal = A.angle
set TempReal1 = 360/A.count
set TempReal2 = A.dist
call ForGroup(A.g,function move1)
if A.dist <= 50. then
loop
set u = FirstOfGroup(A.g)
exitwhen u == null
call KillUnit(u)
call GroupRemoveUnit(A.g,u)
endloop
call DestroyGroup(A.g)
call FlushChildHashtable(H,GetHandleId(GetExpiredTimer()))
call PauseTimer(GetExpiredTimer())
call DestroyTimer(GetExpiredTimer())
set A.caster = null
set A.g = null
call A.destroy()
endif
endfunction
private function Spell_Actions takes nothing returns nothing
local timer t = CreateTimer()
local mys A = mys.create()
local real a
local real x
local real y
set A.caster = GetTriggerUnit()
set A.g = CreateGroup()
set A.x = GetSpellTargetX()
set A.y = GetSpellTargetY()
set A.dist = 500.
set A.speed = 10.
set A.speedr = 3.
set A.angle = GetRandomReal(0,360)
set A.count = 6
set bj_forLoopAIndex = 0
set a = A.angle
set bj_groupEnumOwningPlayer = GetOwningPlayer(A.caster)
loop
exitwhen bj_forLoopAIndex == A.count
set x = A.x+A.dist*Cos(a*bj_DEGTORAD)
set y = A.y+A.dist*Sin(a*bj_DEGTORAD)
set bj_lastCreatedUnit = CreateUnit(bj_groupEnumOwningPlayer,'u000',x,y,a)
call UnitAddAbility(bj_lastCreatedUnit,'Arav')
call SetUnitFlyHeight(bj_lastCreatedUnit,50,0)
call SetUnitScale(bj_lastCreatedUnit,.5,.5,.5)
call SetUnitPathing(bj_lastCreatedUnit,false)
call GroupAddUnit(A.g,bj_lastCreatedUnit)
set a = a+360/A.count
set bj_forLoopAIndex = bj_forLoopAIndex+1
endloop
set bj_groupEnumOwningPlayer = null
set bj_lastCreatedUnit = null
call SaveInteger(H,GetHandleId(t),0,A)
call TimerStart(t,.03125,true,function move)
set t = null
endfunction
//===========================================================================
private function mycond takes nothing returns boolean
if GetSpellAbilityId() == 'A000' then
call Spell_Actions()
endif
return false
endfunction
function InitTrig_Spell takes nothing returns nothing
local rect r = GetWorldBounds()
set gg_trg_Spell = CreateTrigger( )
call TriggerRegisterPlayerUnitEvent(gg_trg_Spell, Player(0x00), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
call TriggerAddCondition( gg_trg_Spell, Condition(function mycond) )
set MaxX = GetRectMaxX(r)
set MinX = GetRectMinX(r)
set MaxY = GetRectMaxY(r)
set MinY = GetRectMinY(r)
call RemoveRect(r)
set r = null
endfunction
endlibrary
не советую пользоваться сджассом, потом можешь встретиться с фигнёй которую не поймёшь как решить, я долго ломал голову почему мои скиллы при импорте в другую карту переставали работать, пока не понял, что сджасс ломал весь остальной код
struct square
private real x
private real y
private real a
void SetSide(real newSide) {
a=newSide
}
endstruct
void somefunc() {
square A = square.create()
//...
A.SetSide(2.0)
}
оно на вджассе выглядит так
struct square
private real x
private real y
private real a
method SetSide takes real newSide returns nothing
set a = newSide
endmethod
endstruct
function somefunc takes nothing returns nothing
local square A = square.create()
//...
set A.SetSide(2.0)
endfunction
а то что оно делает это очевидно - устанавливает приватной переменной структуры "а" значение 2.0, то есть то, что передали в метод
вероятно эти крипы не под владением нейтрального игрока, если же они у нейтральных, то посмотри не трогал ли ты константы с временем агра и дистанцией агра
function myfunc takes nothing returns nothing
endfunction
на сджассе выглядит так
nothing myfunc(){ }
а void - это лишь макрос, это слово при компиляции заменяется на nothing
в JNGP - AdicParser - lib - cj_types.j можешь найти макросы насчёт void, float, int, bool и т.д.
Гуванч, выносишь все нужные переменные, а именно угол, дистанция и кол-во юнитов в группе - в глобалки, потом через ForGroup двигаешь юнитов, меняя глобальную переменную угла под формулой что я описал выше, после ForGroup плюсуешь к углу нужную реальную, которая влияет на скорость вращения
ну и дистанцию понижаешь после ForGroup, если они в центре должны взорваться, на следующий тик достаёшь все изменённые значения и повторяешь все те же действия, пока все шары не столкнутся в центре
Гуванч, я не говорю что меня что-то не устраивает, и судя по началу это ты проявил агрессию, я же сказал, что если ты умеешь двигать одного юнита, то в чём проблема двигать группу?
если моя "агрессия" проявляется в том, что я назвал делать на каждого юнита таймер для вращения вокруг точки глупым, то это и вправду глупо, когда тут можно обойтись лишь одним таймером, в другом я не вижу проявлений агрессии чтобы клеветать за это
в чём проблема занести их всех в группу и двигать так же, как и того единственного дамми что ты двигал? на крайний, самый тупой случай, делать на каждого дамми по таймеру .-.
то что ты хочешь делается за 10 минут, а основная формула это angle+(360/count) count - число шаров, а angle - угол между центром и даммиками, после движения всех шаров, к этому углу добавить реальную в зависимости от скорости вращения
quq_CCCP, как посмотреть стандартные скилы варкрафт 3? Где лежит код jass на заклинания варкрафт
некоторые абилки ты и сам в состоянии понять как делаются, та же волна силы или ульт рексара, а вариковские абилки на каком-то С языке написаны вроде, и код скорее если и есть у кого, то это единицы, его просто так не найдёшь и не посмотришь
я сам ими интересовался, но те кто смогли бы что-то узнать, им просто лень
» WarCraft 3 / Способности и алгоритмы на заказ
» WarCraft 3 / крипы после боя не идут к центру
Ред. N7 Molot
» Мир безумного / Облучение - Cinematic, Unreal Engine 5
» Блог им. rsfghd / Последний полёт феникса
https://www.xgm.guru/files/2004/264590/comments/472412/PhoenixDa...
» WarCraft 3 / Формула параболы
y0 - высота конечной точки, y1 - начальная высота, h - максимальная высота, d - полное расстояние, x - текущее расстояние до цели
» WarCraft 3 / Как отследить выключение перевоплощения?
проверь вторую карту что я приложил с использованием булевой, всё работает, сообщение показывается только когда он перевоплощается обратно
» WarCraft 3 / Как отследить выключение перевоплощения?
Ред. rsfghd
» WarCraft 3 / Хэш-таблицы в vJass
» WarCraft 3 / кое что о джассе
» WarCraft 3 / кое что о джассе
» Блог пользователя under11 / Кинжал в цель
» WarCraft 3 / как двигать несколько дамми юнитов одновременно
» WarCraft 3 / как двигать несколько дамми юнитов одновременно
Ред. rsfghd
» WarCraft 3 / кое что о джассе
» WarCraft 3 / крипы после боя не идут к центру
Ред. rsfghd
» WarCraft 3 / кое что о джассе
в JNGP - AdicParser - lib - cj_types.j можешь найти макросы насчёт void, float, int, bool и т.д.
» WarCraft 3 / кое что о джассе
Ред. rsfghd
» WarCraft 3 / как двигать несколько дамми юнитов одновременно
Ред. rsfghd
» WarCraft 3 / как двигать несколько дамми юнитов одновременно
Ред. rsfghd
» WarCraft 3 / как двигать несколько дамми юнитов одновременно
Ред. rsfghd
» WarCraft 3 / Есть ли модели дота в открытом доступе?
» WarCraft 3 / loop (цикл) + wait?
Ред. rsfghd
» WarCraft 3 / Проблема с позиционным звуком
Ред. rsfghd
» WarCraft 3 / Утечки в коде
Ред. rsfghd
» WarCraft 3 / Способности и алгоритмы на заказ
Заклинание готово!
Способность: Система Аванпоста
Выполнено: Да