в рефордже все делается итак без этого)) в режим папки переводишь, и все.
Тут есть утилиты, правда я ни разу не пользовался)) например, для кампании. подожди, пока снизу кто-нибудь шарящий ответит
Не, саму кнопку норм видно. Я имею ввиду эффект нажатия. Прям не совсем отчётливо это видно. Я просто как раз подумал заменить кнопку в карте, но нет. Пока не то, что нужно☺
можно из кампании спиздить, не помню было ли. подъемники там были
в идеале надо сильно деформацию вниз. чтобы видно было.
вот для рефорджа карта и скрипт пример заростания почвы
скрипт
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
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
как отдельно какой-нибудь спрайт отключить, я не знаю. но вот поэтому и предложил заменить модель спрайта на пустышку. тут надо глубже копнуть в тему ИИ, чтобы понимать. мб есть какое то решение.
есть ли какое то преимущество по сравнению с обычным игровым таймером?
как узнать какой таймер истек? и надо ли его чистить?
будут ли записи: тек время, сколько прошло (пройденное), сколько осталось? я помню че то такое делал. только там от начала игры запускал таймер. И из него вынимал данные.
slk - это таблицы, открываются в Excel и др похожими табличными редакторами. Это больше по импорту, если хочется добавить как новый тайл.
Весь архив карты, вернее все данные архива разбиты на такие табличные slk. В одном slk лежит информация о юнита, в другом slk о абилках, в третьем о итемах итд.
В архиве игры лежат дефолтная информация обо всем. А в архиве карты лежат дефолтная инфа с внесенными изменениями.
Надо найти таблицу slk для тайлов в архиве игры, извлечь и немного внести изменения, добавив равкод, свой новый тайл. В нее внести путь картинки, и заменить ею. А потом попробовать вызвать тайл. Триггером можно создавать тайл. Но точно не смогу сказать, что будет работать. В редакторе рельефа это точно. Возможно проще заменить импортной текстурой
Зачем так заморачиваться с юнитом, когда можно в требованиях указать улучшение, переименованное как нужно и ничего по сути не добавляющее? Потом при выполнении условия просто исследовать это улучшение для игрока. Всегда можно это условие вернуть обратно, заблокировав это исследование для игрока.
че то не помню такого в требованиях. помню, что требования только на наличие у игрока типа юнита на карте/наличия апгрейдов/уровня тира. делал я пример для классов итемов (воин мечи, магу посохи в магазине). это было динамично, не помню как делал проверки на выделение покупателя, но это работало.
помните, что некоторые исследования и здания доступны, если выполнены требования. а именно, что построены какие то здания. и ветка открывается. по факту, нужно, чтобы этот юнит находился на карте. Создаешь юнита на карте, и в требование выполнено. Если удалить или убить его, то требование опять не выполнено
При убийстве цели создаем даймика на карте, требование убирается.
такую сложно будет найти. очень много похожих карт с подобными механиками. Строишь бараки, и воины сами спавнятся и идут драться. Честно, не помню. То ли Paladin Td. И судя по всему она оч старая. Можно похожие поискать.
или накинуть фрейм-маску, при нажатии которой будут идти по фрейму. Есть еще нативка, определяющая на кого мышь сфокусирована. Можно попробовать, но лично не пробовал.
Ред. MpW
» WarCraft 3 / Как на 1.26 отследить вход раба в логово, чтоб сделать действие
https://www.xgm.guru/p/100/179866
выход можно отследить через событие "получил приказ". При выходе юнит получает приказ "stop".
Ред. MpW
» WarCraft 3 / Перенос импорта с сохранением путей.
Тут есть утилиты, правда я ни разу не пользовался)) например, для кампании. подожди, пока снизу кто-нибудь шарящий ответит
» WarCraft 3 / Проблема с тайлсетами
архив/TerrainArt/Terrain.slk
» WarCraft 3 / Скачать триггер из Дота 2
Ред. MpW
» WarCraft 3 / Скачать триггер из Дота 2
Ред. MpW
» WarCraft 3 / Кнопки Меню, Общение, Союзники при помощи мемхака
» WarCraft 3 / Вычислительная геометрия часть 2
Ред. MpW
» WarCraft 3 / Заростание почвы
Ред. MpW
» Программирование / TimerSystem
Ред. MpW
» WarCraft 3 / Отметка на мини-карте от ИИ
Ред. MpW
» Программирование / TimerSystem
Ред. MpW
» Программирование / TimerSystem
» Программирование / TimerSystem
» WarCraft 3 / Отметка на мини-карте от ИИ
Ред. MpW
» WarCraft 3 / Проблема с тайлсетами
» WarCraft 3 / Проблема с тайлсетами
Ред. MpW
» WarCraft 3 / Исследование доступно только после смерти юнита
» WarCraft 3 / Как заменить в верхнем правом углу иконки ресурсов?
Ред. MpW
» WarCraft 3 / Исследование доступно только после смерти юнита
» WarCraft 3 / Исследование доступно только после смерти юнита
» WarCraft 3 / Помоги найти карту детства
» WarCraft 3 / Неприменимость способности к определённому юниту
Ред. MpW
» WarCraft 3 / Рамки для фреймов из Steam
Ред. MpW
» WarCraft 3 / Рамки для фреймов из Steam
» WarCraft 3 / Рамки для фреймов из Steam