| 
offline
 
Опыт: 
11,698 
Активность: 
     | 
				Aggro System
			 Собственно, система аггро .
 Что такое "аггро-система"?автор MARTY
Аггро-система определяет, какого противника из атакующих юнита этот юнит будет атаковать. Что-то подобное можно видеть в онлайн играх вроде WoW. 
Само слово "аггро" по звучанию близко к "angry" (англ. "злой"). 
То есть, к примеру, пехотинца атакуют два противника... например паладин и рыцарь. Первым напал рыцарь, и аггро пехотинца к рыцарю стало 100%. Но тут вдруг навалился паладин и стал наносить пехотинцу больший урон. Аггро пехотинца: 
Рыцарь: 98% 
Паладин: 1% 
Постепенно оно вырастает до: 
Рыцарь: 49% 
Паладин: 50% 
С этого момента пехотинец начинает больше " злиться " на паладина и начинает атаковать последнего, а не рыцаря. 
 .
Дабы не тревожить хештейбл и сторонние библиотеки, система использует GetUnitUserData() для хранения индекса аггро-таблицы.
 » функции:
	Код: Threat.new(unit ForUnit)
//Создает таблицу угрозы для юнита ForUnit.
 
	Код: Threat.add(unit ForUnit,unit Attacker,real amount)
//Добавляет количество угрозы amount для юнита ForUnit от юнита Attacker.
 
	Код: Threat.get(unit ForUnit,unit Attacker,boolean percent)
//Возвращает количество угрозы созданной юнитом Attacker для юнита ForUnit. Если параметр Percent - true, то вернет процент угрозы для юнита Attacker от общего количество угрозы на юните ForUnit.
 
	Код: Threat.target(unit ForUnit)
//Возвращает текущую цель(цель с максимальной угрозой) для ForUnit.
 
	Код: Threat.top(unit ForUnit)
//Возвращает количество угрозы для вышеуказанной цели.
 
	Код: Threat.clear(unit ForUnit,unit Attacker)
//Очищает угрозу созданную юнитом Attacker для юнита ForUnit. Если вместо параметра Attacker - null, то очищает всю таблицу угрозы для юнита ForUnit.
 
	Код: Threat.remove(unit ForUnit)
//Удаляет таблицу угрозы для юнита ForUnit.
 
	Код: Threat.chase(unit ForUnit,unit Target,boolean Chase)
//Заставляет юнита "ForUnit" преследовать юнита "Target", игнорируя угрозу от остальных, если параметр Chase - true.
 » сама система:
	Код: library Aggro initializer onInit
/*******************************************************************
CREEP AGGRO SYSTEM V1.04                                           *
Created by GodLike! aka Helpmeplz                                  *
********************************************************************
Give me credit if use it in your map.
This system allows you to improve the Creep's AI by adding a Threat Table to him.
Creep attacks the target with the most Threat amount.
For example: use damage event to add an amount of Threat from Damage Source to his target.
Uses GetUnitUserData()
functions:
Threat.new(unit ForUnit) - creates an Threat table for "ForUnit"
Threat.add(unit ForUnit,unit Attacker,real amount) - adds a "amount" of Threat to "ForUnit" from "Attacker"
Threat.get(unit ForUnit,unit Attacker,boolean percent) - returns an Threat amount of "ForUnit" genericed by "Attacker". If "percent" is true then returns the percent value from ALL Threat
Threat.target(unit ForUnit) - returns the current target for "ForUnit"
Threat.top(unit ForUnit) - returns the amount of Threat for "ForUnit"'s Target
Threat.clear(unit ForUnit,unit Attacker) - clears the Threat of "Attacker" for "ForUnit". If "Attacker" is null then clears FULL Threat table for "ForUnit"
Threat.remove(unit ForUnit) - removes an Threat Table for "ForUnit"
Threat.chase(unit ForUnit,unit Target,boolean Chase) - causes the unit "ForUnit" to chase unit "Target", ignoring all incoming threat from others, if "Chase" is true.
*******************************************************************/
globals
private constant integer MAX_ATTACKERS = 20      //maximum attackers of one unit
private constant real CLEAR_AGGRO_PERIOD = 5.   //time after the last attack when the Aggro of unit will be cleared
private constant real TARGET_AGGRO_BONUS = 1.5   //multiplier if the unit gets aggro from its attacker
endglobals
struct Threat
    static Threat array st
    static integer index = 0
    static timer t = CreateTimer()
    static trigger trg = CreateTrigger()
    static group ordered = CreateGroup()
    integer Count = 0
    unit Unit = null
    unit Target = null
    boolean CHASE = false
    real Maxaggro = 0.
    unit array Attacker[MAX_ATTACKERS]
    real array Aggro[MAX_ATTACKERS]
    real array Dur[MAX_ATTACKERS]
    
 static method GetNewTarget takes unit whichUnit returns integer
  local integer i = GetUnitUserData(whichUnit)
  local integer k = 0
  local integer j = 0
    loop
     exitwhen j >= .st[i].Count
      if .st[i].Aggro[j] > .st[i].Aggro[k] then
       set k = j
      endif
     set j = j + 1
    endloop
  return k
 endmethod
 
 static method chase takes unit whichUnit, unit TARGET,boolean CHASE returns nothing
  local integer i = GetUnitUserData(whichUnit)
  set .st[i].CHASE = CHASE
  if CHASE then
  set .st[i].Target = TARGET
  call IssueTargetOrder(.st[i].Unit,"attack",.st[i].Target)
  endif
 endmethod
    
 static method add takes unit whichUnit, unit ATTACKER,real amount returns nothing
  local integer i = GetUnitUserData(whichUnit)
  local integer j = 0
  local boolean founded = false
  if not .st[i].CHASE then
   if .st[i].Target == ATTACKER then
     set amount = amount * TARGET_AGGRO_BONUS
   endif
      loop
       exitwhen j >= .st[i].Count
       if .st[i].Attacker[j] == ATTACKER then
        set founded = true
        set .st[i].Aggro[j] = .st[i].Aggro[j] + amount
        set .st[i].Dur[j] = CLEAR_AGGRO_PERIOD
        if .st[i].Aggro[j] > .st[i].Maxaggro then
         set .st[i].Maxaggro = .st[i].Aggro[j]
         set .st[i].Target = ATTACKER
         call IssueTargetOrder(whichUnit,"attack",ATTACKER)
        endif
        set j = .st[i].Count
       endif
       set j = j + 1
      endloop
      if not founded then
       if .st[i].Count <= MAX_ATTACKERS then
        set .st[i].Attacker[.st[i].Count] = ATTACKER
        set .st[i].Aggro[.st[i].Count] = amount
        set .st[i].Dur[.st[i].Count] = CLEAR_AGGRO_PERIOD
        if amount > .st[i].Maxaggro then
         set .st[i].Maxaggro = amount
         set .st[i].Target = ATTACKER
         call IssueTargetOrder(whichUnit,"attack",ATTACKER)
        endif
        set .st[i].Count = .st[i].Count + 1
       endif
      endif
  endif
 endmethod
 
 static method get takes unit TARGET, unit ATTACKER, boolean percent returns real
  local integer i = GetUnitUserData(TARGET)
  local integer j = 0
  local real aggro = 0.
  local real mainaggro = 0.
  if .st[i].Count > 0 then
    loop
     exitwhen j >= .st[i].Count
      set mainaggro = mainaggro + .st[i].Aggro[j]
      if .st[i].Attacker[j] == ATTACKER then
       set aggro = .st[i].Aggro[j]
      endif
     set j = j + 1
    endloop
   if percent then
    return aggro / mainaggro * 100.
   endif
    return aggro
  endif
  return 0.
 endmethod
 
 static method target takes unit whichUnit returns unit
  if whichUnit == .st[GetUnitUserData(whichUnit)].Unit then
    return .st[GetUnitUserData(whichUnit)].Target
  endif
  return null
 endmethod
 
 static method top takes unit whichUnit returns real
  if whichUnit == .st[GetUnitUserData(whichUnit)].Unit then
    return .st[GetUnitUserData(whichUnit)].Maxaggro
  endif
  return 0.
 endmethod
 
 static method clear takes unit whichUnit, unit forUnit returns nothing
  local integer i = GetUnitUserData(whichUnit)
  local integer j = 0
  local integer k = 0
  if not (forUnit == null) then
   loop
    exitwhen j >= .st[i].Count
     if forUnit == .st[i].Attacker[j] then
        if .st[i].Attacker[j] == .st[i].Target then
          set .st[i].Target = null
          call IssueImmediateOrder(.st[i].Unit,"stop")
        endif
       set .st[i].Count = .st[i].Count - 1
       set .st[i].Attacker[j] = .st[i].Attacker[.st[i].Count]
       set .st[i].Aggro[j] = .st[i].Aggro[.st[i].Count]
       set .st[i].Dur[j] = .st[i].Dur[.st[i].Count]
        if .st[i].Count == 0 then
         set .st[i].Target = null
         set .st[i].Maxaggro = 0.
        elseif .st[i].Target == null then
         set k = Threat.GetNewTarget(.st[i].Unit)
         set .st[i].Target = .st[i].Attacker[k]
         set .st[i].Maxaggro = .st[i].Aggro[k]
         call IssueTargetOrder(.st[i].Unit,"attack",.st[i].Target)
        endif
       set j = .st[i].Count
     endif
    set j = j + 1
   endloop
  else
   set .st[i].Count = 0
   set .st[i].Maxaggro = 0.
   set .st[i].Target = null
  endif
 endmethod
 
 static method remove takes unit whichUnit returns nothing
  local integer i = GetUnitUserData(whichUnit)
   if .st[i].Unit == whichUnit then
    if .st[i].Count > 0 then
    call .st[i].destroy()
    endif
    set .index = .index - 1
    set .st[i] = .st[.index]
    call GroupRemoveUnit(.ordered,whichUnit)
    if .index == 0 then
      call PauseTimer(.t)
    endif
   endif
 endmethod
 
 static method onTimer takes nothing returns nothing
  local integer i = 0
  local integer j = 0
  local integer k = 0
   loop
    exitwhen i >= .index
     set j = 0
     loop
      exitwhen j >= .st[i].Count
       set .st[i].Dur[j] = .st[i].Dur[j] - 1.
       if .st[i].Dur[j] <= 0. or IsUnitType(.st[i].Target,UNIT_TYPE_DEAD) then
        if .st[i].Attacker[j] == .st[i].Target then
         set .st[i].Target = null
         call IssueImmediateOrder(.st[i].Unit,"stop")
        endif
        set .st[i].Count = .st[i].Count - 1
        set .st[i].Attacker[j] = .st[i].Attacker[.st[i].Count]
        set .st[i].Aggro[j] = .st[i].Aggro[.st[i].Count]
        set .st[i].Dur[j] = .st[i].Dur[.st[i].Count]
        if .st[i].Count == 0 then
         set .st[i].Target = null
         set .st[i].Maxaggro = 0.
        elseif .st[i].Target == null then
         set k = Threat.GetNewTarget(.st[i].Unit)
         set .st[i].Target = .st[i].Attacker[k]
         set .st[i].Maxaggro = .st[i].Aggro[k]
         call IssueTargetOrder(.st[i].Unit,"attack",.st[i].Target)
        endif
        set j = j - 1
       endif
      set j = j + 1
     endloop
    set i = i + 1
  endloop
 endmethod
 
 static method new takes unit whichUnit returns nothing
  if not (.st[GetUnitUserData(whichUnit)].Unit == whichUnit) then
   set .st[.index] = Threat.create()
   set .st[.index].Unit = whichUnit
   set .st[.index].Target = null
   set .st[.index].Count = 0
   set .st[.index].Maxaggro = 0.
   call SetUnitUserData(whichUnit,.index)
   if .index == 0 then
      call TimerStart(.t,1.,true,function Threat.onTimer)
   endif
   if not IsUnitInGroup(whichUnit,.ordered) then
    call TriggerRegisterUnitEvent(Threat.trg,whichUnit,EVENT_UNIT_ISSUED_TARGET_ORDER)
    call GroupAddUnit(.ordered,whichUnit)
   endif
   set .index = .index + 1
  endif
 endmethod
 
 static method onOrder takes nothing returns boolean
 local integer i = 0
  if GetIssuedOrderId() == OrderId("attack")
   set i = GetUnitUserData(GetTriggerUnit())
   if not (GetOrderTargetUnit() == .st[i].Target) and not (.st[i].Target == null) then
    call IssueTargetOrder(.st[i].Unit,"attack",.st[i].Target)
   endif
  endif
  return false
 endmethod
endstruct
private function onInit takes nothing returns nothing
  call TriggerAddCondition(Threat.trg,Condition(function Threat.onOrder))
endfunction
endlibrary
 Настройки:MAX_ATTACKERS             - максимальное количество юнитов, которые будут занесены в аггро таблицу к данному
CLEAR_AGGRO_PERIOD    - время с последней атаки юнита, после которого он потеряет все свое аггро на цели
TARGET_AGGRO_BONUS   - множитель аггро если нападающий юнит является целью
 Визуализация
   » код
	Код: library ThreatBars initializer onInit requires Aggro
/*******************************************************************
THREAT BARS for CREEP AGGRO SYSTEM V1.04                           *
Created by GodLike! aka Helpmeplz                                  *
********************************************************************
Give me credit if use it in your map.
This system allows you to adds a Threat Bar for your multiboard, showing an Threat amount of any Unit on the other.
functions:
TBar.add(ForUnit,Attacker,Mb,Row,S_COLUMN,E_COLUMN) - adds an Aggro Bar (showing Threat of "Attacker" on "ForUnit") for multiboard "mb" in row "ROW" starts with S_COMUN and Ends with E_COLUMN.
Automaticaly increases the counts of rows/columns of multiboard if they are lesser than needed.
NOTE: the differense beetwen the starting column and the ending column must be at least 3!
TBar.remove(ForUnit,Attacker,Mb,Row) - removes an Threat Bar (showing Threat of "Attacker" on "ForUnit") for multiboard "mb" from row "Row".
*******************************************************************/
globals
private string array Bars[24]
endglobals
struct TBar
     static TBar array st
     static integer index = 0
     static timer t = CreateTimer()
     unit Target = null
     unit Attacker = null
     multiboard mb = null
     integer ROW = 0
     real COUNT = 0
     integer S_COL = 0
     integer E_COL = 0
     
 static method GetIcon takes integer index,integer s_col, integer e_col returns string
  if index == s_col then
   return Bars[0]
  elseif index == e_col then
    return Bars[23]
  endif
  return Bars[24]
 endmethod
 
 static method RefreshTable takes nothing returns nothing
  local integer i = 0
  local integer j = 0
  local multiboarditem mbi = null
  local string icon = ""
  local integer k = 0
   loop
    exitwhen i >= .index
     set j = .st[i].S_COL
     set k = R2I(Threat.get(.st[i].Target,.st[i].Attacker,true) / .st[i].COUNT)
      loop
       exitwhen j > .st[i].E_COL
       set mbi = MultiboardGetItem(.st[i].mb,.st[i].ROW,j)
       if j == .st[i].S_COL then
        if k == 0 then
         set icon = Bars[0]
        elseif k>=7 then
         set k=k-7
         set icon = Bars[7]
        else
         set icon = Bars[k]
         set k = 0
        endif
       elseif j == .st[i].E_COL then
        if k==0 then
         set icon = Bars[23]
        elseif k>=7 then
         set icon = Bars[22]
        else
         set icon = Bars[15+k]
        endif
       else
        if k==0 then
         set icon = Bars[24]
        elseif k>=7 then
         set k = k - 7
         set icon = Bars[15]
        else
         set icon = Bars[7+k]
         set k = 0
        endif
       endif
       set j = j + 1
       call MultiboardSetItemIcon(mbi,icon)
       call MultiboardReleaseItem(mbi)
       set mbi = null
      endloop
    set i = i + 1
   endloop
 endmethod
 
 static method remove takes unit Target,unit Attacker,multiboard m,integer Row returns nothing
  local integer i = 0
  local integer j = 0
  local multiboarditem mbi = null
   loop
    exitwhen i >=. index
     if .st[i].Target == Target and .st[i].Attacker == Attacker and .st[i].mb == m and .st[i].ROW == Row then
      set j = .st[i].S_COL
      loop
       exitwhen j > .st[i].E_COL
        set mbi = MultiboardGetItem(.st[i].mb,.st[i].ROW,j)
        call MultiboardSetItemStyle(mbi,false,false)
        call MultiboardReleaseItem(mbi)
        set mbi = null
       set j = j + 1
      endloop
      call .st[i].destroy()
      set .index = .index - 1
      set .st[i] = .st[.index]
      if .index == 0 then
       call PauseTimer(.t)
      endif
      set i = .index
     endif
    set i = i + 1
   endloop
 endmethod
     
 static method add takes unit Target,unit Attacker, multiboard m,integer row,integer s_col,integer e_col returns nothing
  local integer i = 0
  local multiboarditem mbi = null
  set .st[.index] = TBar.create()
  set .st[.index].mb = m
  set .st[.index].ROW = row
  set .st[.index].S_COL = s_col
  set .st[.index].E_COL = e_col
  set .st[.index].Target = Target
  set .st[.index].Attacker = Attacker
  set .st[.index].COUNT = 100. / ( (e_col - s_col + 1) * 8 - 2)
  if e_col > MultiboardGetColumnCount(m) then
   call MultiboardSetColumnCount(m,e_col)
  endif
  if row > MultiboardGetRowCount(m) then
   call MultiboardSetRowCount(m,row)
  endif
  set i = s_col
  loop
   exitwhen i > .st[.index].E_COL
   set mbi = MultiboardGetItem(m,row,i)
   call MultiboardSetItemStyle(mbi,false,true)
   call MultiboardSetItemWidth(mbi,0.01)
   call MultiboardSetItemIcon(mbi,TBar.GetIcon(i,.st[.index].S_COL,.st[.index].E_COL))
   call MultiboardReleaseItem(mbi)
   set mbi = null
   set i = i + 1
  endloop
  if .index == 0 then
   call TimerStart(.t,0.04,true,function TBar.RefreshTable)
  endif
  set .index = .index + 1
 endmethod
 
endstruct
private function onInit takes nothing returns nothing
set Bars[0] = "war3mapImported\\AggroL0.tga"
set Bars[1] = "war3mapImported\\AggroL1.tga"
set Bars[2] = "war3mapImported\\AggroL2.tga"
set Bars[3] = "war3mapImported\\AggroL3.tga"
set Bars[4] = "war3mapImported\\AggroL4.tga"
set Bars[5] = "war3mapImported\\AggroL5.tga"
set Bars[6] = "war3mapImported\\AggroL6.tga"
set Bars[7] = "war3mapImported\\AggroL7.tga"
set Bars[8] = "war3mapImported\\AggroM1.tga"
set Bars[9] = "war3mapImported\\AggroM2.tga"
set Bars[10] = "war3mapImported\\AggroM3.tga"
set Bars[11] = "war3mapImported\\AggroM4.tga"
set Bars[12] = "war3mapImported\\AggroM5.tga"
set Bars[13] = "war3mapImported\\AggroM6.tga"
set Bars[14] = "war3mapImported\\AggroM7.tga"
set Bars[15] = "war3mapImported\\AggroM8.tga"
set Bars[16] = "war3mapImported\\AggroR1.tga"
set Bars[17] = "war3mapImported\\AggroR2.tga"
set Bars[18] = "war3mapImported\\AggroR3.tga"
set Bars[19] = "war3mapImported\\AggroR4.tga"
set Bars[20] = "war3mapImported\\AggroR5.tga"
set Bars[21] = "war3mapImported\\AggroR6.tga"
set Bars[22] = "war3mapImported\\AggroR7.tga"
set Bars[23] = "war3mapImported\\AggroR0.tga"
set Bars[24] = "war3mapImported\\AggroM0.tga"
endfunction
endlibrary
 » +функции
	Код: TBar.add(ForUnit,Attacker,Mb,Row,S_COLUMN,E_COLUMN)
//добавляет Трит-бар(показывает угрозу юнита Attacker на юните ForUnit) в строку Row мультиборда Mb, начиная со столбца S_COLUM и заканчивая столбцом E_COLUMN.
Автоматически увеличивает количество строк/столбцов в мультиборде, если их меньше чем указано.
Примечание: в этом случае не инициализируются ячейки в строках не относящихся к Трит-бару.
Примечание: количество столбцов в промежутке должно быть не менее 3.
 
	Код: TBar.remove(ForUnit,Attacker,Mb,Row)
//удаляет Трит-бар(показывает угрозу юнита Attacker на юните ForUnit) из строки Row мультиборда Mb.
 
карта-пример прилагается(обновлено)			 Отредактировано Helpmeplz, 19.08.2011 в 20:11.
 |