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

  • Автор темы Автор темы M@G
  • Дата начала Дата начала

M@G

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

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

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

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

Но думаю, легче будет разобраться в GetAttackRange(): скинь текст, что пишет при краше.
 
Последнее редактирование модератором:
И еще на крайняк можно сделать пассивку, где можно прописать "специальную" величину (ability special), которой ты присвоишь заранее значение, равное base range юнита, которому дашь эту пассивку и уже через нее доставать эту величину, т.е. base range))
 
Последнее редактирование модератором:
Вот что я выяснил и что сделал (не до конца, или гайд по изменению стандартной способности с использованием динамических значений):

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 косяка: первый - т.к. расчет ренжа делается на стороне сервера, то у пользователя этот ренж на панели героя не отображается; второй - сларк (возможно еще кто-то, пока не тестил) каким-то образом после вЫключения способности перестает наносить урон, т.е. он подходит, начинает бить, проигрывается анимация, слышен звук, но урона нет. Иногда он наносится, но я хз при каких обстоятельствах. Есть идеи?
 
Последнее редактирование модератором:
Так далеко в коде я еще не залазил, так что у меня идей далее нет. Тут надо посидеть и поразбираться. А так молодец, хоть какой-то выход.
 
Думаю раз ты изменяешь рейндж на стороне сервера, на стороне клиента он остается старым и соответственно, когда рейндж на сервере станет равным 0, на клиенте он будет равным 128 например. На клиенте будет анимация, звук, и т.д, а с точки зрения сервера он не может бить => урона нет. Зато если юниты находятся друг в други с проходом коллизий(типо фазов) урон нанесется так как разница между ними будет 0.
 
Последнее редактирование модератором:
Думаю раз ты изменяешь рейндж на стороне сервера, на стороне клиента он остается старым и соответственно, когда рейндж на сервере станет равным 0, на клиенте он будет равным 128 например. На клиенте будет анимация, звук, и т.д, а с точки зрения сервера он не может бить => урона нет. Зато если юниты находятся друг в други с проходом коллизий(типо фазов) урон нанесется так как разница между ними будет 0.
В том то и дело, что на стороне сервера ренж никогда нулевым не становится, а у клиента может быть. Но урон то расчитывается у сервера. Или я опять что-то не так понял?
 
Последнее редактирование модератором:
В том то и дело, что на стороне сервера ренж никогда нулевым не становится, а у клиента может быть. Но урон то расчитывается у сервера. Или я опять что-то не так понял?
Видимо становится.
 
Последнее редактирование модератором:
Реклама: