Добавлен quq_CCCP,
опубликован
Алгоритмы, Наработки и Способности
Способ реализации:
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
В карте примере код на vjass
Чтобы оставить комментарий, пожалуйста, войдите на сайт.
Твоя старая восстанавливалка.
pro100master, лог фатала в студию, у меня ниче не фаталит, ни когда бьют иллюзии ни когда иллюзии бьют. Все работает исправно.
Отредактирован Diaboliko
Перед блоком с //# +nosemanticerror надо вставить //! nocjass . После блока //! nocjassend или endnocjass , не помню
*вроде как