, Гильдия «Черамор»

Заклинание: Длань Господня

» опубликован
» Способ реализации: Jass
» Тип: Способность
» MUI: да
» Импорт: иконка
» Утечки: нет
» Требования: нет
Длань Господня, способность, которую могли освоить лишь Истинные Паладины. В их руках, эта сила не только излечивала любые раны и болезни. Но и искореняла любое зло, ставшее на пути Паладина.
Божественная вспышка, не знающая пощады для врагов, и дарующая Благодать союзникам.
И самое главное теперь, Паладин может восстановить себе утерянную жизнь, в ровном размере излеченного здоровья или нанесенного урона.
  • Лечит живых или наносит урон андедам в размере "Базовый урон героя * уровень способности".
  • Восстанавливает здоровье кастеру в количестве восстановленного здоровья или нанесённого урона.

Скриншот

Технические подробности

» Перенос в свою карту
Триггеры
  • HolyFist
Способности
  • Длань Господня 'SHoF'
Импорт
  • ReplaceableTextures\CommandButtons\BTNSpellHolyFist.blp
  • ReplaceableTextures\CommandButtonsDisabled\DISBTNSpellHolyFist.blp
» Настройка
local ABILITY_ID = AbilityId('SHoF')
local EFFECT = "Abilities\\Spells\\Human\\HolyBolt\\HolyBoltSpecialArt.mdl"
local EFFECT_ATTACH = "origin"
» Код
//! beginusercode
do
    -- На момент патча 1.31 эта функция всегда возвращает 0. Поэтому создадим её локальный аналог.
    local function AbilityId(id)
        return id:byte(1) * 0x1000000 + id:byte(2) * 0x10000 + id:byte(3) * 0x100 + id:byte(4)
    end

    -- Настройки
    local ABILITY_ID = AbilityId('SHoF')
    local EFFECT = "Abilities\\Spells\\Human\\HolyBolt\\HolyBoltSpecialArt.mdl"
    local EFFECT_ATTACH = "origin"
    
    -- Заклинание
    local t = CreateTrigger()
    for i = 0, bj_MAX_PLAYER_SLOTS - 1, 1 do
        TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_SPELL_EFFECT)
    end
    TriggerAddCondition(t, Condition(function()
        return GetSpellAbilityId() == ABILITY_ID
    end))
    TriggerAddAction(t, function()
        local caster = GetTriggerUnit()
        local target = GetSpellTargetUnit()
        local level = GetUnitAbilityLevel(caster, ABILITY_ID)
        local damage = BlzGetUnitBaseDamage(caster, 1) * level
        local hp_caster = 0

        DestroyEffect(AddSpecialEffectTarget(EFFECT, target, EFFECT_ATTACH))

        if IsUnitType(target, UNIT_TYPE_UNDEAD)
        then
            hp_caster = math.min(damage, GetUnitState(target, UNIT_STATE_LIFE))
            UnitDamageTarget(caster, target, damage, true, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS);
        else
            local hp = GetWidgetLife(target)
            SetWidgetLife(target, hp + damage)
            hp_caster = math.min(damage, GetUnitState(target, UNIT_STATE_MAX_LIFE) - hp)
        end
        
        if hp_caster > 0
        then
            SetWidgetLife(caster, GetWidgetLife(caster) + hp_caster)
            DestroyEffect(AddSpecialEffectTarget(EFFECT, caster, EFFECT_ATTACH))
        end
    end)
end
//! endusercode


Просмотров: 929

» Лучшие комментарии


KaneThaumaturge #1 - 5 месяцев назад 0
Не совсем понял что делает спелл, пока не посмотрел в код. Делай описание по точнее.
Реквестирую больше примеров на луа для чайников, как я.
NazarPunk #2 - 5 месяцев назад 0
Не совсем понял что делает спелл, пока не посмотрел в код.
Описание способностей не моя сильная сторона. Исправил
Реквестирую больше примеров на луа для чайников
Понемногу буду переписывать свои старые заклинания для 1.26 и может новое что-то придумаю)
Bergi_Bear #3 - 5 месяцев назад 0
NazarPunk, неее, давай сразу новые на луа, чтоб двойной профит..
И у меня вопросы по луа, почему триггер локальный?
И особо луа элементов не заметил, больше на CJ похоже, пропали call и then
а что делает строчка do она обязательна?
NazarPunk #4 - 5 месяцев назад 0
еее, давай сразу новые на луа
Я только любимые перегоню)
больше на CJ похоже
На zinc ещё больше похоже, мой старый код перегонять одно удовольствие)
а что делает строчка do
Блок do end создаёт область видимости и переменные наружу не торчат. Поэтому и триггер локальный)
Bergi_Bear #5 - 5 месяцев назад 0
Блок do end создаёт область видимости и переменные наружу не торчат. Поэтому и триггер локальный)
а что такое область видимости? то есть это не обязательно? а если ничего не написать всё будет глобально?
про я хз я не програмист
NazarPunk #6 - 5 месяцев назад 3
а что такое область видимости?
Если в кратце изолирование переменных от других областей кода. Вот простейший пример из документации.
local a = 5
print(a) --> 5

do
  local a = 6 -- create a new local inside the do block instead of changing the existing a
  print(a) --> 6
end

print(a) --> 5
Bergi_Bear #7 - 5 месяцев назад 0
я теперь всё понял, спасибо
ScopteRectuS #8 - 5 месяцев назад 0
У меня тоже вопрос по Lua. Почему здесь нету функций (кроме условия и действия триггера)? Этот код как-то самоинициализируется или его нужно вызвать где-то?
NazarPunk #9 - 5 месяцев назад 1
Почему здесь нету функций
А зачем они в таком простом заклинании? Я повесил слушатель на событие и спрятал переменные в scope. Что ещё нужно?
ScopteRectuS #10 - 5 месяцев назад 0
NazarPunk, ну в jass есть функция для инициализации способности, где создаются триигеры и навешиваются события, а здесь такого нет, из-за этого я не понимаю как это работает.
Bergi_Bear #11 - 5 месяцев назад 0
ScopteRectuS,
как же а это что?
local t = CreateTrigger() - триггер
TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_SPELL_EFFECT) - добавление события
этого уже достаточно чтобы проверять условие и делать действия =)
ScopteRectuS #12 - 5 месяцев назад 0
Bergi_Bear, ну в жасс это еще нужно где-то вызвать. А тут оно само работает или как?
NazarPunk #13 - 5 месяцев назад 1
ну в жасс это еще нужно где-то вызвать
Если конвертировать триггер, то будет тоже самое.
function Trig_cast_Actions takes nothing returns nothing
endfunction

//===========================================================================
function InitTrig_cast takes nothing returns nothing
    set gg_trg_cast = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_cast, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddAction( gg_trg_cast, function Trig_cast_Actions )
endfunction
прикреплены файлы
ScopteRectuS #14 - 5 месяцев назад 0
NazarPunk, функция InitTrig_cast будет вызвана в функции InitCustomTriggers, которая, в свою очередь будет вызвана в main. А здесь не понятно, как происходит инициализация способности.
NazarPunk #15 - 5 месяцев назад 1
ScopteRectuS, эх, а я всегда думал, что можно убрать обёртку.
set gg_trg_cast = CreateTrigger(  )
call TriggerRegisterAnyUnitEventBJ( gg_trg_cast, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddAction( gg_trg_cast, function Trig_cast_Actions )
как происходит инициализация способности
Код исполняется и вешает обработчик на событие. А для инициализации, можно использовать старый добрый таймер.
TimerStart(CreateTimer(), 0, false, function()
	print('Init')
end)
ScopteRectuS #16 - 5 месяцев назад 0
Этот код как функция main сама запускается. Я правильно понимаю? Сори за глупые вопросы, но я кроме жасс не знаю других языков.
NazarPunk #17 - 5 месяцев назад 0
но я кроме жасс не знаю других языков
А я только хотел сравнить с js(
ScopteRectuS:
Этот код как функция main сама запускается
Он сразу исполняется, а так как карта ещё не прогружена оперировать ей неполучится (юнита например разместить на карте не получится). Но можно создавать объекты (триггеры, таймеры, группы) и вешать обработчики событий.
Запуская таймер, вы ставите его в очередь, которая начнёт разгребаться после прогрузки main. Только не забывайте его уничтожать.
TimerStart(CreateTimer(), 0, false, function()
    print('Init')
    DestroyTimer(GetExpiredTimer())
end)
ScopteRectuS #18 - 5 месяцев назад 0
NazarPunk, спасибо большое, кажется, начинаю понемногу понимать.
SomeFire #19 - 5 месяцев назад 0
Он сразу исполняется, а так как карта ещё не прогружена оперировать ей неполучится (юнита например разместить на карте не получится).
Но ведь юниты, расставленные в редакторе, на самом деле ставятся в коде. Тот же самый триггер инициализации карты.
NazarPunk #20 - 5 месяцев назад 0
Но ведь юниты, расставленные в редакторе, на самом деле ставятся в коде. Тот же самый триггер инициализации карты.
Только это jass триггер, луа раньше срабатывает.
ScopteRectuS #21 - 5 месяцев назад 0
Я так полагаю , что работает такой код в тот момент, когда у жасс инициализируются глоб. перменные. Если написать так, то юнит не создается.
Globals
unit u = createUnit( )
endglobals
NazarPunk #22 - 5 месяцев назад 0
Я так полагаю , что работает такой код в тот момент, когда у жасс инициализируются глоб. перменные
Скорее всего сначала lua, потом jass. Можно попробовать BJDebugMsg('jass'), print('lua') ничего не выводит.
PT153 #23 - 5 месяцев назад (отредактировано ) 0
BJDebugMsg
Не надо эту функцию использовать, внутри её цикл, есть куда более эффективная функция, которая асинхронна.
function DebugMsg takes string s returns nothing
    debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0., 0., 5., s)
endfunction
ScopteRectuS, если так написать, то карта вылетит ещё при нажатии на неё, как мне кажется.
NazarPunk:
Только это jass триггер, луа раньше срабатывает.
Там нет триггера, там просто вызов функции из main.

Я верно понял, что союзная нежить будет получать урон?

Я думаю, что блок do...end выполняется во время клика на карту карты (создания лобби для неё), вот и всё. Если это так, то тогда не стоит использовать GetLocalPlayer(), карта вылетит ещё при клике на неё.

Во время создания карты используется функция config, которая также есть и в Lua, насколько помню. Также создаются все глобалки.
NazarPunk #24 - 5 месяцев назад 0
Я думаю, что блок do...end выполняется во время клика на карту карты
do...end создаёт область видимости и выполняется там, где объявлен.
PT153:
если так написать, то карта вылетит ещё при нажатии на неё, как мне кажется
скорей всего юнит не создатся. хотя тестить нужно
PT153:
Не надо эту функцию использовать
я уже на lua перешёл, а функция для теста приводилась.
PT153:
((цитата
Я верно понял, что союзная нежить будет получать урон?
))
да
PT153:
Во время создания карты используется функция config
Может package.config()? И скорее всего близы её прикрыли.
pro100master #25 - 5 месяцев назад 0
NazarPunk, вреш!
Станартный луа
как видим его создает внутри функции и обазначают
прикреплены файлы
NazarPunk #26 - 5 месяцев назад 0
Станартный луа
Как я сразу не догадался в этот файл заглянуть, теперь всё понятно.
function InitGlobals()
end

--> Пользовательский код

function main()
end

function config()
end
PT153 #27 - 5 месяцев назад 0
скорей всего юнит не создатся. хотя тестить нужно
Обычно карта просто вылетает. Это как создать регион или выполнить GetLocalPlayer().
NazarPunk:
выполняется там, где объявлен.
Ну так об этом же. Объявил, он и выполнился во время клика на карту (создание лобби с картой).
prog #28 - 5 месяцев назад 2
во время клика на карту
Откуда дровишки о том что на этом этапе вобще что-то выполняется из юзер-кода? И почему я уверен что код начинает выполняться где-то в процессе загрузки карты, уже после перехода из лобби?
ScopteRectuS #29 - 5 месяцев назад (отредактировано ) 0
Есть ли в Lua нечто похожее на / /! inject main из vJass?
NazarPunk #30 - 5 месяцев назад 0
ScopteRectuS, зачем вам эти древние костыли?
ScopteRectuS #31 - 5 месяцев назад 0
NazarPunk, хочу полностью управлять тем, как инициализируется карта.
NazarPunk #32 - 5 месяцев назад 3
хочу полностью управлять тем, как инициализируется карта.
Правьте war3map.lua))
PT153 #33 - 5 месяцев назад (отредактировано ) 0
prog, это лишь мои догадки, скорее всего ты прав. Но глобалки точно инициализируются при клике на карту, потому что если дать неверное значение глобалке, то при клике на карту игра крашнется.
NazarPunk, это не костыли, а весьма удобный способ править функции config и main. Без инжекта тебе после каждого нового сохранения придётся править war3map.lua или war3map.j заново, потому что редактор эти файлы перезаписывает.
DarkLigthing #34 - 5 месяцев назад (отредактировано ) 0
Зачем Set/GetWidgetLife, если он всё равно преобразуется в Set/GetUnitLife... (:
NazarPunk #35 - 5 месяцев назад 3
DarkLigthing:
Зачем Set/GetWidgetLife, если он всё равно преобразуется в Set/GetUnitLife... (:
Высмысле преобразуется? Это же нативка.
prog #36 - 5 месяцев назад 2
PT153, к сожалению кастом код весь инжектится при сохранении в код карты раньше функций инициализации - переопределить их напрямую не выйдет. Можно попробовать по играться с метатаблицами или хуками, но скорее всего не выйдет или выйдет но через подлежащий обрезке функционал.
Главный вопрос - зачем править руками конфиг и мейн? Какие задачи решаются правкой этих двух функций и не могут быть решены другими способами?
PT153 #37 - 5 месяцев назад 0
сожалению кастом код весь инжектится
Это ты про Lua?
Главный вопрос - зачем править руками конфиг и мейн?
Например.
» config
//! textmacro InitPlayerWithTeam takes i, team
    set p = Player($i$)
    call DefineStartLocation($i$, CENTER_X, CENTER_Y)
    call SetPlayerStartLocation(p, $i$)
    call SetPlayerColor(p, ConvertPlayerColor($i$))
    static if TestingEnabled then
    call SetPlayerRacePreference(p, RACE_PREF_HUMAN)
    else
    call SetPlayerRacePreference(p, RACE_PREF_RANDOM)
    endif
    call SetPlayerRaceSelectable(p, true)
    call SetPlayerController(p, MAP_CONTROL_USER)
    call SetPlayerTeam(p, $team$)
//! endtextmacro

//! textmacro InitPlayer takes i
    set p = Player($i$)
    call DefineStartLocation($i$, CENTER_X, CENTER_Y)
    call SetPlayerStartLocation(p, $i$)
    call SetPlayerColor(p, ConvertPlayerColor($i$))
    static if TestingEnabled then
    call SetPlayerRacePreference(p, RACE_PREF_HUMAN)
    else
    call SetPlayerRacePreference(p, RACE_PREF_RANDOM)
    endif
    call SetPlayerRaceSelectable(p, true)
    call SetPlayerController(p, MAP_CONTROL_USER)
    call SetPlayerTeam(p, $i$)
//! endtextmacro

//! inject config
    local player p
    call SetMapName("TRIGSTR_001")
    call SetMapDescription("TRIGSTR_024")
    call SetPlayers(MaxUserPlayers)
    static if TestingEnabled then
        call SetTeams(2)
    //! runtextmacro InitPlayerWithTeam("0", "0")
    //! runtextmacro InitPlayerWithTeam("1", "1")
    //! runtextmacro InitPlayerWithTeam("2", "1")
    //! runtextmacro InitPlayerWithTeam("3", "1")
    //! runtextmacro InitPlayerWithTeam("4", "1")
    //! runtextmacro InitPlayerWithTeam("5", "1")
    //! runtextmacro InitPlayerWithTeam("6", "1")
    //! runtextmacro InitPlayerWithTeam("7", "1")
    //! runtextmacro InitPlayerWithTeam("8", "1")
    //! runtextmacro InitPlayerWithTeam("9", "1")
    else
        call SetTeams(MaxUserPlayers)
    //! runtextmacro InitPlayer("0")
    //! runtextmacro InitPlayer("1")
    //! runtextmacro InitPlayer("2")
    //! runtextmacro InitPlayer("3")
    //! runtextmacro InitPlayer("4")
    //! runtextmacro InitPlayer("5")
    //! runtextmacro InitPlayer("6")
    //! runtextmacro InitPlayer("7")
    //! runtextmacro InitPlayer("8")
    //! runtextmacro InitPlayer("9")
    endif
    set p = null
//! endinject
А main для того, чтобы всякие бесполезные надстройки для моей карты не настраивались, которые нужны для остальных карт.