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.
|