1
13
3 года назад
1

» WarCraft 3 / Нативка SetUnitTimeScale

Хм, всегда думал она именно так и работает... Правда насколько понимаю это коэффициент от текущего значения, то есть
SetUnitTimeScale(u, 5)
SetUnitTimeScale(u, 5)
увеличение скорости в 25 раз
0
13
3 года назад
Отредактирован Nelloy
0

» WarCraft 3 / Запуск .exe из архива карты

map_maiker, склоны = "искривление" + модель склона. Для летающих делаешь триггер корректирующий высоту полета. Воду из катомных моделей собирать надо будет.
0
13
3 года назад
0

» WarCraft 3 / Lua: как вызвать без аргументов функцию?

Bergi_Bear, не вдавался в подробности, если честно
0
13
3 года назад
Отредактирован Nelloy
0

» WarCraft 3 / Lua: как вызвать без аргументов функцию?

МрачныйВорон, дебаггер от берги работает только для триггеров и таймеров.
local realTimerStart = TimerStart
TimerStart = function(timer, duration, repeating, callback)
	local pcallback = function()
		if callback == nil then return end
		local status, err = pcall(callback)
		if not status then
			print(err)
		end
	end
	realTimerStart(timer, duration, repeating, pcallback)
end
Есть функция pcall, которой берги и пользуется. www.lua.org/pil/8.4.html Она позволяет вызвать какую-то функцию таким образом, что можно отследить ошибку внутри функции без прерывания потока, потом можно ее вывести например через print. Таким же образом можно ее использовать например в инициализации модуля. Кривоватенько, но чтобы передать основную идею:
math.lua
function init()
	local math = {}
	function math.add(a, b)
		return a + b
	end
	return math + 1
end

local success, result = pcall(init)
if (success) then
	return result
else
	print(err)
end
В этом случае будет выведена ошибка связанная со строкой "return math + 1", так как нельзя складывать таблицу и число. При этом выполнение потока не прервется.
0
13
3 года назад
0

» WarCraft 3 / Lua: как вызвать без аргументов функцию?

МрачныйВорон, если используешь сторонний редактор кода, лучше весь код использовать внутри pcall или xpcall. Тогда все эти "обрывы" можно будет выводить с текстом ошибки.
2
13
3 года назад
Отредактирован Nelloy
2

» WarCraft 3 / Реген хп на джассе

МрачныйВорон, 'uhpr' - id этого филда (u - unit h - health p - points r - regeneration). Они в архиве игры где-то перечислены, уже не помню где.
ConvertUnitRealField(FourCC('uhpr')) == UNIT_RF_HIT_POINTS_REGENERATION_RATE
0
13
3 года назад
0

» WarCraft 3 / Реген хп на джассе

МрачныйВорон, далеко не все работают. Надо проверять каждое отдельно.
0
13
3 года назад
0

» WarCraft 3 / Реген хп на джассе

Bergi_Bear, да, очепятка
0
13
3 года назад
0

» WarCraft 3 / Реген хп на джассе

А что не так с BlzSetUnitWeaponRealField(u, UNIT_RF_HIT_POINTS_REGENERATION_RATE, val) в рефордже?
0
13
3 года назад
0

» WarCraft 3 / Ошибка в скрипте (Lua)

Компилятор же явно указал на место где ошибка... После OnMouseClick не хватает скобок

Bergi_Bear, действительно
0
13
3 года назад
Отредактирован Nelloy
0

» WarCraft 3 / Отслеживание мышки

МрачныйВорон, абсолютно не тестировал, но примерно так
Screen.lua
local Screen = {}

Screen.pos = {0, 0}
Screen.size = {0.8, 0.6}

local pixel_w = 0
local pixel_h = 0

local function update()
    local cur_pixel_width = BlzGetLocalClientWidth()
    local cur_pixel_height = BlzGetLocalClientHeight()

    if (cur_pixel_width == pixel_w and cur_pixel_height == pixel_h) then
        return
    end

    pixel_w = cur_pixel_width
    pixel_h = cur_pixel_height

    local default_zone_width = cur_pixel_height * 0.8 / 0.6
    Screen.size[0] = 0.8 * cur_pixel_width / default_zone_width
    Screen.pos[0] = - (Screen.__size.x - 0.8) / 2
end

local timer = CreateTimer()
TimerStart(timer, 1, true, update)
update()

return Screen
Grid
local Grid = {}

local COLS = 7
local ROWS = 7

local __pos = {0, 0}
local __size = {0, 0}
local btns = {}
local tools = {}

local parent = BlzGetFrameByName("ConsoleUIBackdrop", 0)

for x = 1, COLS do
    btns[x] = {}
    tools[x] = {}
    for y = 1, ROWS do
        btns[x][y] = BlzCreateFrameByType("GLUETEXTBUTTON", "MyButton", parent, "ScriptDialogButton", 0)
        BlzFrameSetAlpha(btns[x][y], 25)
        BlzFrameSetAbsPoint(btns[x][y], FRAMEPOINT_BOTTOMLEFT, 0, 0)
        BlzFrameSetSize(btns[x][y], 0, 0)

        tools[x][y] = BlzCreateFrameByType("FRAME", "FaceFrame", parent, "", 0)
        BlzFrameSetAlpha(tools[x][y], 0)
        BlzFrameSetAbsPoint(tools[x][y], FRAMEPOINT_BOTTOMLEFT, 0, 0)
        BlzFrameSetSize(tools[x][y], 0, 0)

        BlzFrameSetTooltip(btns[x][y], tools[x][y])
    end
end

local function __updateGrid()
    local w = __size[0] / COLS
    local h = __size[1] / ROWS

    for x = 1, COLS do
        for y = 1, ROWS do
            BlzFrameSetAbsPoint(btns[x][y], FRAMEPOINT_BOTTOMLEFT, __pos[0] + x * w, __pos[1] + y * h)
        end
    end
end

function Grid.setPos(pos)
    __pos = pos
    __updateGrid()
end

function Grid.setSize(size)
    __size = size
    __updateGrid()
end

-- return true, x, y, w, h
-- return false
function Grid.mouseROI()
    local w = __size[0] / COLS
    local h = __size[1] / ROWS

    for x = 1, COLS do
        for y = 1, ROWS do
            local found = BlzFrameIsVisible(tools[x][y])
            if (found) then
                return true, __pos[0] + x * w, __pos[1] + y * h, w, h
            end
        end
    end

    return false
end

return Grid
Detector
local Screen = require('Screen')
local Grid = require('Grid')

local Detector = {}

local timer = CreateTimer()

local ROI = 3
local PREC = 0.01

Detector.x = 0
Detector.y = 0
Detector.w = 0
Detector.h = 0

local function __getBetterPos()
    local t = CreateTimer()
    TimerStart(t, 0.025, false, function()
        DestroyTimer(t)

        local found, x, y, w, h = Grid.mouseROI()
        Detector.x = x
        Detector.y = y
        Detector.w = w
        Detector.h = h
        if (not found) then
            return
        end

        if (w > PREC or h > PREC) then
            __getBetterPos()
        end

        Grid.setPos({x - w * (ROI - 1) / 2, y - h * (ROI - 1) / 2})
        Grid.setSize({w * ROI, h * ROI})
    end)
end

local timer = CreateTimer()
TimerStart(t, 0.5, true, function()
    Detector.x = Screen.pos[0]
    Detector.y = Screen.pos[1]
    Detector.w = Screen.size[0]
    Detector.h = Screen.size[1]
    __getBetterPos()
end)

return Detector
1
13
3 года назад
Отредактирован Nelloy
1

» WarCraft 3 / Отслеживание мышки

Сделал свою реализацию, правда на TypeScript и своих либах, но думаю тут главное уловить суть. Несмотря на код, у всех фреймов реальный предок - BlzGetFrameByName("ConsoleUIBackdrop", 0). В видео мерцание, вызвано неполной прозрачность фреймов, для демонстрации. Координаты обновляются примерно каждые 0.2сек. Используется 64 фрейма.
Основная идея была сделать сетку из GlueTextButton (в коде сетка 8х8), в сетке с помощью определения видимости Tooltip определяется ячейка, содержащая курсор. Как оказалось работает гораздо быстрее ивента FRAMEEVENT_MOUSE_ENTER (раз в 10).
Сначала сетка строится на весь экран, определяется ячейка с курсором. Вокруг этой ячейки выделяется регион интереса (3х3) и сетка перестраивается в этом регионе. Процедура повторяется пока точность не достигнет заданной или пока сетка не потеряет курсор. Стоит добавить выходные фильтры.
Работает в том числе вне 8:6
Видео
Grid.ts
import * as Frame from '../../FrameExt'
import { Color, Vec2 } from '../../Utils'

const COLOR = new Color(0, 0, 0, 0.1)

export class MouseDetectGrid extends Frame.SimpleEmpty {
    constructor(cols: number, rows: number){
        super()
        
        this.__grid_btn = []
        this.__grid_tool = []
        for (let x = 0; x < cols; x++){
            this.__grid_btn.push([])
            this.__grid_tool.push([])
            for (let y = 0; y < rows; y++){
                let btn = new Frame.GlueTextButton()
                this.__grid_btn[x].push(btn)
                btn.parent = this
                btn.color = COLOR

                let tool = new Frame.Backdrop()
                this.__grid_tool[x].push(tool)
                tool.visible = false
                tool.color = new Color(0, 0, 0, 0)
                BlzFrameSetTooltip(btn.handle, tool.handle)
            }
        }
    }

    getMousePos(){
        for (let x = 0; x < this.__grid_btn.length; x++){
            for (let y = 0; y < this.__grid_btn[x].length; y++){
                let tool = this.__grid_tool[x][y]
                if (tool.visible){
                    let btn = this.__grid_btn[x][y]
                    return $multi(true, this.pos.add(btn.pos), btn.size)
                }
            }
        }
        return $multi(false, this.pos, this.size)
    }

    protected _set_size(size: Vec2){
        super._set_size(size)

        let btn_size = new Vec2(size.x / this.__grid_btn.length,
                                size.y / this.__grid_btn[0].length)
        for (let x = 0; x < this.__grid_btn.length; x++){
            for (let y = 0; y < this.__grid_btn[x].length; y++){
                this.__grid_btn[x][y].size = btn_size
                this.__grid_btn[x][y].pos = new Vec2(x * btn_size.x, y * btn_size.y)
            }
        }

    }

    private __grid_btn: Frame.GlueTextButton[][]
    private __grid_tool: Frame.Backdrop[][]
}
MouseDetector.ts
import * as Frame from '../../FrameExt'
import { hTimer } from '../../Handle'
import { Vec2 } from '../../Utils'

import { MouseDetectGrid } from './Grid'

const STEP_TIME = 0.025
const GRID_SIZE = 8
const ROI_SIZE = 3

export class MouseDetector {
    constructor(){
        this.precision = 0.01
        this.__pos = Frame.Screen.pos
        this.__size = Frame.Screen.size

        this.__grid = new MouseDetectGrid(GRID_SIZE, GRID_SIZE)

        let t = new hTimer()
        t.addAction(() => {
            this.__pos = Frame.Screen.pos
            this.__size = Frame.Screen.size
            this.__grid.pos = this.__pos
            this.__grid.size = this.__size
            this.__getBetterPos()
        })

        let period = STEP_TIME
        let tmp = this.precision
        while (tmp < Frame.Screen.size.x){
            tmp *= GRID_SIZE / ROI_SIZE
            period += STEP_TIME
        }

        t.start(period, true)
    }

    getMouse(){
        return this.__pos
    }

    private __getBetterPos(){
        let t = new hTimer()
        t.addAction(() => {
            t.destroy()
            let found: boolean
            [found, this.__pos, this.__size] = this.__grid.getMousePos()

            if (!found){
                return
            }

            this.__grid.pos = this.__pos.sub(this.__size.mult((ROI_SIZE - 1) / 2))
            this.__grid.size = this.__size.mult(ROI_SIZE)

            print(this.__pos.toString(), this.__size.toString())

            if (this.__size.x > this.precision || this.__size.y > this.precision){
                this.__getBetterPos()
            }
        })
        t.start(STEP_TIME, false)
    }

    precision: number

    private __pos: Vec2
    private __size: Vec2

    private __grid: MouseDetectGrid
}
Загруженные файлы
0
13
3 года назад
Отредактирован Nelloy
0

» WarCraft 3 / Отслеживание мышки

Bergi_Bear, странно, у меня все нормально с GlueTextButton FRAMEEVENT_MOUSE_ENTER / LEAVE / CONTROL_CLICK
0
13
3 года назад
Отредактирован Nelloy
0

» WarCraft 3 / Отслеживание мышки

МрачныйВорон, BlzGetFrameByName("ConsoleUIBackdrop", 0) тот самый волшебный предок. Позволяет своим наследникам выходить за область 4:3
0
13
3 года назад
0

» WarCraft 3 / lua: ошибка

Bergi_Bear, да уж... Внимательность... Лучше Typescript
1
13
3 года назад
1

» WarCraft 3 / lua-дебаг система для варика существует? +двумерные массивы

МрачныйВорон,
цикл с предусловием, тело цикла выполняется до тех пор пока условие == true
например можно переделать обычных for в цикл while
local a = {}
for i = 1, 10 do
	a[i] = i
end

-- Равнозначно
local a = {}
local i = 1
while (i <= 10) do
	a[i] = i
	i = i + 1
end
1
13
3 года назад
Отредактирован Nelloy
1

» WarCraft 3 / lua-дебаг система для варика существует? +двумерные массивы

PT153, уверен, что под капотом множественный return всегда через таблицы?
Вроде все происходит без упаковки в таблицу в первом случае.
return a, b
return {a, b}

МрачныйВорон, Несколько значений по одному ключу? Можно, но либо упаковав их в таблицу (то есть на самом деле возвращает только 1 объект - таблицу), либо через метатаблицы, но это сложнее.
А для автоматического удаления неиспользуемых данных из таблиц нужно использовать метаметод __mode.
Много интересного и непонятного, по началу, по метатаблицам habr.com/ru/post/346892
1
13
3 года назад
Отредактирован Nelloy
1

» WarCraft 3 / lua-дебаг система для варика существует? +двумерные массивы

Или так:
function newArray(dim_count, dim_size)
	local arr = {}
	for i = 1, dim_size do
		if (dim_count > 1) then
			arr[i] = newArray(dim_count - 1, dim_size)
		end
	end
    return arr
end

local a = newArray(2, 10)

a[1][1] = 5     -- OK
a[1][1][1] = 5  -- Error
a[12][12] = 5  -- Error

print(a[1][1])      -- a[1][1] == 5
0
13
3 года назад
0

» WarCraft 3 / Режим графики игрока SD или HD?

makkad, спасибо, интересный способ надо будет попробовать
0
13
3 года назад
0

» WarCraft 3 / Вопрос по мемхаку.

Не пользовался мемхаком, но если там реализация похожа на 1.31+, то нет - нельзя. Но можно создать для всех и спрятать у всех игроков кроме нужного.
2
13
3 года назад
2

» WarCraft 3 / Пеоны разбойники

Bergi_Bear, преодолеть, согласен, не получится. Но была у меня мысль, что у каждого игрока есть невидимый юнит, скажем так, некоторая сущность для физики, определяющая хит-боксы. Именно они синхронизируются у игроков. При этом каждый локальный игрок не ждем пока эти сущности синхронизируются, а управляет своим effect, который для игрока локального выглядит как его персонаж и мгновенно реализует действия игрока. Затем физические сущности синхронизируют эти действия. Задержку не изменит, но уменьшит чувство заторможенности персонажа. Сдается мне что-то подобное работает в близзов в Overwatch. Ведь обмен данными с сервером там достаточно редкий, сейчас кажется 60 тиков/сек, а до этого было вроде 30.
0
13
3 года назад
0

» WarCraft 3 / Пеоны разбойники

Bergi_Bear, попробовал разок, некоторый дискомфорт вызывает задержка. Не думал на системой компенсации лага на эффектах?
0
13
3 года назад
0

» WarCraft 3 / CreateImage артефакты

Неоптимальное, но быстрое решение для нарезки атласов с тайлами:
from PIL import Image
from wand import image
import os

IN_W = 256
IN_H = 256
OUT_W = 128
OUT_H = 128

dir = './HD/Ruins/dirt/'
atlas = Image.open(dir + 'ruins_dirt_diffuse.dds')
print(dir)

max_x = int(atlas.size[0] / IN_W)
max_y = int(atlas.size[1] / IN_H)

for x in range(max_x):
    for y in range(max_y):
        croped = atlas.crop((x * IN_W, y * IN_H, (x + 1) * IN_W, (y + 1) * IN_H))
        croped_back = croped.resize((OUT_W - 2, OUT_H - 2))
        croped_back.putalpha(1)

        im = Image.new('RGBA', (OUT_W, OUT_H), 0)
        im.paste(croped_back, (1, 1))
        im.paste(croped.resize((int(OUT_W / 2), int(OUT_H / 2))), (int(OUT_W / 4), int(OUT_H / 4)))
        path = dir + '%02dx%02d.tga' % (x, y)
        im.save(path)

        dds = image.Image(filename=path)
        dds.compression = 'dxt5'
        dds.save(filename=dir + '%02dx%02d.dds' % (x, y))

        os.remove(path)
2
13
3 года назад
2

» WarCraft 3 / CreateImage артефакты

PT153, суть в том что с этой рамкой творится какая-то дичь
Bergi_Bear, сохранил в формате paint.net, с сохранением слоев и в dds
Загруженные файлы
2
13
3 года назад
2

» WarCraft 3 / CreateImage артефакты

Bergi_Bear, нашел способ на 99% избавиться от проблемы. Для изображения 64х64 делаю новую картинку с 2 слоями. Фоновый цвет удаляю. В одном слое ставлю по центру нужное изображение, в другом слое то же самое изображение только увеличиваю до 126х126 и 1 альфа канала.
Загруженные файлы