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

Дополнение метода у конкретного объекта

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

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

Так как ни один нормальный человек скорее всего не поймет тот бред, который я изложил выше, задам свой вопрос на таком примере:
Задача: При направлении способности на базовое дерево Третий подряд вопрос про деревья ДА СКОЛЬКО МОЖНО!?7, в точке местоположения вашего героя создается новое дерево, в то время как старое (то, на которое была направлена способность) срубается на неограниченный срок. При ломке нового дерева старое тут же вырастает. (Вообще цель скила - передвинуть дерево, а после его ломки вернуть обратно. Но двигать его через SetOrigin - так себе идея.)
Никому не нужные рассуждения: Если не писать свое  дерево с нуля (чего мне бы не хотелось делать), то единственный способ создать дерево в точке - это CreateTempTree( pos, 2283221337 ). А единственный способ убрать такое дерево раньше срока - Kill(). Поэтому я уверен, что все дотовские предметы и скилы расправляются со временным деревом именно так. Соответственно мне нужно переопределить метод Kill() для этого дерева так, чтобы в нем сначала выращивалось старое дерево, а потом уже удалялось новое. Но как мне удалить новое дерево, если единственный способ сделать это - Kill(), а именно его я сейчас и переопределяю?
Я пытался сделать так:
Код
--[[
Вырванный кусок кода из тела функции OnSpellStart(). hTarget - старое дерево.
CreateMyTree - созданный мною метод. Делает то же, что и CreateTempTree, но еще и возвращает только что созданное дерево
]]
local model = hTarget:GetModelName()
hTarget:CutDownRegrowAfter( 99999, self:GetCaster():GetTeamNumber() )

local hTree = CreateMyTree( self:GetCaster():GetOrigin(), 99999)
hTree:SetModel( model )
hTree.assigned_tree = hTarget
function hTree:Kill()
if self.assigned_tree then
self.assigned_tree:GrowBack()
end

self.BaseClass.Kill()
end
Но это все равно вызвало рекурсивный вызов, заставивший Доту вылететь. Если честно, я вообще не знаю, как работает ".BaseClass"; я случайно нашел его в шаблоне abilities_lua (или как он там называется) и решил попробовать. Был бы очень рад, если бы еще и объяснили, как пользоваться сим изобретением.
Вопрос: Как выполнить задачу? Абстрактный вопрос описан первым предложением темы.
« Последнее редактирование: 29-05-2017, 18:11:19 от мамин программист »

Оффлайн CryDeS

  • Друзья CG
  • 1212
  • Мощь: 12
Для начала, в lua нет классов, методов и объектов, не упарывайся настолько.
А так, нахрен тебе переопределять его? Сделай вместо переопределение новый метод CustomKill() к примеру, и там уже нормально убивай дерево.

Для начала, в lua нет классов, методов и объектов, не упарывайся настолько.
А так, нахрен тебе переопределять его? Сделай вместо переопределение новый метод CustomKill() к примеру, и там уже нормально убивай дерево.

Мне нужно, чтобы старое дерево восстанавливалось не зависимо от того, как было сломано новое, будь то топорик, или третий скилл энигмы. Как я уже написал, все эти способности скорее всего убирают временные деревья через Kill(). А если делать CustomKill(), то придется с нуля переписывать все существующие абилки, ломающие деревья и менять в них kill на CustomKill. А это долго... (Мне нужны уже существующие абилки)


в lua нет классов, методов и объектов, не упарывайся настолько.
А как же тогда их называть? ;D
« Последнее редактирование: 30-05-2017, 04:39:33 от мамин программист »

Только что нашел слушателя (событие) tree_cut и подумал "Вот оно!", но нет. Он передает только координаты сломанного дерева, а не само дерево. И вычислить сломанное дерево по координатам будет нельзя, так как оно уже сломано. Нет его.
« Последнее редактирование: 30-05-2017, 04:40:54 от мамин программист »

Оффлайн CryDeS

  • Друзья CG
  • 1212
  • Мощь: 12
Мне нужно, чтобы старое дерево восстанавливалось не зависимо от того, как было сломано новое, будь то топорик, или третий скилл энигмы. Как я уже написал, все эти способности скорее всего убирают временные деревья через Kill(). А если делать CustomKill(), то придется с нуля переписывать все существующие абилки, ломающие деревья и менять в них kill на CustomKill. А это долго... (Мне нужны уже существующие абилки)

А как же тогда их называть? ;D
Почему в своей задаче ты так не используешь SetOrigin?
И все дотовские предметы и абилки сделаны не на lua, соответственно просто переопределив lua функцию нихрена не поменяется(скорее всего). И ты уверен что оно уходит в рекурсию(проверил принтами?), а не просто крашит на чем нибудь еще.

Оффлайн MahouShoujo

  • Продвинутый
  • 201
  • Мощь: 3
Методы можно переопределять только для своего кода. Все С++ классы в луа представлены как прокси.

Почему в своей задаче ты так не используешь SetOrigin?
И все дотовские предметы и абилки сделаны не на lua, соответственно просто переопределив lua функцию нихрена не поменяется(скорее всего). И ты уверен что оно уходит в рекурсию(проверил принтами?), а не просто крашит на чем нибудь еще.

SetOrigin для деревьев работает крайне неадекватно. Лучше его вообще не использовать.
Про то, что абилки сделаны не на луа, и переопредение кила ничего не даст, верно подмечено. Я об этом не подумал. А тут еще и пишут, что встроенные функции переопределить вообще нельзя.
И нет, рекурсивный вызов я не проверял. Но когда дота виснет и через пару секунд крашится - это признак, чаще всего свойственный именно неограниченной рекурсии.

Короче понял. Мою задачу надо решать другим путем. У меня есть одна кривая, но единственная идея. Когда реализую - скину код.

Спасибо всем за ответы!

(Вопрос про .BaseClass еще актуален)
« Последнее редактирование: 30-05-2017, 07:59:18 от мамин программист »

Оффлайн MahouShoujo

  • Продвинутый
  • 201
  • Мощь: 3
Код
local oldKill = hTree.Kill
function hTree:Kill(...)
if self.assigned_tree then
self.assigned_tree:GrowBack()
end

oldKill(...)
end

Про бейзкласс в этом случае конкретно не знаю, по-моему он работает только в абилках.

Оффлайн CryDeS

  • Друзья CG
  • 1212
  • Мощь: 12
Код
local oldKill = hTree.Kill
function hTree:Kill(...)
if self.assigned_tree then
self.assigned_tree:GrowBack()
end

oldKill(...)
end

Про бейзкласс в этом случае конкретно не знаю, по-моему он работает только в абилках.
Кстати, очень вероятно, так что можно самому допилить этот BaseClass ко всем деревьям ссылаясь, к примеру, на CBaseEntity в данном случае.

Оффлайн MahouShoujo

  • Продвинутый
  • 201
  • Мощь: 3
Вопрос был для конкретного инстанса, но да, можно. Просто редко имеет смысл.

Оффлайн CryDeS

  • Друзья CG
  • 1212
  • Мощь: 12
Вопрос был для конкретного инстанса, но да, можно. Просто редко имеет смысл.
Или hTree.BaseClass = CBaseEntity, что даст эффект для конкретного инстанса. Но если нужен ток Kill, то твой способ пизже.

В общем, я ошибся везде, где только можно, и даже там, где нельзя.


Дота крашилась не из-за "рекурсивного" вызова через ".BaseClass", а из-за хер знает чего. А именно, из-за этой строчки:
Код
local model = hTarget:GetModelName()
Причем проблема не в GetModelName, а в том, что я применяю его к дереву. С другими юнитами эта функция нормально работает.

Касательно ".BaseClass", когда я все-таки сделал через него, мне написали нил валуе. Видимо, он действительно есть только для способностей

Большое спасибо за этот код:
Код
local oldKill = hTree.Kill
function hTree:Kill(...)
if self.assigned_tree then
self.assigned_tree:GrowBack()
end

oldKill(...)
end
Теперь я хотя бы примерно понимаю, как работать с функциями в луа. Но его надо было немножко изменить, чтобы он начал работать:
Код
hTree.oldKill = hTree.Kill
function hTree:Kill()
if self.assigned_tree then
self.assigned_tree:GrowBack()
end

self.oldKill()
end

И все-таки, как и было предположено, переопределение этого несчастного кила мне ничего не дало. Он делает то, что нужно, когда я вызываю Kill в своем коде. Но валвавские абилки просто ломают дерево, не вызывая Kill.

И внезапно появляется новый вопрос: "Как получить модель выбранного дерева, если GetModelName для него не работает?". А без ответа на этот вопрос, весь этот аутизм, которым я страдал вместе с моими деревьями пропадет напрасным трудом, так как все-таки цель скила - переместить дерево.

Задача решена, если не учитывать проблему с заменой модели. Если коротко, то при использовании скила на кастера вешается модификатор, в который передаются старое и новое деревья, а в его функции OnIntervalThink выполняется проверка на существование нового дерева.
Конечный код способности
Код
function vengefulspirit_nether_swap_sc_lua:OnSpellStart()
local hCaster = self:GetCaster()
local hTarget = self:GetCursorTarget()

local vPos1 = hCaster:GetOrigin()

hTarget:CutDownRegrowAfter( 99999, hCaster:GetTeamNumber() )

hTree = CreateMyTree( vPos1, 99999 )
local info = { hOldTree = hTarget, hNewTree = hTree }
local tree_checker = hCaster:AddNewModifier( hCaster, self, "tree_checker", { duration = -1 } )
tree_checker:SetInfo( info )
function tree_checker:OnIntervalThink()
if self.info.hNewTree:IsNull() then
self.info.hOldTree:GrowBack()
self:Destroy()
end
end
hTree.tree_checker = tree_checker


ResolveNPCPositions( vPos1, 64.0 )
end
Код
tree_checker = class( {} )

function tree_checker:GetAttributes()
return MODIFIER_ATTRIBUTE_MULTIPLE
end

function tree_checker:IsHidden()
return true
end

function tree_checker:OnCreated( kv )
self:StartIntervalThink( 0.2 )
end

function tree_checker:OnIntervalThink()
end

function tree_checker:SetInfo( info )
self.info = info
end
[свернуть]
Это не будет работать для временных деревьев, но это уже не по теме.

Оффлайн Илья

  • Супермодератор
  • 2131
  • Мощь: 21
По моему, тебе действительно проще было бы создать свои деревья и раскидать их по карте. Т.к. двигаться они не будут, то и на производительности это не отразится.

Оффлайн I_GRIN_I

  • Продвинутый
  • 608
  • Мощь: 11
  • Научиться бы скриптить...
А на деревья модификаторы нельзя кидать, это же декорации, да? А как работает сова у трента тогда?