мне лень придумывать насколько это говнище, так что просто представьте что я максимум облил помоями этот говноресурс и сбросился
код
library ShieldSystemLib
globals
    private constant hashtable H = InitHashtable( )
    private constant timer TempTimer = CreateTimer( )
    private constant group TempGroup = CreateGroup( )
    private constant integer SHIELD_STATE_SHIELD = 0
    private constant integer SHIELD_STATE_TIME = 1
endglobals

private struct ShieldS
    real shield
    real time
    boolean permanent
endstruct

function GetUnitShieldCount takes unit u returns integer
    return LoadInteger( H, GetHandleId( u ), 0 )
endfunction

function UnitRemoveShield takes unit u, integer cell returns nothing
    local integer h = GetHandleId( u )
    local integer i = LoadInteger( H, h, 0 )
    local ShieldS A  = LoadInteger( H, GetHandleId( u ), cell )
    
    set A.shield = 0.00
    set A.time = 0.00
    call A.destroy( )
    
    if cell != i then
        call SaveInteger( H, h, cell, LoadInteger( H, h, i ) )
    endif
    
    call RemoveSavedInteger( H, h, i )
    call SaveInteger( H, h, 0, i - 1 )
endfunction

function UnitRemoveTotalShield takes unit u returns nothing
    local integer h = GetHandleId( u )
    local integer i = LoadInteger( H, h, 0 )
    
    loop
        exitwhen i <= 0
        
        call UnitRemoveShield( u, i )
        
        set i = i - 1
    endloop
endfunction

function GetUnitTotalShield takes unit u returns real
    local integer h = GetHandleId( u )
    local integer i = LoadInteger( H, h, 0 )
    local ShieldS A
    local real r = 0.00
    
    loop
        exitwhen i <= 0
        
        set A = LoadInteger( H, h, i )
        
        set r = r + A.shield
        
        set i = i - 1
    endloop
    
    return r
endfunction

function GetUnitShieldState takes unit u, integer shieldState, integer cell returns real
    local ShieldS A = LoadInteger( H, GetHandleId( u ), cell )
    
    if shieldState == SHIELD_STATE_SHIELD then
        return A.shield
    elseif shieldState == SHIELD_STATE_TIME then
        return A.time
    endif
    
    if A.permanent then
        return 1.00
    endif
    
    return 0.00
endfunction

function SetUnitShieldState takes unit u, integer shieldState, integer cell, real value returns nothing
    local ShieldS A = LoadInteger( H, GetHandleId( u ), cell )
    
    if shieldState > 0 and shieldState < 2 then
        if value <= 0.00 then
            call UnitRemoveShield( u, cell )
        else
            if shieldState == 0 then
                set A.shield = value
            else
                set A.time = value
            endif
        endif
    else
        if value <= 0.00 then
            set A.permanent = false
        else
            set A.permanent = true
        endif
    endif
endfunction

function BlockDamage takes unit u, real dmg returns nothing
    local integer h = GetHandleId( u )
    local integer i = LoadInteger( H, h, 0 )
    local ShieldS A
    local real r = 0.00
    
    loop
        exitwhen i <= 0
        
        set A = LoadInteger( H, h, i )
        
        if A.shield > dmg then
            set A.shield = A.shield - dmg
            set r = r + dmg
            exitwhen true
        else
            set dmg = dmg - A.shield
            set r = r + A.shield
            call UnitRemoveShield( u, i )
        endif
        
        set i = i - 1
    endloop
    
    call NegateDamage( u, r )
endfunction

private function CheckShieldTime_1 takes nothing returns nothing
    local unit u = GetEnumUnit( )
    local integer h = GetHandleId( u )
    local integer i = LoadInteger( H, h, 0 )
    local integer m = i
    local integer s = m
    local ShieldS A
    
    loop
        exitwhen i <= 0
        
        set A = LoadInteger( H, h, i )
        
        if not A.permanent then
            set A.time = A.time - 0.01
            
            if A.time <= 0.00 then
                set A.shield = 0.00
                set A.time = 0.00
                call A.destroy( )
                
                call SaveInteger( H, h, i, LoadInteger( H, h, m ) )
                call RemoveSavedInteger( H, h, m )
                
                set m = m - 1
            endif
        endif
        
        set i = i - 1
    endloop
    
    if s != m then
        if m <= 0 then
            call GroupRemoveUnit( TempGroup, u )
            call RemoveSavedInteger( H, h, 0 )
        else
            call SaveInteger( H, h, 0, m )
        endif
    endif
    
    set u = null
endfunction

private function CheckShieldTime takes nothing returns nothing
    call ForGroup( TempGroup, function CheckShieldTime_1 )
    
    if FirstOfGroup( TempGroup ) == null then
        call PauseTimer( TempTimer )
    endif
endfunction

function ShieldUnit takes unit u, real shield, real time returns nothing
    local integer i = GetHandleId( u )
    local integer h = LoadInteger( H, i, 0 ) + 1
    local ShieldS A = ShieldS.create( )
    
    call SaveInteger( H, i, 0, h )
    call SaveInteger( H, i, h, A )
    
    set A.shield = shield
    
    if time > 0.00 then
        set A.time = time
        set A.permanent = false
    else
        set A.permanent = true
    endif
    
    if FirstOfGroup( TempGroup ) == null then
        call TimerStart( TempTimer, 0.01, true, function CheckShieldTime )
    endif
    
    call GroupAddUnit( TempGroup, u )
endfunction
endlibrary

//===========================================================================
function InitTrig_ShieldSystem takes nothing returns nothing
    //set gg_trg_ShieldSystem = CreateTrigger(  )
endfunction

в коде менять особо нечего
карта с примером реализации такого щита

говноапи
  • function ShieldUnit takes unit u, real shield, real time returns nothing
вешает щит на юнита, первый аргумент юнит, второе хп щита, третье время щита, если время щита выставить меньше или равно 0.00, то щит будет перманентным (пока не уничтожить само собой)
  • function BlockDamage takes unit u, real dmg returns nothing
блочит урон щитом, первый аргумент юнит, второе кол-во блокируемого урона
  • function SetUnitShieldState takes unit u, integer shieldState, integer cell, real value returns nothing
устанавливает один из статов щита на выбранное значение, всего статов 3: хп, время, перманентность, считаются от 0 до 2
первый аргумент юнит, второй аргумент стат, третье ячейка щита, четвёртое значение, чтобы изменить перманентность нужно выбрать либо 0.00 (убрать) либо 1.00 (включить)
ячейки считаются от 1 до максимума (функция получения максимума ниже)
  • function GetUnitShieldState takes unit u, integer shieldState, integer cell returns real
получения значения одного из статов щита, выше всё расписано
  • function GetUnitTotalShield takes unit u returns real
получение полного объёма щитов на юните
  • function UnitRemoveTotalShield takes unit u returns nothing
удаление всех щитов с юнита
  • function UnitRemoveShield takes unit u, integer cell returns nothing
удаление конкретного щита с юнита, первый аргумент юнит, второе - ячейка
  • function GetUnitShieldCount takes unit u returns integer
получение максимального кол-ва наложенных щитов

17.09.2022
реверсивная версия функции BlockDamage (если кому не нравится, что дамажится последний наложенный щит, а не первый)
код
function BlockDamage takes unit u, real dmg returns nothing
    local integer h = GetHandleId( u )
    local integer i = LoadInteger( H, h, 0 )
    local integer i1 = 1
    local ShieldS A
    local real r = 0.00
    
    loop
        exitwhen i1 > i
        
        set A = LoadInteger( H, h, i1 )
        
        if A.shield > dmg then
            set A.shield = A.shield - dmg
            set r = r + dmg
            exitwhen true
        else
            set dmg = dmg - A.shield
            set r = r + A.shield
            call UnitRemoveShield( u, i1 )
        endif
        
        set i1 = i1 + 1
    endloop
    
    call NegateDamage( u, r )
endfunction

18.09.2022
короче то что выше для реверса это ерунда и работает только на первые 2 щита, так что вот обновлённая версия, пришлось все последующие щиты после удаляемого смещать на ступень ниже, ну и поправил немного основной код
код
library ShieldSystemLib
globals
    private constant hashtable H = InitHashtable( )
    private constant timer TempTimer = CreateTimer( )
    private constant group TempGroup = CreateGroup( )
    private constant integer SHIELD_STATE_SHIELD = 0
    private constant integer SHIELD_STATE_TIME = 1
endglobals

private struct ShieldS
    real shield
    real time
    boolean permanent
endstruct

function GetUnitShieldCount takes unit u returns integer
    return LoadInteger( H, GetHandleId( u ), 0 )
endfunction

function UnitRemoveShield takes unit u, integer cell returns nothing
    local integer h  = GetHandleId( u )
    local integer i  = LoadInteger( H, h, 0 )
    local integer i1 = cell
    local ShieldS A  = LoadInteger( H, GetHandleId( u ), cell )
    
    set A.shield = 0.00
    set A.time = 0.00
    call A.destroy( )
    
    if cell != i then
        loop
            call SaveInteger( H, h, i1, LoadInteger( H, h, i1 + 1 ) )
            
            set i1 = i1 + 1
            exitwhen i1 >= i
        endloop
    endif
	
    call RemoveSavedInteger( H, h, i )
    call SaveInteger( H, h, 0, i - 1 )
endfunction

function UnitRemoveTotalShield takes unit u returns nothing
    local integer h = GetHandleId( u )
    local integer i = LoadInteger( H, h, 0 )
    
    loop
        exitwhen i <= 0
        
        call UnitRemoveShield( u, i )
        
        set i = i - 1
    endloop
endfunction

function GetUnitTotalShield takes unit u returns real
    local integer h = GetHandleId( u )
    local integer i = LoadInteger( H, h, 0 )
    local ShieldS A
    local real r = 0.00
    
    loop
        exitwhen i <= 0
        
        set A = LoadInteger( H, h, i )
        
        set r = r + A.shield
        
        set i = i - 1
    endloop
    
    return r
endfunction

function GetUnitShieldState takes unit u, integer shieldState, integer cell returns real
    local ShieldS A = LoadInteger( H, GetHandleId( u ), cell )
    
    if shieldState == SHIELD_STATE_SHIELD then
        return A.shield
    elseif shieldState == SHIELD_STATE_TIME then
        return A.time
    endif
    
    if A.permanent then
        return 1.00
    endif
    
    return 0.00
endfunction

function SetUnitShieldState takes unit u, integer shieldState, integer cell, real value returns nothing
    local ShieldS A = LoadInteger( H, GetHandleId( u ), cell )
    
    if shieldState > 0 and shieldState < 2 then
        if value <= 0.00 then
            call UnitRemoveShield( u, cell )
        else
            if shieldState == 0 then
                set A.shield = value
            else
                set A.time = value
            endif
        endif
    else
        if value <= 0.00 then
            set A.permanent = false
        else
            set A.permanent = true
        endif
    endif
endfunction

function BlockDamage takes unit u, real dmg returns nothing
    local integer h = GetHandleId( u )
    local integer i = LoadInteger( H, h, 0 )
    local integer i1 = 1
    local ShieldS A
    local real r = 0.00
    
    loop
        exitwhen i1 > i
        
        set A = LoadInteger( H, h, i1 )
        
        if A.shield > dmg then
            set A.shield = A.shield - dmg
            set r = r + dmg
            exitwhen true
        else
            set dmg = dmg - A.shield
            set r = r + A.shield
            call UnitRemoveShield( u, i1 )
        endif
        
        set i1 = i1 + 1
    endloop
    
    call NegateDamage( u, r )
endfunction

private function CheckShieldTime_1 takes nothing returns nothing
    local unit u = GetEnumUnit( )
    local integer h = GetHandleId( u )
    local integer i = LoadInteger( H, h, 0 )
    local integer m = i
    local integer s = m
    local ShieldS A
    
    loop
        exitwhen i <= 0
        
        set A = LoadInteger( H, h, i )
        
        if not A.permanent then
            set A.time = A.time - 0.01
            
            if A.time <= 0.00 then
                call UnitRemoveShield( u, i )
                
                set m = m - 1
            endif
        endif
        
        set i = i - 1
    endloop
    
    if s != m then
        if m <= 0 then
            call GroupRemoveUnit( TempGroup, u )
            call RemoveSavedInteger( H, h, 0 )
        else
            call SaveInteger( H, h, 0, m )
        endif
    endif
    
    set u = null
endfunction

private function CheckShieldTime takes nothing returns nothing
    call ForGroup( TempGroup, function CheckShieldTime_1 )
    
    if FirstOfGroup( TempGroup ) == null then
        call PauseTimer( TempTimer )
    endif
endfunction

function ShieldUnit takes unit u, real shield, real time returns nothing
    local integer i = GetHandleId( u )
    local integer h = LoadInteger( H, i, 0 ) + 1
    local ShieldS A = ShieldS.create( )
    
    call SaveInteger( H, i, 0, h )
    call SaveInteger( H, i, h, A )
    
    set A.shield = shield
    
    if time > 0.00 then
        set A.time = time
        set A.permanent = false
    else
        set A.permanent = true
    endif
    
    if FirstOfGroup( TempGroup ) == null then
        call TimerStart( TempTimer, 0.01, true, function CheckShieldTime )
    endif
    
    call GroupAddUnit( TempGroup, u )
endfunction
endlibrary

//===========================================================================
function InitTrig_ShieldSystem takes nothing returns nothing
    //set gg_trg_ShieldSystem = CreateTrigger(  )
endfunction

`
ОЖИДАНИЕ РЕКЛАМЫ...