CustomGames.ru - Dota 2 пользовательские игры

Изменение существующего модификатора

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн M@G

  • Продвинутый
  • 63
  • Мощь: 0
Если герою ближнего боя дать абилку троля Berskers Rage, то при переключении она будет уменьшает радиус атаки до нуля, и он перестанет атаковать вовсе. В стандартном файле доты с абилками стоит значение, на которое уменьшается базовая дальность троля. В SpellLibrary - это же значение, но со знаком минус. Есть какие-нибудь варианты исправить это? Нужно чтобы у мили-героев с этой абилкой и при ее переключении была их обычная дальность атаки. Из SpellLibrary абилка работает не полностью. Модификатор на изменение дальности атаки MODIFIER_PROPERTY_ATTACK_RANGE_BONUS то ли сломан, то ли я криворукий. Рассматривал также вариант с внешним луа-модификатором, но заставить его работать при переключении главной абилки не смог.

Оффлайн CryDeS

  • Друзья CG
  • 1200
  • Мощь: 12
Если герою ближнего боя дать абилку троля Berskers Rage, то при переключении она будет уменьшает радиус атаки до нуля, и он перестанет атаковать вовсе. В стандартном файле доты с абилками стоит значение, на которое уменьшается базовая дальность троля. В SpellLibrary - это же значение, но со знаком минус. Есть какие-нибудь варианты исправить это? Нужно чтобы у мили-героев с этой абилкой и при ее переключении была их обычная дальность атаки. Из SpellLibrary абилка работает не полностью. Модификатор на изменение дальности атаки MODIFIER_PROPERTY_ATTACK_RANGE_BONUS то ли сломан, то ли я криворукий. Рассматривал также вариант с внешним луа-модификатором, но заставить его работать при переключении главной абилки не смог.
Как вариант сделай скрытый скилл дающий рейндж?

Оффлайн Илья

  • Супермодератор
  • 1909
  • Мощь: 16
Да, или добавь вызов скрипта, который будет при переключении возвращать ему его дальность.

Оффлайн CryDeS

  • Друзья CG
  • 1200
  • Мощь: 12
Да, или добавь вызов скрипта, который будет при переключении возвращать ему его дальность.
Он вроде про ванильный скилл.

Оффлайн M@G

  • Продвинутый
  • 63
  • Мощь: 0
GetAttackRange крашит доту, если вызывается во внешнем луа-модификаторе, в котором используется через self:GetCaster(). Если прописать это в gamemode, то берется конечный ренж после всех модификаторов, а надо чтобы бралось до, т.е. базовый ренж.

GetBaseAttackRange не распознается нигде. Консоль пишет, что пытается вызвать этот метод (nil value). Бла бла бла.
Тот метод, который мне в итоге нужен, не работает. Кто-нибудь знает функцию, которая может заменить модификатор MODIFIER_PROPERTY_ATTACK_RANGE_BONUS?

Оффлайн Илья

  • Супермодератор
  • 1909
  • Мощь: 16
Я опробовал GetAttackRange() на self:GetCaster(), у меня никакого краша не было.

Если глянуть GitHub, то становистя понятно, что все пользуются  GetAttackRange(), а вот GetBaseAttackRange() почему-то совершенно не в моде. Скорее всего, последний жалуется на неприменимость ко всем классам, кроме "CDOTA_BaseNPC" в следствии проблемы, что была у меня здесь. То есть, у остальных entity попросту нет такого метода и его надо определить в них.

Ну либо отыскать функцию, что даст тебе именно того entity, подобно тому, что я описывал здесь.

Но думаю, легче будет разобраться в GetAttackRange(): скинь текст, что пишет при краше.


Оффлайн Илья

  • Супермодератор
  • 1909
  • Мощь: 16
И еще на крайняк можно сделать пассивку, где можно прописать "специальную" величину (ability special), которой ты присвоишь заранее значение, равное base range юнита, которому дашь эту пассивку и уже через нее доставать эту величину, т.е. base range))

Оффлайн M@G

  • Продвинутый
  • 63
  • Мощь: 0
Вот что я выяснил и что сделал (не до конца, или гайд по изменению стандартной способности с использованием динамических значений):

1. Создал новую абилку троля на базе основной с использованием
Код
"BaseClass"                   "troll_warlord_berserkers_rage"

2. В "AbilitiesSpecial" установил значение "bonus_range" в ноль.
Код
"04"
{   
    "var_type"      "FIELD_INTEGER"
    "bonus_range"       "0"
}

3. Создал луа-модификатор berserkers_rage_bonus_range_modifier.lua в папке scripts/vscripts/heroes/troll_warlord :
Код
if berserkers_rage_bonus_range_modifier == nil then
    berserkers_rage_bonus_range_modifier = class({})
end

4. Т.к. я не стал использовать дополнительную способность, чтобы определять применять модификатор или нет, то прикрепил я его в gamemode.lua в функции GameMode:InitGameMode()
Код
LinkLuaModifier( "berserkers_rage_bonus_range_modifier", "heroes/troll_warlord/berserkers_rage_bonus_range_modifier", LUA_MODIFIER_MOTION_NONE)

5. В той же функции установил фильтр отлова приказов:
Код
GameRules:GetGameModeEntity():SetExecuteOrderFilter(Dynamic_Wrap(GameMode,"FilterExecuteOrder"),self)

6. А ниже прописал саму функцию:
Спойлер
Код
function GameMode:FilterExecuteOrder( filterTable )

    local ability = filterTable[ "entindex_ability" ] --записываем индекс способности из приказа

    if ability > 0 then -- если это действительно способность или предмет

        local order = filterTable[ "order_type" ] -- записываем тип приказа

        if order == DOTA_UNIT_ORDER_CAST_TOGGLE then -- если применилась переключаемая способность

            local ab = EntIndexToHScript( ability ) -- запоминаем саму способность вместо ее индекса
            local ability_name = "troll_warlord_berserkers_rage" --записываем способность, наличие которой и будет определяющим фактором

            if ab:GetAbilityName() == ability_name then -- если использованная способность та, по которой будем проверять

                local hero = EntIndexToHScript( filterTable[ "units" ][ "0" ] ) -- запомнить героя, который ее применил

                local modifier_name = "modifier_" .. ability_name -- для удобства запомнить модификатор, который появляется у героя именно тогда, когда способность во включенном состоянии (он встроенный и идет вместе со способностью, если ее не переписывать полностью)
                local modifier_name_fix = "berserkers_rage_bonus_range_modifier" -- запомнить имя нашего самописного луа-модификатора

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

                if not hero:HasModifier( modifier_name ) then -- если у героя нет модификатора от родной способности
                    local attack_range = hero:GetAttackRange() -- записываем ренж атаки героя
                    hero:AddNewModifier( hero, nil, modifier_name_fix, { range = attack_range } ) -- применяем луа-модификатор к герою, передавая в параметр тот самый ренж
                else -- если у героя есть модификатор от способности(т.е. способность была включена), то при вЫключении способности, он будет удален
                    hero:RemoveModifierByName( modifier_name_fix ) -- вместе с луа-модификатором
                end

            end

        end

    end
--поскольку сама абилка выполняется в любом случае, как и любой другой приказ, пихаем return в самый конец
    return true
end
[свернуть]

7. Записал переданный ренж при создании модификатора в файле самого модификатора:
Код
function berserkers_rage_bonus_range_modifier:OnCreated( kv )
        -- kv - { range = attack_range } из пункта 6
    if IsServer() then
        self.range = kv.range
    end
end
Обязательно использовать IsServer(), иначе будет "ругаться на все что только можно и вылетать по поводу и без повода".

8. Для изменения ренжа героя используется модификатор MODIFIER_PROPERTY_ATTACK_RANGE_BONUS. Поскольку для поставленной задачи надо охватить весь пул существующих в доте героев, то значение для этого модификатора должно быть плавающим и зависеть от имеющейся дальности у героя, которую я записал в предыдущем пункте. Это значит, что этот модификатор (он же функция) надо переопределить, т.к. по умолчанию подразумевается, что он будет использоваться в kv-файле со статичным значением. Переопределил в файле модификатора:
Код
function berserkers_rage_bonus_range_modifier:DeclareFunctions()
    local funcs = {
        MODIFIER_PROPERTY_ATTACK_RANGE_BONUS
    }

    return funcs
end

function berserkers_rage_bonus_range_modifier:GetModifierAttackRangeBonus( params )
    if IsServer() then
        return (( self.range - 128 ) * -1 )
    end
    return 0
end
Соотношение прочих констант и функций можно посмотреть в API

Сервер будет использовать для расчетов формулу из переопределенной функции:
Код
(( self.range - 128 ) * -1 )
где self.range - сохраненный ранее изначальный ренж,
128 - ренж мили героя,
-1 - т.к. при использовании модификатора значения складываются, а нам надо вычесть.

Если не делать первых 2 пункта, то эта формула примет вид:
Код
( 372 - ( self.range - 128) )
где 372 - это то самое значение в AbilitySpecial, которое отвечает за урезание ренжа героя для оригинальной способности в npc_abilities.txt

9. До кучи скрыл модификатор, чтобы глаза не мозолил
Код
function berserkers_rage_bonus_range_modifier:IsHidden()
    return true
end

function berserkers_rage_bonus_range_modifier:IsPurgable()
    return false
end

10. В итоге при наличии у любого героя способности Berserkers Rage и при его включении, герой получает милишный ренж атаки равный 128. При выключении - герой получает свой родной ренж обратно. Все бафы, баши и прочие плюшки от оригинальной способности добавляются. На данный момент нашел 2 косяка: первый - т.к. расчет ренжа делается на стороне сервера, то у пользователя этот ренж на панели героя не отображается; второй - сларк (возможно еще кто-то, пока не тестил) каким-то образом после вЫключения способности перестает наносить урон, т.е. он подходит, начинает бить, проигрывается анимация, слышен звук, но урона нет. Иногда он наносится, но я хз при каких обстоятельствах. Есть идеи?
« Последнее редактирование: 04-02-2016, 12:25:39 от M@G »

Оффлайн Илья

  • Супермодератор
  • 1909
  • Мощь: 16
Так далеко в коде я еще не залазил, так что у меня идей далее нет. Тут надо посидеть и поразбираться.  А так молодец, хоть какой-то выход.

Оффлайн CryDeS

  • Друзья CG
  • 1200
  • Мощь: 12
Думаю раз ты изменяешь рейндж на стороне сервера, на стороне клиента он остается старым и соответственно, когда рейндж на сервере станет равным 0, на клиенте он будет равным 128 например. На клиенте будет анимация, звук, и т.д, а с точки зрения сервера он не может бить => урона нет. Зато если юниты находятся друг в други с проходом коллизий(типо фазов) урон нанесется так как разница между ними будет 0.

Оффлайн M@G

  • Продвинутый
  • 63
  • Мощь: 0
Думаю раз ты изменяешь рейндж на стороне сервера, на стороне клиента он остается старым и соответственно, когда рейндж на сервере станет равным 0, на клиенте он будет равным 128 например. На клиенте будет анимация, звук, и т.д, а с точки зрения сервера он не может бить => урона нет. Зато если юниты находятся друг в други с проходом коллизий(типо фазов) урон нанесется так как разница между ними будет 0.
В том то и дело, что на стороне сервера ренж никогда нулевым не становится, а у клиента может быть. Но урон то расчитывается у сервера. Или я опять что-то не так понял?

Оффлайн CryDeS

  • Друзья CG
  • 1200
  • Мощь: 12
В том то и дело, что на стороне сервера ренж никогда нулевым не становится, а у клиента может быть. Но урон то расчитывается у сервера. Или я опять что-то не так понял?
Видимо становится.

Оффлайн Se7eN

  • Продвинутый
  • 298
  • Мощь: 11
  • King
Да напиши с нуля абилку, че ты паришься.