27

» WarCraft 3 / Как на 1.26 отследить вход раба в логово, чтоб сделать действие

вход можно через событие "погружен на транспорт"
выход можно отследить через событие "получил приказ". При выходе юнит получает приказ "stop".
А если зданием пробовать выгрузить всех, это отслеживать не нужно по идее. тк второй триггер сделает все хорошо.
27

» WarCraft 3 / Перенос импорта с сохранением путей.

в рефордже все делается итак без этого)) в режим папки переводишь, и все.
Тут есть утилиты, правда я ни разу не пользовался)) например, для кампании. подожди, пока снизу кто-нибудь шарящий ответит
27

» WarCraft 3 / Проблема с тайлсетами

MPQ-архиватором вскрываем какой то архив mpq, там в игре их несколько
архив/TerrainArt/Terrain.slk
27

» WarCraft 3 / Скачать триггер из Дота 2

Не, саму кнопку норм видно. Я имею ввиду эффект нажатия. Прям не совсем отчётливо это видно. Я просто как раз подумал заменить кнопку в карте, но нет. Пока не то, что нужно☺
можно из кампании спиздить, не помню было ли. подъемники там были

в идеале надо сильно деформацию вниз. чтобы видно было.
27

» WarCraft 3 / Кнопки Меню, Общение, Союзники при помощи мемхака

там в разделе фреймы у анрайза. к ним есть отдельные функции. найди там

мб найти полосу. и отследить потомков
27

» WarCraft 3 / Заростание почвы

вот для рефорджа карта и скрипт пример заростания почвы
скрипт
do
    local InitGlobalsOrigin = InitGlobals
    function InitGlobals()
        InitGlobalsOrigin()



----------------------------------------------- SquareArray
if not SquareArray then
local floor = math.floor
local ceil = math.ceil


local function round(x) return x > 0 and floor(x+0.5) or ceil(x-0.5) end

local function norm_x(self, x)
	if x < self.minX or x > self.maxX then return nil
	else return x end
end

local function norm_y(self, y)
	if y < self.minY or y > self.maxY then return nil
	else return y end
end

local function norm_ix(self, ix)
	if ix < self.minIX or ix > self.maxIX then return nil
	else return ix end
end

local function norm_iy(self, iy)
	if iy < self.minIY or iy > self.maxIY then return nil
	else return iy end
end

local index = {}

function index:norm_xy(x,y) return norm_x(self, x), norm_y(self, y) end

function index:is_xy(x, y) return norm_x(self, x) and norm_y(self, y) end

function index:real_to_index(x, y)
	x, y = self:norm_xy(x, y)
	if not (x and y) then return nil end
	local offsetX, offsetY, step = self.offsetX, self.offsetY, self.step
	local ix = round((x+offsetX)/step)
	local iy = round((y+offsetY)/step)
	return ix, iy
end

function index:get_xy(x, y)
	local ix, iy = self:real_to_index(x, y)
	return ix and self.grid[iy][ix] or nil
end

function index:set_xy(x, y, val)
	local ix, iy = self:real_to_index(x, y)
	if ix then self.grid[iy][ix] = val end
end

function index:get_ixiy(ix, iy)
	return self.grid[iy][ix]
end

function index:set_ixiy(ix, iy, val)
	self.grid[iy][ix] = val
end

function index:id_xy(x, y)
	local ix, iy = self:real_to_index(x, y)
	if ix then
		return iy*self.maxIX + ix
	else return nil end
end

function index:by_all_square()
	local offsetX, offsetY, step = self.offsetX, self.offsetY, self.step
	local minIX, minIY, maxIX, maxIY = self.minIX, self.minIY, self.maxIX, self.maxIY
	-- print(offsetX, offsetY, step)
	-- print(minIX, minIY, maxIX, maxIY)
	local t_minIX = minIX - 1
	return function()
		t_minIX = t_minIX + 1
		if t_minIX > maxIX then
			t_minIX = minIX
			minIY = minIY + 1
		end
		if minIY <= maxIY then
			return t_minIX*step-offsetX, minIY*step-offsetY, t_minIX, minIY
		end
	end
end

local mt = {__index = index}

function SquareArray(minX, maxX, minY, maxY, step)
	local grid = {}
	local object = { minX=minX, maxX=maxX, minY=minY, maxY=maxY, step=step,
		offsetY = -minY, offsetX = -minX, players = {},
		minIX = 0, minIY = 0, maxIX = round((maxX-minX)/step), maxIY = round((maxY-minY)/step),
		grid = grid,
	}
	for i=0, object.maxIY do grid[i] = {} end
	return setmetatable(object, mt)
end
end
----------------------------------------------- Time
if not TimeSystem then
function TimeSystem(ptime)
	local list = {}
	local ht = {}
	local tick = 0
	local ptime = ptime or 0.03125
	local Time = {}

	-- @param func function(time) [[your code]] end
	local function subscribe(func)
		table.insert(list, func)
		ht[func] = true
	end

	local function unsubscribe(func)
		if ht[func] then
			for i=1, #list do
				if list[i] == func then table.remove(list, i); ht[func] = nil end
			end
		end
	end

	local function update()
		tick = tick + 1
		local time = tick*ptime
		Time.time = time
		for i=1, #list do
			list[i](time)
		end
	end
	stop = true
	local function run()
		while stop do
			update()
		end
	end

	Time.ptime = ptime
	Time.time = 0
	Time.subscribe = subscribe
	Time.unsubscribe = unsubscribe
	Time.run = run

	-- connect API game
	TimerStart(CreateTimer(), ptime, true, update)
	return Time
end
end
----------------------------------------------- TimerHeap
if not TimerHeap then
local assert = assert
local floor = math.floor
--================================================================
-- https://github.com/Tieske/binaryheap.lua/blob/master/src/binaryheap.lua
-- basic heap sorting algorithm
--================================================================

--- Basic heap.
-- This is the base implementation of the heap. Under regular circumstances
-- this should not be used, instead use a _Plain heap_ or _Unique heap_.
-- @section baseheap

--- Creates a new binary heap.
-- This is the core of all heaps, the others
-- are built upon these sorting functions.
-- @param swap (function) `swap(heap, idx1, idx2)` swaps values at
-- `idx1` and `idx2` in the heaps `heap.values` and `heap.payloads` lists (see
-- return value below).
-- @param erase (function) `swap(heap, position)` raw removal
-- @param lt (function) in `lt(a, b)` returns `true` when `a < b` (for a min-heap)
-- @return table with two methods; `heap:bubbleUp(pos)` and `heap:sinkDown(pos)`
-- that implement the sorting algorithm and two fields; `heap.values` and
-- `heap.payloads` being lists, holding the values and payloads respectively.
local binaryHeap = function(swap, erase, lt)

	local heap = {
			values = {},  -- list containing values
			erase = erase,
			swap = swap,
			lt = lt,
		}

	function heap:bubbleUp(pos)
		local values = self.values
		while pos>1 do
			local parent = floor(pos/2)
			if not lt(values[pos], values[parent]) then
					break
			end
			swap(self, parent, pos)
			pos = parent
		end
	end

	function heap:sinkDown(pos)
		local values = self.values
		local last = #values
		while true do
			local min = pos
			local child = 2 * pos

			for c = child, child + 1 do
				if c <= last and lt(values[c], values[min]) then min = c end
			end

			if min == pos then break end

			swap(self, pos, min)
			pos = min
		end
	end

	return heap
end

--================================================================
-- plain heap management functions
--================================================================

--- Plain heap.
-- A plain heap carries a single piece of information per entry. This can be
-- any type (except `nil`), as long as the comparison function used to create
-- the heap can handle it.
-- @section plainheap
do end -- luacheck: ignore
-- the above is to trick ldoc (otherwise `update` below disappears)

local update_old
--- Updates the value of an element in the heap.
-- @function heap:update
-- @param pos the position which value to update
-- @param newValue the new value to use for this payload
update_old = function(self, pos, newValue)
	assert(newValue ~= nil, "cannot add 'nil' as value")
	assert(pos >= 1 and pos <= #self.values, "illegal position")
	self.values[pos] = newValue
	if pos > 1 then self:bubbleUp(pos) end
	if pos < #self.values then self:sinkDown(pos) end
end

local remove
--- Removes an element from the heap.
-- @function heap:remove
-- @param pos the position to remove
-- @return value, or nil if a bad `pos` value was provided
remove = function(self, pos)
	local last = #self.values
	if pos < 1 then
		return  -- bad pos

	elseif pos < last then
		local v = self.values[pos]
		self:swap(pos, last)
		self:erase(last)
		self:bubbleUp(pos)
		self:sinkDown(pos)
		return v

	elseif pos == last then
		local v = self.values[pos]
		self:erase(last)
		return v

	else
		return  -- bad pos: pos > last
	end
end

local insert
--- Inserts an element in the heap.
-- @function heap:insert
-- @param value the value used for sorting this element
-- @return nothing, or throws an error on bad input
insert = function(self, value) -- changed
	assert(value ~= nil, "cannot add 'nil' as value")
	local pos = #self.values + 1
	self.values[pos] = value
	self.position[value] = pos
	self:bubbleUp(pos)
end

local pop
--- Removes the top of the heap and returns it.
-- @function heap:pop
-- @return value at the top, or `nil` if there is none
pop = function(self)
	if self.values[1] ~= nil then
		return remove(self, 1)
	end
end

local peek
--- Returns the element at the top of the heap, without removing it.
-- @function heap:peek
-- @return value at the top, or `nil` if there is none
peek = function(self)
	return self.values[1]
end

local size
--- Returns the number of elements in the heap.
-- @function heap:size
-- @return number of elements
size = function(self)
	return #self.values
end

local function swap(heap, a, b) -- (pos_a and pos_b) -- changed
	heap.position[heap.values[a]], heap.position[heap.values[b]] = b, a
	heap.values[a], heap.values[b] = heap.values[b], heap.values[a]
end

local function erase(heap, pos) -- changed
	heap.position[heap.values[pos]] = nil
	heap.values[pos] = nil
end

--================================================================
-- new functions
-- changed: erase, swap, insert
local function append(self, obj)
	local pos = self.position[obj]
	if pos then
		self:update_old(pos, obj)
	else
		self:insert(obj)
	end
end

local function drop(self, obj)
	local pos = self.position[obj]
	if pos and self.values[pos] ~= nil then
		return remove(self, pos)
	end
end

local function update(self, obj)
	local pos = self.position[obj]
	if pos then
		self:update_old(pos, obj)
	else return nil end
end

local function first(self)
	return self.values[1]
end

--================================================================
--================================================================
-- TimerHeap heap creation
--================================================================

function TimerHeap(lt)
	-- if not lt then lt = function(a,b) return a[1] < b[1] end end
	local h = binaryHeap(swap, erase, lt)
	h.peek = peek
	h.pop = pop
	h.size = size
	h.remove = remove
	h.insert = insert -- changed
	h.update_old = update_old -- renamed

	h.position = {}
	h.append = append
	h.drop = drop
	h.update = update
	h.first = first
	return h
end
end
----------------------------------------------- Timer
if not TimerSystem then
local TimerHeap = TimerHeap
local TimeSystem = TimeSystem
assert(TimerHeap, TimeSystem)


----- class Timer
local index = {}

function index:every(delay, count, func, arg)
	if type(func) ~= 'function' then print('error') return end
	local Time = self.Time
	if delay <= 0 then delay = Time.ptime end
	self.delay = delay
	self.count = count
	self.func = func
	self.arg = arg
	self.start_time = Time.time
	self.end_time = Time.time + delay
	self.Heap:append(self)
	return self
end

function index:after(delay, func, arg)
	return self:every(delay , 1, func, arg)
end

function index:pause()
	return self.Heap:drop(self)
end

function index:remained()
	local time = self.end_time - self.Time.time
	return time > 0 and time or 0
end

local mt = {__index = index}
-----

local function lt(a,b) return a.end_time < b.end_time end

function TimerSystem(Time)
	Time = Time or TimeSystem()
	assert(Time)
	local Heap = TimerHeap(lt)

	local Timer = {}
	function Timer.new()
		local timer = {Time = Time, Heap = Heap}
		return setmetatable(timer, mt)
	end

	function Timer.after(...)
		return Timer.new():after(...)
	end

	function Timer.every(...)
		return Timer.new():every(...)
	end

	local function update_timer(self) -- timer
		self.count = self.count - 1
		if self.count > 0 then
			self.count = self.count - 1
			self.start_time = self.end_time
			self.end_time = self.end_time + self.delay
			Heap:append(self)
		end
		self.func(self, self.arg)
		if self.count <= 0 then Heap:pop() end
	end

	Time.subscribe(function(time)
		local timer = Heap:first()
		while timer and timer.end_time and timer.end_time <= time do
			update_timer(timer)
			timer = Heap:first()
		end
	end)
	return Timer
end
end
----------------------------------------------- TerrainSystem
if not TerrainSystem then
-- types - цепочки превращений земли до FOOTBALL_GRASS 
-- type - тип почвы
-- time - время перехода до следующей стадии
local EARTH = {
	{types = {'Ldrt', 'Ldrg', 'Fdrg'}, time = 3},
	{types = {'Lrok', 'Frok'}, time = 4},
}
local FOOTBALL_GRASS = {type = 'Lgrs', time = 5}
local GREEN_GRASS = {type = 'Lgrd', time = 6}
local YELLOW_GRASS = {type = 'Fgrd'}

local function FourCC(str)
	local n, len = 0, #str
	for i = len, 1, -1 do n = n + (str:byte(i,i) << 8*(len-i)) end -- shift by 0,8,16,24
	return n
end
local ALL_TYPES = {}
local function add_all_types(tbl) -- преобразовавыем строки в числа в бд
	if tbl.type then
		local str = tbl.type
		tbl.type = FourCC(tbl.type)
		ALL_TYPES[tbl.type] = str
	elseif tbl.types then
		for i=1, #tbl.types do
			local str = tbl.types[i]
			tbl.types[i] = FourCC(tbl.types[i])
			ALL_TYPES[tbl.types[i]] = str
		end
	else
		for _, dict in ipairs(tbl) do add_all_types(dict) end
	end
end
add_all_types{EARTH, FOOTBALL_GRASS, GREEN_GRASS, YELLOW_GRASS}

local function IsEarth(self,x,y)
	local typ = self.get_type(x,y)
	for _, chain in ipairs(EARTH) do
		for _, next_typ in ipairs(chain.types) do
			if next_typ == typ then return true end
		end
	end
end

local function IsYellowGrass(self,x,y)
	return self.get_type(x,y) == YELLOW_GRASS.type
end

local function IsGreenGrass(self,x,y)
	return self.get_type(x,y) == GREEN_GRASS.type
end

local function IsFootballGrass(self,x,y)
	return self.get_type(x,y) == FOOTBALL_GRASS.type
end

-- @param typ - optional - needed type
-- @return (next_type, time) or nil
local function next(self, x, y, typ)
	local typ = typ or self.get_type(x,y)
	local time, next_typ

	if not ALL_TYPES[typ] then return nil end
	if GREEN_GRASS.type == typ then
		time = GREEN_GRASS.time
		next_typ = YELLOW_GRASS.type
		return next_typ, time
	elseif FOOTBALL_GRASS.type == typ then
		time = FOOTBALL_GRASS.time
		next_typ = GREEN_GRASS.type
		return next_typ, time
	else
		for _, chain in ipairs(EARTH) do -- пробегаем по EARTH
			for i, next_typ in ipairs(chain.types) do
				if typ == next_typ then -- если совпал тип
					if i >= #chain.types then -- если последняя стадия
						next_typ = FOOTBALL_GRASS.type
					else
						next_typ = chain.types[i+1]
					end
					time = chain.time
					return next_typ, time
				end
			end
		end
	end
end

local update
local function save_point(self, x, y, time)
	local timer = self.array:get_xy(x,y)
	if not timer then
		timer = self.Timer.after(time, update, {self,x,y,1}) -- 1-speed
		-- timer = Timer.start(time, false, update, {self,x,y,1})
		self.array:set_xy(x,y, timer)
	else
		timer:after(time, update, {self,x,y,1})
	end
end

update = function(timer, arg)
	local self, x, y = arg[1], arg[2], arg[3]
	local typ, dtime = next(self, x, y)
	assert(typ)
	self.set_type(x,y, typ)
	typ, dtime = next(self, x, y, typ)
	-- print('next typ', ALL_TYPES[typ])
	if typ then
		timer:after(dtime, update, arg)
	else
		self.array:set_xy(x,y,nil)
	end
end

local index = {}
function index:start_tox(x,y) --> true or false
	if self.array:is_xy(x,y) then
		local typ, dtime = next(self, x, y)
		if not dtime then return false end
		save_point(self, x, y, dtime)
	else return false end
end

function index:stop_tox(x,y)
	local timer = self.array:get_xy(x,y)
	if timer then
		timer:pause()
		self.array:set_xy(x,y,nil)
	end
end

function index:modification(x,y, ratio) --> true or false
	local timer = self.array:get_xy(x,y)
	-- print('timer', timer, x, y)
	if timer then
		local speed = timer.arg[4] + ratio
		timer.arg[4] = speed
		local dtime = timer:remained()*(speed >= 0 and speed or 0)
		-- print('dtime', dtime)
		timer:after(dtime, timer.func, timer.arg)
		return true
	else return false end
end

function index:init()
	local rand, array = math.random, self.array
	local up_time = (array.maxIX*array.maxIY)/100
	for x, y, ix, iy in array:by_all_square() do
		local typ, dtime = next(self, x, y)
		if dtime then
			dtime = dtime+rand()*up_time
			save_point(self, x, y, dtime)
		end
	end
end

index.IsEarth = IsEarth
index.IsGreenGrass = IsGreenGrass
index.IsYellowGrass = IsYellowGrass
index.IsFootballGrass = IsFootballGrass

local mt = {__index = index}

-- @param Timer = require "Timer"
-- @param array = require "SquareArray"
-- @param get_type = function(real x, real y) --> terrain_type
-- @param set_type = function(real x, real y, terrain_type type)
function TerrainSystem(tbl)
	assert(tbl.Timer and tbl.array and tbl.get_type and tbl.set_type)
	local object = {
		Timer = tbl.Timer,
		get_type = tbl.get_type,
		set_type = tbl.set_type,
		array = tbl.array,
	}
	return setmetatable(object, mt)
end

end

----------------------------------------------- Пример использования TerrainSystem

print(1)
-- math.randomseed(GetRandomInt(0, 2147483648-1)) -- синхронизируем lua рандом
print(2)
local world_rect = GetWorldBounds()
local minX, maxX, minY, maxY = GetRectMinX(world_rect), GetRectMaxX(world_rect), GetRectMinY(world_rect), GetRectMaxY(world_rect)
local step = 128 -- шаг сетки
print(3)
local Timer = TimerSystem()
print(4)
local ts_array = SquareArray(minX, maxX, minY, maxY, step) -- квадратный массив для создания TerrainSystem
print(5)
local ts_set = function (x,y,typ) SetTerrainType(x,y,typ,math.random(4)-1,1,0) end
print(6)
local ts_get = GetTerrainType
print(7)
ter_sys = TerrainSystem{
	Timer = Timer,
	array = ts_array,
	get_type = ts_get,
	set_type = ts_set,
}
print(8)
-- функция конвертации строки-типа в число, для того чтобы показать пример
local function FourCC(str)
	local n, len = 0, #str
	for i = len, 1, -1 do n = n + (str:byte(i,i) << 8*(len-i)) end -- shift by 0,8,16,24
	return n
end
print(9)
-- создаем 3 участка
SetTerrainType(-200,200, FourCC('Ldrg'), 1, 3, 0)

SetTerrainType(200,-200, FourCC('Lrok'), 1, 3, 0)

SetTerrainType(-200,-200, FourCC('Ybtl'), 1, 3, 0)


-- print('ter_sys:IsEarth(-200, 200)', ter_sys:IsEarth(-200, 200))
-- print('ter_sys:IsYellowGrass(-200, 200)', ter_sys:IsYellowGrass(-200, 200))

-- запуск по всей карте
ter_sys:init() 


-- запуск в квадратном участке
-- for x = -384, 384, 128 do
-- 	for y = -384, 384, 128 do
-- 		ter_sys:start_tox(x, y)
-- 	end
-- end

-- Timer.after(1, function()
-- 	ter_sys:stop_tox(0,128)
-- 	ter_sys:modification(128,0, 5)
-- end)


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

» Программирование / TimerSystem

Vlod, очень интересно, надо попробовать вместе этим багом, будет приколько если он не проявится
проверь есть ли замедление
27

» WarCraft 3 / Отметка на мини-карте от ИИ

нет. это я не знаю. то, что вы предлагаете
может это поможет?
jass
SetAllyColorFilterState( 0 )
native PingMinimap takes real x, real y, real duration returns nothing
native PingMinimapEx takes real x, real y, real duration, integer red, integer green, integer blue, boolean extraEffects returns nothing
function PingMinimapForForce takes force whichForce, real x, real y, real duration returns nothing
    if (IsPlayerInForce(GetLocalPlayer(), whichForce)) then
        // Use only local code (no net traffic) within this block to avoid desyncs.
        call PingMinimap(x, y, duration)
        //call StartSound(bj_pingMinimapSound)
    endif
endfunction
function PingMinimapForForceEx takes force whichForce, real x, real y, real duration, integer style, real red, real green, real blue returns nothing
    local integer red255   = PercentTo255(red)
    local integer green255 = PercentTo255(green)
    local integer blue255  = PercentTo255(blue)

    if (IsPlayerInForce(GetLocalPlayer(), whichForce)) then
        // Use only local code (no net traffic) within this block to avoid desyncs.

        // Prevent 100% red simple and flashy pings, as they become "attack" pings.
        if (red255 == 255) and (green255 == 0) and (blue255 == 0) then
            set red255 = 254
        endif

        if (style == bj_MINIMAPPINGSTYLE_SIMPLE) then
            call PingMinimapEx(x, y, duration, red255, green255, blue255, false)
        elseif (style == bj_MINIMAPPINGSTYLE_FLASHY) then
            call PingMinimapEx(x, y, duration, red255, green255, blue255, true)
        elseif (style == bj_MINIMAPPINGSTYLE_ATTACK) then
            call PingMinimapEx(x, y, duration, 255, 0, 0, false)
        else
            // Unrecognized ping style - ignore the request.
        endif
        
        //call StartSound(bj_pingMinimapSound)
    endif
endfunction
function PingMinimapForPlayer takes player whichPlayer, real x, real y, real duration returns nothing
    if (GetLocalPlayer() == whichPlayer) then
        // Use only local code (no net traffic) within this block to avoid desyncs.
        call PingMinimap(x, y, duration)
        //call StartSound(bj_pingMinimapSound)
    endif
endfunction

как отдельно какой-нибудь спрайт отключить, я не знаю. но вот поэтому и предложил заменить модель спрайта на пустышку. тут надо глубже копнуть в тему ИИ, чтобы понимать. мб есть какое то решение.
Загруженные файлы
27

» Программирование / TimerSystem

можно еще получить тек время от момента начала игры?
27

» Программирование / TimerSystem

есть ли какое то преимущество по сравнению с обычным игровым таймером?

как узнать какой таймер истек? и надо ли его чистить?

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

» WarCraft 3 / Отметка на мини-карте от ИИ

это Miniping. Пингует на миникарте. Нужно посмотреть в API какие нативки есть для этого. Можно заменить попробовать текстуру.

если не хватает чего то. можно вызвать собственно через фрейм. хотя мне помнится есть api для создания изображения
27

» WarCraft 3 / Проблема с тайлсетами

slk - это таблицы, открываются в Excel и др похожими табличными редакторами. Это больше по импорту, если хочется добавить как новый тайл.
Весь архив карты, вернее все данные архива разбиты на такие табличные slk. В одном slk лежит информация о юнита, в другом slk о абилках, в третьем о итемах итд.
В архиве игры лежат дефолтная информация обо всем. А в архиве карты лежат дефолтная инфа с внесенными изменениями.
Надо найти таблицу slk для тайлов в архиве игры, извлечь и немного внести изменения, добавив равкод, свой новый тайл. В нее внести путь картинки, и заменить ею. А потом попробовать вызвать тайл. Триггером можно создавать тайл. Но точно не смогу сказать, что будет работать. В редакторе рельефа это точно. Возможно проще заменить импортной текстурой
Другой путь это через уберпласты и здания.
27

» WarCraft 3 / Проблема с тайлсетами

попробуй slk и через триггеры

или какой нибудь нестандартный редактор рельефа
27

» WarCraft 3 / Исследование доступно только после смерти юнита

так откатить нельзя его. сам же пишешь. тут требование: после смерти юнита
27

» WarCraft 3 / Исследование доступно только после смерти юнита

Зачем так заморачиваться с юнитом, когда можно в требованиях указать улучшение, переименованное как нужно и ничего по сути не добавляющее? Потом при выполнении условия просто исследовать это улучшение для игрока. Всегда можно это условие вернуть обратно, заблокировав это исследование для игрока.
че то не помню такого в требованиях. помню, что требования только на наличие у игрока типа юнита на карте/наличия апгрейдов/уровня тира. делал я пример для классов итемов (воин мечи, магу посохи в магазине). это было динамично, не помню как делал проверки на выделение покупателя, но это работало.

выглядит как пиздеж какой то
27

» WarCraft 3 / Исследование доступно только после смерти юнита

помните, что некоторые исследования и здания доступны, если выполнены требования. а именно, что построены какие то здания. и ветка открывается. по факту, нужно, чтобы этот юнит находился на карте. Создаешь юнита на карте, и в требование выполнено. Если удалить или убить его, то требование опять не выполнено
При убийстве цели создаем даймика на карте, требование убирается.
27

» WarCraft 3 / Помоги найти карту детства

такую сложно будет найти. очень много похожих карт с подобными механиками. Строишь бараки, и воины сами спавнятся и идут драться. Честно, не помню. То ли Paladin Td. И судя по всему она оч старая. Можно похожие поискать.

нужно больше информации. в чем особенность ее
27

» WarCraft 3 / Неприменимость способности к определённому юниту

или накинуть фрейм-маску, при нажатии которой будут идти по фрейму. Есть еще нативка, определяющая на кого мышь сфокусирована. Можно попробовать, но лично не пробовал.
27

» WarCraft 3 / Рамки для фреймов из Steam

Bergi, png уже может анимировать? че то у вас анимированная картинка
27

» WarCraft 3 / Рамки для фреймов из Steam

а больше 100 кадров (1 сек) нельзя? знаю, что в рекомендации для спрайтов носит рекомендация брать в 1 сек