28

» WarCraft 3 / Анашин - Похититель душ

ArhiMEN, бред, я всегда юзаю эту абилку чтобы отключить юниту атаку на время

может ты её не удаляешь, а заново добавляешь или с равкодом ошибся, или юнит, которому ты удаляешь абилку, не существует (null) или это другой юнит

к тому же зачем тебе мемхак в карте, если ты не пользуешься его функционалом, там наверняка есть тема с блоком возможности атаковать
28

» WarCraft 3 / Анашин - Похититель душ

ArhiMEN, я поставил абилкам перезарядку на 0 и потыкал на кнопочки, в общем счётчик душ каким-то образом сбился у меня, вокруг летало 4 души, убиваю последнего противника и мне пишет "всего душ: 1"

+ у тебя эффекты багуются с обнажением душ, если кастануть обнажение на уже обнаженных

ну и утечки всё-таки остаются, с текстагом и таймером я нашёл и рассказал, остальные сам ищи)
а так хорошо, только что с щитом произошло?
28

» WarCraft 3 / Анашин - Похититель душ

Что за способность?
не поленись и через Ctrl+D Ctrl+F поищи в ро ._.
ArhiMEN:
Не работатет
Работает, не надо тут ляля, FadePoint на 0 ставь

--->

Что за способность?
эта абилка не даст атаковать юниту
28

» WarCraft 3 / Анашин - Похититель душ

хватит обнулять локальные целочисленные и реальные, оно не имеет смысла от слова совсем, проверь пожалуйста спелл SoulAttraction, у тебя создаётся таймер вначале, и если на цели не будет 'B000', то отменить каст абилки, а таймер удалить, если никаких действий больше не будет с ним? Утечка
28

» WarCraft 3 / Анашин - Похититель душ

ArhiMEN, помимо приказов желательно проверять разницу координат точек (сохраняемая и текущая), если разница больше 0 значит юнит сместился и соответственно прервать каст, но я бы на твоём месте просто выдал ему абилку 'Abun' пока он кастует спелл, а по завершении - удалял бы
28

» WarCraft 3 / Анашин - Похититель душ

ArhiMEN, первая и третья абилка с одинаковыми названиями, а души он может призвать ещё до накопления 6 душ (вероятно кривое описание и должно быть он призывает не больше 6 накопленных душ)
дальше, порадовало добавление комбинации с тюрьмой душ и притягиванием, однако есть недоработка, притягивание ты сбрасываешь если Анашин сдвинется с места, вот только если к нему подбежит противник, а он будет притягивать кого-то - он пойдёт атаковать противника а связь не разорвётся

Утечек стало намного меньше, это здорово, но ты всё равно продолжаешь юзать BJ функции и локации, которые порой не удаляешь, как со спавном текстага, кста, насчёт него, зачем ты юзаешь бж функцию получения текстага если можно непосредственно к глобалке обратиться? и вообще можно даже не объявлять переменную Tekst
--->

А если вообще по красоте, создание текстага должно так выглядеть
28

» WarCraft 3 / отлов удара на ГУИ

xgm.guru/p/wc3/jass_triggers там система блока урона на джасс без МемХака, в целом можешь заменить там глобальные переменные на локальные с хештаблицей и вот тебе отлов урона
я видел это, и оно, откровенно говоря, полное говнище))
заключается говняность в том, что если урон больше чем хп юнита, то он сдохнет, а щит не спасёт
не нужно скидывать такое
Вот нормальная система для блока урона без мемхака xgm.guru/p/wc3/negate-damage-lib

(кста, я вроде как тебе её в спеллпак Анашина кидал, странно, что ты проигнорил)
28

» WarCraft 3 / Анашин - Похититель душ

кто-то хочет повторения чего-то подобного?
если повторение подразумевается под всей этой дичью выше - нет, а вот просто посоревноваться за симпатию зрителей у кого герой прикольнее получился в плане скиллов - хочется, пускай даже без призового фонда, хотя бы очки опыта или значок какой-нибудь в статус, лол)
28

» WarCraft 3 / Респавн крипов

Да забей ты на тот счётчик хэндлов ну емае, если ты спавнишь юнита в точке которую запеременил и обнулил если больше не используется, то всё норм

Ты же пишешь на джассе и знаешь что функции например позиция юнита триггера вызывают точку, которая не переменится и вообще никак не обнуляется

Сам юнит это тоже хэндл и чем больше юнитов на карте тем больше хэндлов счётчик будет показывать, это нормально
28

» WarCraft 3 / отлов удара на ГУИ

тут баг очевидный, на юнита регистрируется таймер 0.33, если ему изменить скорость атаки оно сломается (выдать ему перчатки скорости 400% или замедлить атаку увечьем например)
сказали, делай через яд либо все скиллы пиши на джассе, либо используй мемхак


да и к тому же там вроде как есть окно в 0.1 сек, где даже если отменить автоатаку напишет, что урон был

к тому же такая система будет работать только до 8192 (макс размер массива вара) юнитов, потом оно накроется ибо там никак не подчищается таймер, тупо юнит вошёл на карту - увеличили счётчик колва юнитов - запустили таймер равный этому счётчику - добавили событие в другой триггер что таймер этого счётчика истёк

я сам когда увидел в первые эту систему думал что она офигенная, я даже не понимал как оно работает и вообще не умел регистрировать получение юнитом урона))
28

» WarCraft 3 / Castle Revival ARPG beta

По описанию и скринам карта очень сочная, но я тоже не могу заценить, хотелось бы видосик по карте)
28

» WarCraft 3 / Анашин - Похититель душ

Vlod, это ради какого-то конкурса? Тю, я даже не знал, сам бы хотел поучаствовать
28

» WarCraft 3 / Анашин - Похититель душ

Я не понял что имеется ввиду, можно поподробнее, пожалуйста?
видишь у меня на скрине в правом верхнем углу счётчик? это он (кэп)
Имеется ввиду Х и У позиция?
да

тут есть счётчик хэндлов, если не пользуешься сджассом оберни глобалку в globals..endglobals и можешь закидывать к себе в карту либу

счётчик хэндлов поможет определить норм ли всё со скиллами, а именно смотрит растёт ли кол-во хэндлов, если после каста их кол-во не уменьшается - значит это утечки, чем больше утечек тем хуже спелл, если их кол-во достигнет критической отметки - вар крашнет
хэндлы это группы, таймера, юниты, точки, эффекты, молнии, деревья те же на карте, короче вот: xgm.guru/p/wc3/optimisations
28

» Блог им. rsfghd / говно-бумеранг

раскрыть
library mylib initializer init // initializer (с англ.) инициализирует, в нашем случае оно инициализирует функцию init в самом низу
globals
    private constant hashtable H = InitHashtable() // константные переменные - те, что по коду не должны изменяться, то есть если где-то попытаешься задать другое значение этой переменной - выдаст ошибку
    private constant group TempG = CreateGroup()
    private group TempG1
    private real TempR
    
    private real MaxX // значения этим переменным присваиваются в функции инициализации
    private real MinX
    private real MaxY
    private real MinY
    
    // приставки private нужны, чтобы не конфликтовать с функциями извне библиотеки, удобно для импорта в чужую карту
endglobals

native UnitAlive takes unit id returns boolean // объявление нативной функции проверки жив ли юнит, находящаяся в common.j

function DBC takes real x, real y, real x1, real y1 returns real //Distance Between Coordinates (DBC)
   return SquareRoot((x-x1)*(x-x1)+(y-y1)*(y-y1)) 
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 mys // структура это такая таблица данных, при компиляции это всё превращается в обычные глобальные переменные
    unit caster // применяющий
    unit dummy // дамми
    real damage // урон
    real speed // скорость
    real radius // радиус
    real angle // угол
    real distance // дистанция
    group g // группа юнитов, которые получили урон
    boolean b // нужно для разовой очистки группы получивших урон
    
    method Destroy takes nothing returns nothing // методы - функции используемые в структурах, в нашем случае при уничтожении удаляется даммик с группой и обнуляются переменные
        call KillUnit(this.dummy)
        call GroupClear(this.g)
        call DestroyGroup(this.g)
        set this.caster = null
        set this.dummy = null
        set this.g = null
        call this.destroy()
    endmethod
endstruct

private function DamageCond takes nothing returns boolean
    set bj_lastReplacedUnit = GetFilterUnit()
    if not IsUnitInGroup(bj_lastReplacedUnit,TempG1) and UnitAlive(bj_lastReplacedUnit) and IsUnitEnemy(bj_lastReplacedUnit,GetOwningPlayer(bj_lastCreatedUnit)) then
        call UnitDamageTarget(bj_lastCreatedUnit,bj_lastReplacedUnit,TempR,false,false,null,null,null)
        call DestroyEffect(AddSpecialEffectTarget("Objects\\Spawnmodels\\Critters\\Albatross\\CritterBloodAlbatross.mdl",bj_lastReplacedUnit,"chest"))
        call GroupAddUnit(TempG1,bj_lastReplacedUnit)
    endif
    return false
endfunction

private function move takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local mys A = LoadInteger(H,GetHandleId(t),0)
    local real x = GetUnitX(A.dummy)
    local real y = GetUnitY(A.dummy)
    
    if A.distance > 0 then // если юнит не достиг конечной точки, то двигать к ней
        set A.distance = A.distance-A.speed
    else // иначе сменить угол и двигать к кастеру
        call SetUnitFacing(A.dummy,Atan2(GetUnitY(A.caster)-y,GetUnitX(A.caster)-x)*bj_RADTODEG)
        set A.angle = GetUnitFacing(A.dummy)*bj_DEGTORAD
        
        if A.b then // очистить группу получивших урон
            set A.b = false
            call GroupClear(A.g)
        endif
    endif
    set x = x+A.speed*Cos(A.angle)
    set y = y+A.speed*Sin(A.angle)
    call SetUnitPositionEx(A.dummy,x,y)
    
    set TempG1 = A.g
    set TempR = A.damage
    set bj_lastCreatedUnit = A.caster
    call GroupEnumUnitsInRange(TempG,x,y,A.radius,Condition(function DamageCond))
    
    if A.distance <= 0 and DBC(x,y,GetUnitX(A.caster),GetUnitY(A.caster)) <= 50. then
        call FlushChildHashtable(H,GetHandleId(t))
        call PauseTimer(t)
        call DestroyTimer(t)
        call A.Destroy() // вызываем метод уничтожения этой структуры
    endif
    
    set t = null
endfunction

private function myfunc takes nothing returns nothing
    local timer t = CreateTimer()
    local mys A = mys.create() // таким образом объявляется структура. А - название, к которому мы будем обращаться, а mys - название структуры, которую хотим создать
    local integer lvl
    local real x
    local real y
    local real sc
    
    set A.g = CreateGroup()
    set A.caster = GetTriggerUnit()
    set x = GetUnitX(A.caster)
    set y = GetUnitY(A.caster)
    set A.angle = Atan2(GetSpellTargetY()-y,GetSpellTargetX()-x)
    set lvl = GetUnitAbilityLevel(A.caster,'A000')
    set A.dummy = CreateUnit(GetOwningPlayer(A.caster),'u000',x,y,A.angle*bj_RADTODEG)
    call SetUnitPathing(A.dummy,false)
    call UnitAddAbility(A.dummy,'Arav')
    call SetUnitPositionEx(A.dummy,x+50*Cos(A.angle),y+50*Sin(A.angle)) // если юниту что-то помешало заспавниться строго так, как задумано - переместить его в нужную точку
    call SetUnitFlyHeight(A.dummy,50,0)
    
    if     lvl == 1 then // в зависимости от уровня способности определить параметры
        set A.damage = 50.
        set A.speed = 10.
        set A.radius = 100.
        set A.distance = 400.
        set sc = 1.
    elseif lvl == 2 then
        set A.damage = 75.
        set A.speed = 12.
        set A.radius = 150.
        set A.distance = 500.
        set sc = 1.5
    elseif lvl == 3 then
        set A.damage = 130.
        set A.speed = 17.
        set A.radius = 225.
        set A.distance = 700.
        set sc = 2.25
    endif
    set A.damage = A.damage+GetHeroStr(A.caster,true)
    
    call SetUnitScale(A.dummy,sc,sc,sc)
    call SaveInteger(H,GetHandleId(t),0,A) // сохраняем структуру в таймер, структура на самом деле это целочисленная
    call TimerStart(t,.02,true,function move)
    set t = null
endfunction

private function mycond takes nothing returns boolean
    if GetSpellAbilityId() == 'A000' then
        call myfunc()
    endif
    return false
endfunction
private function init takes nothing returns nothing
    local trigger t = CreateTrigger()

    call TriggerRegisterPlayerUnitEvent(t,Player(0x00),EVENT_PLAYER_UNIT_SPELL_EFFECT,null)
    call TriggerAddCondition(t,Condition(function mycond))
    
    set MaxX = GetRectMaxX(GetWorldBounds()) // задаём значения глобалкам, чтобы юнит не мог вылететь за карту и не крашнул нам игру
    set MaxY = GetRectMaxY(GetWorldBounds())
    set MinX = GetRectMinX(GetWorldBounds())
    set MinY = GetRectMinY(GetWorldBounds())

    set t = null
endfunction
endlibrary

library mylib1 initializer init // либа для показа урона
globals
    private trigger trg = CreateTrigger()
endglobals
private function myfunc takes nothing returns boolean
    local texttag t = CreateTextTag()
    
    call SetTextTagText(t,I2S(R2I(GetEventDamage())),10*0.023/10)
    call SetTextTagVelocity(t,64*0.071/128*Cos(90*bj_DEGTORAD),64*0.071/128*Sin(90*bj_DEGTORAD))
    call SetTextTagColor(t,255,0,255,255)
    call SetTextTagPosUnit(t,GetTriggerUnit(),0)
    call SetTextTagPermanent(t,false)
    call SetTextTagLifespan(t,.5)
    call SetTextTagFadepoint(t,0.)
    
    set t = null
    return false
endfunction
private function mycond takes nothing returns boolean
    call TriggerRegisterUnitEvent(trg,GetFilterUnit(),EVENT_UNIT_DAMAGED)
    return false
endfunction
private function init takes nothing returns nothing
    local group g = CreateGroup()
    call GroupEnumUnitsInRect(g,bj_mapInitialPlayableArea,Condition(function mycond))
    call DestroyGroup(g)
    call TriggerAddCondition(trg,Condition(function myfunc))
    set g = null
endfunction
endlibrary



library HC initializer init // счётчик хэндлов чтобы понимать наличие утечек
    globals
    private leaderboard HB
    endglobals
    private function HCU takes nothing returns nothing
        local integer i = 0
        local integer id
        local location array P
        local real result = 0
        loop
            exitwhen i >= 50
            set i = i+1
            set P[i] = Location(0,0)
            set id = GetHandleId(P[i])
            set result = result+(id-0x100000)
        endloop
        set result = result/i-i/2
        loop
            call RemoveLocation(P[i])
            set P[i] = null
            exitwhen i <= 1
            set i = i-1
        endloop
        call LeaderboardSetItemValue(HB,0,R2I(result))
    endfunction

    private function HCA takes nothing returns nothing
        set HB = CreateLeaderboard()
        call LeaderboardSetLabel(HB,"Handle Counter")
        call PlayerSetLeaderboard(GetLocalPlayer(),HB)
        call LeaderboardDisplay(HB,true)
        call LeaderboardAddItem(HB,"Handles",0,Player(0))
        call LeaderboardSetSizeByItemCount(HB,1)
        call HCU()
        call TimerStart(GetExpiredTimer(),.05,true,function HCU)
    endfunction

    private function init takes nothing returns nothing
        call TimerStart(CreateTimer(),0,false,function HCA)
    endfunction
endlibrary
Загруженные файлы
28

» WarCraft 3 / Как повернуть юнита горизонтально или вертикально?

динамически юнита можно повернуть как указали выше, если изначально, то зайди в ро к юниту и найди строку "максимальный угол крена" зажимаешь шифт и -90 к примеру
28

» WarCraft 3 / Нужна модель? - Вам сюда!

Zacharriasz, тимколор текстуры если не ошибаюсь, относится к самой модели, к материалу, так что отдельная тема не нужна)
28

» WarCraft 3 / Функция ForGroup

Гуванч, лол, думаю хвастаться или радоваться этим нужно немного в другом месте)
ах да, не матерись, а то банов от модераторов отхватишь
28

» WarCraft 3 / Анашин - Похититель душ

Перейди с точек на координаты, они быстрее работают и их не нужно обнулять в конце кода, раскрывай BJ функции, зажми ctrl и кликни по ним левой кнопкой мыши, вытащи с них ту функцию, что тебе нужна
к примеру ты юзаешь
function CreateNUnitsAtLoc takes integer count, integer unitId, player whichPlayer, location loc, real face returns group
    call GroupClear(bj_lastCreatedGroup)
    loop
        set count = count - 1
        exitwhen count < 0
        call CreateUnitAtLocSaveLast(whichPlayer, unitId, loc, face)
        call GroupAddUnit(bj_lastCreatedGroup, bj_lastCreatedUnit)
    endloop
    return bj_lastCreatedGroup
endfunction
всё что тебе нужно в данном случае оттуда это
set bj_lastCreatedUnit = CreateUnitAtLoc(id, unitid, loc, face)
которую лучше заменить на
native CreateUnit takes player id, integer unitid, real x, real y, real face returns unit

Ну и дальше, твои спеллы не пригодны для муи, их может юзать лишь один юнит на карте по сути, иначе возможна похожая несостыковка

а, сорян, это не в муи дело, это недоработка автора, что если цель в тюрьме то её можно сделать душой и тюрьма поломается и на юнита в тюрьме можно будет юзануть притягивание души

обнулять локальные целочисленные конечно мощно

в таком предложении
можно обойтись без else

В общем дальше мне лень осматривать, ошибки одни и те же по сути, автору советую почитать больше статей по джассу или обучающих гайдов на ютубе и переделать/доработать скиллы, лайк конечно ставлю за труды, но всё же надеюсь что ты накопаешь больше информации о хорошем коде, с Konstantin19 согласен, спеллы пока что не пригодны к импорту в свою карту, однозначно нужно дорабатывать

Справедливости ради, сопровождение и движение у зелёных огоньков прикольное.
28

» WarCraft 3 / Анашин - Похититель душ

Я посмотрел карту, мне кажется то, что нельзя притягивать юнита во время тюрьмы душ было лишним, хорошая убийственная комбинация могла бы получится, да и потом, молнии порой криво спавнятся

Если у кого-то будут советы по оптимизации кода, буду рад выслушать.
--->

Если делаешь спеллпак, соизволь закинуть счётчик хэндлов в карту, чтобы проверить свои триггеры на наличие утечек. Я понимаю, он не точен, это само собой, но если что-то без конца растёт он даст понять. Например при касте тюрьмы душ у тебя из 300- хэндлов растёт до 1500+

Да и потом, способ реализации у тебя Jass/vJass, мемхак, объявление нативных функций, глобальные переменные объявляемые в коде и т.д. - это всё фишки вджасса

Если ты закинул мемхак в карту только ради щита, то мог воспользоваться библиотекой Negate Damage library от PT153 (сорян за антирекламу мемхака)
28

» WarCraft 3 / Функция ForGroup

Я тебе несколько раз говорил, заноси локальные переменные в глобальные

globals
group TempGroup = CreateGroup()
endglobals

function mycond takes nothing returns boolean
set bj_lastReplacedUnit = GetFilterUnit()
return UnitAlive(bj_lastReplacedUnit) ... and IsUnitEnemy(bj_lastReplacedUnit,GetOwningPlayer(bj_lastCreatedUnit))
endfunction

function damage takes nothing returns nothing
call UnitDamageTarget(bj_lastCreatedUnit,GetEnumUnit()...)
endfunction

function myfunc takes nothing returns nothing
set bj_lastCreatedUnit = GetTriggerUnit()
call GroupEnumUnitsInRange(TempG,GetUnitX(bj_lastCreatedUnit),GetUnitY(bj_lastCreatedUnit),300,Condition(function mycond))
call ForGroup(TempG,function damage)
call GroupClear(TempG)
endfunction
Можно в принципе действия сразу в фильтре делать, возвращая фолс/ничего

function mycond takes nothing returns boolean
set bj_lastReplacedUnit = GetFilterUnit()
if UnitAlive(bj_lastReplacedUnit) ... and IsUnitEnemy(bj_lastReplacedUnit,GetOwningPlayer(bj_lastCreatedUnit)) then
call UnitDamageTarget(bj_lastCreatedUnit,bj_lastReplacedUnit...)
endif
return false
endfunction

function myfunc takes nothing returns nothing
set bj_lastCreatedUnit = GetTriggerUnit()
call GroupEnumUnitsInRange(TempG,GetUnitX(bj_lastCreatedUnit),GetUnitY(bj_lastCreatedUnit),300,Condition(​function mycond))
endfunction

Конечно в юзе вариковских переменных возможна проблема, если например в событии юнит получает урон, создаётся юнит (на гуи, используя переменную bj_lastCreatedUnit), то возможна перезапись, в таком случае достаточно использовать нигде не используемую глобалку, ну либо каждый раз вызывать юнита триггера в функции проверки, как сказал quq_CCCP

о, даже смог найти вопрос где я читал об этом, можешь заглянуть в комменты

вот тебе мини-тест, фильтр в состоянии обработать всех юнитов и продолжить выполнять следующие действия, а цикл обрывает поток
раскрыть
globals
    integer i = 0
    integer count = 1330 // колво юнитов на карте
    group TempG = CreateGroup()
endglobals

function mycond takes nothing returns boolean
    set i = i+1
    call BJDebugMsg(I2S(i))
    return true
endfunction

function Trig_sd_Actions takes nothing returns nothing
    call GroupEnumUnitsInRect(TempG,bj_mapInitialPlayableArea,Condition(function mycond))
    call BJDebugMsg("проигнорировано юнитов: "+I2S(count-i))
    call BJDebugMsg("через 3 сек посмотрим сколько юнитов обработает цикл")
    call TriggerSleepAction(3)
    set i = 0
    loop
        set bj_lastCreatedUnit = FirstOfGroup(TempG)
        exitwhen bj_lastCreatedUnit == null
        set i = i+1
        call BJDebugMsg(I2S(i))
        call GroupRemoveUnit(TempG,bj_lastCreatedUnit)
    endloop
    call BJDebugMsg("проигнорировано юнитов: "+I2S(i))
    // поток обрывается и это сообщение мы даже не увидим, все последующие действия не будут выполнены
endfunction

function s takes nothing returns nothing
    set i = i+1
endfunction

function show takes nothing returns nothing
    set i = 0
    call ForGroup(TempG,function s)
    call BJDebugMsg("проигнорировано юнитов: "+I2S(i))
endfunction

//===========================================================================
function InitTrig_sd takes nothing returns nothing
    set gg_trg_sd = CreateTrigger(  )
    call TriggerAddAction( gg_trg_sd, function Trig_sd_Actions )
    call TimerStart(CreateTimer(),4,false,function show)
endfunction



Загруженные файлы