Алгоритмы, Наработки и Способности
Способ реализации:
Jass
Тип:
Алгоритм
Версия Warcraft:
1.26a - 1.27a, не тестировалось на более ранних версиях.
Собственно небольшая библиотека требующая немного модифицированный мемхак второй версии (прилагается в тест карте), ну и немного терпения, которая добавить возможность проверять тип урона, атаки, типа атаки, флагов атаки, начального урона без резистов во всех триггерах вашей карты срабатывающих на событие EVENT_UNIT_DAMAGED.
Так же в этой версии включена система восстановления памяти при выходе из игры, фаталить не будет.
А так же добавлена система отображения зарядов на иконке.
Код библиотеки
include "cj_types_priv.j"

library MHDamage /*initializer init*/ requires Memory, Utils

define
{
    PAGE_EXECUTE           = 0x10
    PAGE_EXECUTE_READ      = 0x20
    PAGE_EXECUTE_READWRITE = 0x40
    PAGE_EXECUTE_WRITECOPY = 0x80
    PAGE_NOACCESS          = 0x01
    PAGE_READONLY          = 0x02
    PAGE_READWRITE         = 0x04
    PAGE_WRITECOPY         = 0x08
    PAGE_TARGETS_INVALID   = 0x40000000
    PAGE_TARGETS_NO_UPDATE = 0x40000000
    PAGE_GUARD             = 0x100
    PAGE_NOCACHE           = 0x200
    PAGE_WRITECOMBINE      = 0x400
}

define pointer = int
define sizeof_pointer_ = $04
define NULL = 0

define 
{
    KB = 1024
    MB = KB * 1024
}

// Максимальное количество одновременных событий урона.
private constant int MAX_DAMAGE_STACK_SIZE = 1024

private pointer pDamageStack = NULL
private pointer pDamageHook = NULL

pointer GetDamageEventData()
{
	int Length = RMem(pDamageStack)
	
	if (Length > 0)
	{
		return RMem(pDamageStack + $04 + sizeof_pointer_ * (Length - 1))
	}
	
	return NULL
}

public void init()
{
    pDamageStack = malloc($04 + $04 * MAX_DAMAGE_STACK_SIZE)
    pDamageHook = AllocateExecutableMemory(1 * KB)
    
    // hook
    
    pointer CUnit_VMT = GameDLL + $931934
    pointer pSlot72 = CUnit_VMT + (sizeof_pointer_ * 72)
    
    int OldProtection = ChangeOffsetProtection(pSlot72, 4, PAGE_READWRITE)
    
    pointer PreviousMethod = RMem(pSlot72)
    WMem(pSlot72, pDamageHook)
    
    ChangeOffsetProtection(pSlot72, 4, OldProtection)
    
    // init code
    
    //WMem(pDamageHook + $00, $8DE58955)
    //WMem(pDamageHook + $04, $53F82464)
    //WMem(pDamageHook + $08, $B8F84D89)
    //WMem(pDamageHook + $0C, pDamageStack)
    //WMem(pDamageHook + $10, $89044D8D)
    //WMem(pDamageHook + $14, $89138BC3)
    //WMem(pDamageHook + $18, $8304904C)
    //WMem(pDamageHook + $1C, $4D8B0103)
    //WMem(pDamageHook + $20, $1475FFF8)
    //WMem(pDamageHook + $24, $8B1075FF)
    //WMem(pDamageHook + $28, $8B500C45)
    //WMem(pDamageHook + $2C, $B8500845)
    //WMem(pDamageHook + $30, PreviousMethod)
    //WMem(pDamageHook + $34, $4589D0FF)
    //WMem(pDamageHook + $38, $012B83FC)
    //WMem(pDamageHook + $3C, $5BFC458B)
    //WMem(pDamageHook + $40, $0010C2C9)
    
    WMem(pDamageHook + $00, $8DE58955)
    WMem(pDamageHook + $04, $53E82464)
    WMem(pDamageHook + $08, $B8F84D89)
    WMem(pDamageHook + $0C, pDamageStack)
    WMem(pDamageHook + $10, $890C558B)
    WMem(pDamageHook + $14, $558BE855)
    WMem(pDamageHook + $18, $10528B0C)
    WMem(pDamageHook + $1C, $8BEC5589)
    WMem(pDamageHook + $20, $55891055)
    WMem(pDamageHook + $24, $14558BF0)
    WMem(pDamageHook + $28, $8DF45589)
    WMem(pDamageHook + $2C, $C389E84D)
    WMem(pDamageHook + $30, $4C89138B)
    WMem(pDamageHook + $34, $03830490)
    WMem(pDamageHook + $38, $4D8B9001)
    WMem(pDamageHook + $3C, $1475FFF8)
    WMem(pDamageHook + $40, $8B1075FF)
    WMem(pDamageHook + $44, $8B500C45)
    WMem(pDamageHook + $48, $B8500845)
    WMem(pDamageHook + $4C, PreviousMethod)
    WMem(pDamageHook + $50, $4589D0FF)
    WMem(pDamageHook + $54, $012B83FC)
    WMem(pDamageHook + $58, $5BFC458B)
    WMem(pDamageHook + $5C, $0010C2C9)
}

endlibrary
Как видим библиотака с несколькими функциями, после её запуска можно будет делать так:
function Trig_Damage_Test_Conditions takes nothing returns boolean
    return GetEventDamage() > 0.00
endfunction

function Trig_Damage_Test_Actions takes nothing returns nothing
    local integer EventData = GetDamageEventESPData()
    local integer Data = RMem(EventData + $00)
    local real InitialAmount = mI2R( RMem(EventData + $04) )
    local integer UnkBool = RMem(EventData + $08)
    local integer Flags = RMem(Data + 0x0C ) 
    local real Amount = mI2R( RMem(Data + $10) )
    local integer WeaponType = RMem(Data + $04)
    local integer DamageType = RMem(Data + $14)
    local integer AttackType = RMem(Data + $20)
    
    call BJDebugMsg("*** Damage info ***")
    call BJDebugMsg("Target: " + GetUnitName(GetTriggerUnit()))
    call BJDebugMsg("Source: " + GetUnitName(GetEventDamageSource()))
    call BJDebugMsg("Amount: " + R2S(Amount))
    call BJDebugMsg("Initial Amount: " + R2S(InitialAmount))
    call BJDebugMsg("Weapon Type: " + I2S(WeaponType))
    call BJDebugMsg("Damage Type: " + I2S(DamageType))
    call BJDebugMsg("Attack Type: " + I2S(AttackType))
    call BJDebugMsg("Flags - " + I2S(Flags) )
    call BJDebugMsg("Bool - " + I2S(UnkBool)  )
    
    if IsFlagBitSet(Flags, 0x100) then
        call BJDebugMsg("урон от атаки ближнего боя")
    endif
endfunction

//===========================================================================
function InitTrig_Damage_Test takes nothing returns nothing
    set gg_trg_Damage_Test = CreateTrigger(  )
    call TriggerAddCondition( gg_trg_Damage_Test, Condition( function Trig_Damage_Test_Conditions ) )
    call TriggerAddAction( gg_trg_Damage_Test, function Trig_Damage_Test_Actions )
endfunction
Рассмотрим по подробнее:
    local integer ESP = GetDamageEventESPData()
    local integer Data = RMem(ESP + $08) // second argument
Это получения структуры в которой хранятся все данные об уроне на это событие урона.
 local real Amount = mI2R( RMem(Data + $10) )
Урон без учета резиста, все просто...
local integer WeaponType = RMem(Data + $04)
Это тип оружия, это вот тут используется:
native UnitDamageTarget takes unit whichUnit, widget target, real amount, boolean attack, boolean ranged, attacktype attackType, damagetype damageType, !!weapontype weaponType!! returns boolean 
Вот их столько:
Обратите внимание, weapontype в данном случаи получается в виде целочисленной переменной, их соотсветсвие можно глянуть в common.j или использовать ConverWeaponType
Идем далее:
local integer DamageType = RMem(Data + $14)
В данном случаи тип урона тоже представлен в виде целочисленной переменной, для преобразование в хендл damagetype модно юзать данный код:
D2DT
function DT2DT takes integer k returns integer
    local integer i = 1
    if k == 0 then
        return 0
    endif
    loop
        exitwhen k / 2 <= 1
        set i = i + 1
        set k = k / 2
    endloop
    return i
endfunction

	//пример использования:
	ConvertDamageType(DT2DT(dmgTypeHex))==DAMAGE_TYPE_FIRE
local integer AttackType = RMem(Data + $20)
Это тип атаки юнита, причем тоже не хендл а целое чило, но тут все просто:
7 видов атаки, от 0 до 6, числовые значения можно превратить в хендлы с помощью нативки:
	constant native ConvertAttackType takes integer i returns attacktype
Ну и наконец флаги атаки:
 local integer Flags = RMem( Data + 0x0C )
Это целое число, а точнее сразу несколько слепленных в кучу, где каждое является флагом который что то означает, если Flags == 0x100 то это урон от атаки ближнего боя, 0х101 урон от атаки дальнего боя, многие способности ставят свои флаги на атаку, к примеру Стремительность ('AOwk' - windwalk ) - ставит флаг 0x500.
Ссылка на тестмап тут

Отображение зарядов

Вы когда-нибудь видели способности 'Afla' (Осветительная ракета) и 'Asen' (Сторожевая сова)? Вспомните эти красивые циферки с кол-вом зарядов на иконке, но увы таких способностей всего 2 на весь варкравт, но спс DracoL1ch, теперь мы можем рисовать заряды на иконке практически любой способности, в тестовой карте у мастера клинка при изучении способности "Стремительность" на иконке видны заряды, равные уровню способности, они конечно не тратятся сами как у "Ракет" и "Сов" но с помощью кода мы можем задавать способности любое кол-во зарядов а так же включать и отключать отображение зарядов на иконке.
Функционал довольно прост:
    function InitChargesHook takes unit u, integer id returns nothing // вешает хук на отображение зарядов для указанной способности.
    function InitCharges takes unit u, integer id returns nothing //активирует отображение зарядов на этом id на этом юните
    function RemoveCharges takes unit u, integer id returns nothing  //отключает отображение зярядов
    function SetCharges takes unit u, integer id, integer charges returns nothing //записывает юниту в абилку кол-во зарядов
    function GetCharges takes unit u, integer id returns integer //показывает  кол - во зарядов
Есть вопросы? Задавайте.
В карте примере код на vjass

Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
2
23
6 лет назад
2
если клон бьет то фаталит =)
5
16
6 лет назад
5
без восстановления памяти вы угробите кучу карт
2
32
6 лет назад
2
DracoL1ch, приложено, кстати надо будет описать.
Твоя старая восстанавливалка.
pro100master, лог фатала в студию, у меня ниче не фаталит, ни когда бьют иллюзии ни когда иллюзии бьют. Все работает исправно.
2
23
6 лет назад
2
0
10
6 лет назад
0
Не могу сохранить наработку, т.к. выдает ошибку
В чем причина? парсер и оптимайзер выключил. pjass скачал отсюда: xgm.guru/p/wc3/memoryhack
Загруженные файлы
0
20
6 лет назад
Отредактирован Diaboliko
0
у автора предыдущего поста сжасс сжирает комменты с инструкциями для парсера.
Перед блоком с //# +nosemanticerror надо вставить //! nocjass . После блока //! nocjassend или endnocjass , не помню
*вроде как
Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.