- Joined
- Mar 10, 2009
- Messages
- 5,016
I made an engage system for AI hero or unit, I need some testers and suggestions before I put this in spell's section...
This AI system will assign ANY moving unit to attack enemies in range...
Read the instructions carefully...
credits to watermelon_1234 for helping me to improve things...
This AI system will assign ANY moving unit to attack enemies in range...
Read the instructions carefully...
JASS:
//System Name: EngageSystem
//Made by: Mckill2009
//===FEATURES:
//- This system will order the AI to engage and search for enemies
//- Allows pick up item or custom item type
//- Allows target random enemy units include creeps
//- Allows follow user hero option
//- Retreat away from attacker or to building when HP goes down
//- Allows to learn/pick custom skill (manually set it up below)
//- Allows target refresh when target dies or duration runs out
//===HOW TO USE:
//- Make a new trigger and convert to custom text via EDIT >>> CONVERT CUSTOM TEXT
//- Copy ALL that is written here (overwrite the existing texts in the trigger)
//===REQUIRES:
//- Jass New Gen Pack (JNGP) by Vexorian
library EngageSystem initializer init
globals
//===NON-CONFIGURABLES: Meaning, do not touch this!
private constant hashtable HASH = InitHashtable()
private constant integer FOUNTAIN_OF_HEALTH = 'nfoh'
//private constant integer FOUNTAIN_OF_MANA = 'nmoo' //Reserved
//private constant integer STOP = 851972
private constant integer ATTACK = 851983
private constant integer SMART = 851971
//private constant integer ATTACK_GROUND = 851984
private constant integer MOVE = 851986
private real CENTER_X
private real CENTER_Y
private integer array ITEM_TYPE
private integer array SKILL
private trigger RETREAT_TRIGGER
private rect R
private unit UNIT_RETREATING
private unit UNIT_DATA
private location SEARCH_LOCATION
endglobals
globals
//===CONFIGURABLES:
private constant real AOE_FOLLOW = 4000
private constant real AOE_ITEM_PICK = 500
private constant real AOE_TARGET_RANDOM = 5000
private constant real AOE_TARGET_BUILDING = 6000
private constant real AOE_TARGET_SEARCH = 50000 //This should be big
private constant real AOE_TARGET_CREEP = 6000
private constant real AOE_RETREAT_TO_BUILDING = 8000
private constant real RETREAT_DISTANCE = 2700
private constant real ATTACK_DURATION = 30.
private constant real ATTACK_INTERVAL = 3 //Recommended setting
private constant real ITEM_PICK_INTERVAL = 1 //Recommended setting
private constant real FOLLOW_INTERVAL = 3 //Recommended setting
private constant real MAX_LIFE_PERCENTAGE = 0.5 //Used for retreat
private constant integer MAX_ITEM_TYPE = 3 //Should be match on how many item types created
private constant integer MAX_CUSTOM_SKILL = 5 //Should be match on how many skills created
private constant integer MAX_ITEM_PICKED = 3 //Warning: MAX is 6
private constant boolean ENABLE_PICK_UP_ITEM = true
private constant boolean ENABLE_PICK_UP_ITEM_TYPE = false //Set to false to pick every item types
private constant boolean ENABLE_FOLLOW_HERO = false //set to true to follow hero
private constant boolean ENABLE_RETREAT = true
private constant boolean ENABLE_RETREAT_TO_BUILDING = false
endglobals
//===ATTACKING STRUCT:
private struct Engage
unit hero
unit target
real duration
static method onSearchAttack takes nothing returns boolean
local unit u = GetFilterUnit()
local boolean b = GetWidgetLife(u) > 0.405 and IsUnitEnemy(u, GetOwningPlayer(UNIT_DATA))
set u = null
return b
endmethod
static method onRangeAttack takes nothing returns boolean
local unit u = GetFilterUnit()
local boolean b = GetWidgetLife(u) > 0.405 and IsUnitEnemy(u, GetOwningPlayer(UNIT_DATA)) and GetOwningPlayer(u)!=Player(PLAYER_NEUTRAL_AGGRESSIVE)
set u = null
return b
endmethod
static method onCreepAttack takes nothing returns boolean
local unit u = GetFilterUnit()
local boolean b = GetWidgetLife(u) > 0.405 and GetOwningPlayer(u)==Player(PLAYER_NEUTRAL_AGGRESSIVE)
set u = null
return b
endmethod
static method onEnemyBuildingLoc takes nothing returns boolean
local unit u = GetFilterUnit()
local boolean b = GetWidgetLife(u) > 0.405 and IsUnitEnemy(u, GetOwningPlayer(UNIT_DATA)) and IsUnitType(u, UNIT_TYPE_STRUCTURE)
set u = null
return b
endmethod
static method onAttackNow takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = LoadInteger(HASH, GetHandleId(t), 1)
local unit firsttarget
local real x
local real y
if .duration > 0 and GetWidgetLife(.hero) > 0.405 then
set .duration = .duration - ATTACK_INTERVAL
if GetWidgetLife(.target) > 0.405 and .target != null then
call BJDebugMsg(GetUnitName(.hero)+" TARGET STILL ALIVE")
call IssuePointOrderById(.hero, SMART, GetUnitX(.target), GetUnitY(.target))
call IssueTargetOrderById(.hero, ATTACK, .target)
else
call BJDebugMsg(GetUnitName(.hero)+" SEARCHING")
set UNIT_DATA = .hero
call GroupEnumUnitsInRect(bj_lastCreatedGroup, bj_mapInitialPlayableArea, Filter(function thistype.onSearchAttack))
//call GroupEnumUnitsInRange(bj_lastCreatedGroup, CENTER_X, CENTER_Y, AOE_TARGET_SEARCH, Filter(function thistype.onSearchAttack))
set firsttarget = FirstOfGroup(bj_lastCreatedGroup)
call IssuePointOrderById(.hero, SMART, GetUnitX(firsttarget), GetUnitY(firsttarget))
call IssueTargetOrderById(.hero, ATTACK, .target)
if firsttarget==null then
call BJDebugMsg("MOVE RANDOM")
call MoveLocation(SEARCH_LOCATION, GetRandomReal(GetRectMinX(bj_mapInitialPlayableArea), GetRectMaxX(bj_mapInitialPlayableArea)), GetRandomReal(GetRectMinY(bj_mapInitialPlayableArea), GetRectMaxY(bj_mapInitialPlayableArea)))
call IssuePointOrderByIdLoc(.hero, ATTACK, SEARCH_LOCATION)
endif
endif
else
if GetWidgetLife(.hero) > 0.405 then
call Engage.onAttackSetup(.hero)
endif
call .destroy(this)
call PauseTimer(t)
call DestroyTimer(t)
endif
set firsttarget = null
set t = null
endmethod
static method onAttackSetup takes unit u returns Engage
local Engage EN = Engage.create()
local timer t = CreateTimer()
local integer randomatk = GetRandomInt(1, 4)
set UNIT_DATA = u
if randomatk==1 or randomatk==2 then
call GroupEnumUnitsInRange(bj_lastCreatedGroup, GetUnitX(u), GetUnitY(u), AOE_TARGET_RANDOM, Filter(function thistype.onRangeAttack))
elseif randomatk==3 then
call GroupEnumUnitsInRange(bj_lastCreatedGroup, GetUnitX(u), GetUnitY(u), AOE_TARGET_CREEP, Filter(function thistype.onCreepAttack))
elseif randomatk==4 then
call GroupEnumUnitsInRange(bj_lastCreatedGroup, GetUnitX(u), GetUnitY(u), AOE_TARGET_BUILDING, Filter(function thistype.onEnemyBuildingLoc))
endif
set EN.target = FirstOfGroup(bj_lastCreatedGroup)
set EN.hero = u
set EN.duration = ATTACK_DURATION
//call BJDebugMsg(GetUnitName(EN.hero)+" "+I2S(EN))
call SaveInteger(HASH, GetHandleId(t), 1, EN)
call TimerStart(t, ATTACK_INTERVAL, true, function thistype.onAttackNow)
set t = null
return EN
endmethod
endstruct
//===ITEM PICK STRUCT:
private struct ItemPick
unit hero
private static thistype DATA
static method onPickItem takes nothing returns boolean
local thistype this = DATA
local item it = GetFilterItem()
local integer i = 0
if ENABLE_PICK_UP_ITEM_TYPE then
loop
set i = i+1
if GetItemTypeId(it)==ITEM_TYPE[i] then
call IssueTargetOrderById(.hero, SMART, it)
endif
exitwhen i >= MAX_ITEM_TYPE
endloop
else
call IssueTargetOrderById(.hero, SMART, it)
endif
set it = null
return false
endmethod
static method enumerateItem takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = LoadInteger(HASH, GetHandleId(t), 1)
local real x
local real y
local integer index = 0
local integer count = 0
loop
if (UnitItemInSlot(.hero, index) != null) then
set count = count + 1
endif
set index = index + 1
exitwhen index >= bj_MAX_INVENTORY
endloop
if GetWidgetLife(.hero) > 0.405 and count < MAX_ITEM_PICKED then
set x = GetUnitX(.hero)
set y = GetUnitY(.hero)
set DATA = this
call MoveRectTo(R, x, y)
call EnumItemsInRect(R, function thistype.onPickItem, null)
endif
set t = null
endmethod
static method onenumerateItem takes unit hero returns thistype
local thistype this = thistype.create()
local timer t = CreateTimer()
set .hero = hero
call SaveInteger(HASH, GetHandleId(t), 1, this)
call TimerStart(t, ITEM_PICK_INTERVAL, true, function thistype.enumerateItem)
set t = null
return this
endmethod
endstruct
//===FOLLOW HERO STRUCT:
private struct FollowH
unit trigunit
private static thistype DATA
static method onFollowFilter takes nothing returns boolean
local thistype this = DATA
local unit u = GetFilterUnit()
local real x
local real y
local real offset = GetRandomReal(100, 250)
local real angle = GetRandomReal(0, 360)
if not IsUnitEnemy(u, GetOwningPlayer(.trigunit)) and IsUnitType(u, UNIT_TYPE_HERO) and GetWidgetLife(u) > 0.405 then
set x = GetUnitX(u)+offset*Cos(angle)
set y = GetUnitY(u)+offset*Sin(angle)
call IssuePointOrderById(.trigunit, ATTACK, x, y)
endif
set u = null
return false
endmethod
static method NowFollow takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = LoadInteger(HASH, GetHandleId(t), 1)
local real x = GetUnitX(.trigunit)
local real y = GetUnitY(.trigunit)
set DATA = this
call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, AOE_FOLLOW, function thistype.onFollowFilter)
if GetWidgetLife(.trigunit) <= 0.405 then
call .destroy(this)
call PauseTimer(t)
call DestroyTimer(t)
endif
set t = null
endmethod
static method onFollow takes unit u returns thistype
local thistype this = thistype.create()
local timer t = CreateTimer()
set .trigunit = u
call SaveInteger(HASH, GetHandleId(t), 1, this)
call TimerStart(t, FOLLOW_INTERVAL, true, function thistype.NowFollow)
set t = null
return this
endmethod
endstruct
//===RETREAT:
private function onRetreatForHealth takes nothing returns boolean
local unit u = GetFilterUnit()
local boolean b
if GetRandomInt(1,2)==1 then
set b = GetUnitTypeId(u)==FOUNTAIN_OF_HEALTH
else
set b = not IsUnitEnemy(u, GetOwningPlayer(UNIT_RETREATING)) and GetWidgetLife(u) > 0.405 and IsUnitType(u, UNIT_TYPE_STRUCTURE) or GetUnitTypeId(u)==FOUNTAIN_OF_HEALTH
endif
set u = null
return b
endfunction
function Retreat takes unit hero, unit attacker returns nothing
local real maxlife = GetUnitState(hero, UNIT_STATE_MAX_LIFE)
local real x
local real y
local real x1
local real y1
local unit building
if GetWidgetLife(hero) <= maxlife*MAX_LIFE_PERCENTAGE then
set x = GetUnitX(hero)
set y = GetUnitY(hero)
set x1 = x + RETREAT_DISTANCE * Cos(GetUnitFacing(attacker))
set y1 = y + RETREAT_DISTANCE * Sin(GetUnitFacing(attacker))
call IssuePointOrderById(hero, MOVE, x1, y1)
if ENABLE_RETREAT_TO_BUILDING then
set UNIT_RETREATING = hero
call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, AOE_RETREAT_TO_BUILDING, function onRetreatForHealth)
set building = FirstOfGroup(bj_lastCreatedGroup)
if building==null then
call Retreat(hero, null)
else
call IssuePointOrder(hero, "move", GetUnitX(building), GetUnitY(building))
endif
endif
endif
set building = null
endfunction
private function RetreatCond takes nothing returns boolean
call Retreat(GetTriggerUnit(), GetAttacker())
return false
endfunction
//===LEARN SKILL AND PICK UP ITEM:
private function PickSkillNow takes nothing returns boolean
local integer i
if GetPlayerController(GetTriggerPlayer())==MAP_CONTROL_COMPUTER then
set i = 0
loop
set i = i + 1
call SelectHeroSkill(GetTriggerUnit(), SKILL[i])
exitwhen i >= MAX_CUSTOM_SKILL
endloop
endif
return false
endfunction
// Set the skills and item types here!
private function SetupSkillsAndItemTypes takes nothing returns nothing
//You must setup the skills here
set SKILL[1] = 'A000'
set SKILL[2] = 'A000'
set SKILL[3] = 'A000'
set SKILL[4] = 'A000'
set SKILL[5] = 'A000'
//IMPORTANT NOTE: if you increase the item types created, you should increase also the MAX_ITEM_TYPE of the globals
set ITEM_TYPE[1] = 'will' //Default Wand of Illusion
set ITEM_TYPE[2] = 'woms' //Default Wand of Mana Stealing
set ITEM_TYPE[3] = 'wlsd' //Default Wand of Lightning Shield
//set ITEM_TYPE[4] = 'ADDITIONAL ITEM'
//set ITEM_TYPE[5] = 'ADDITIONAL ITEM'
endfunction
private function init takes nothing returns nothing
local trigger t1 = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t1, EVENT_PLAYER_HERO_LEVEL )
call TriggerAddCondition(t1, function PickSkillNow)
set CENTER_X = GetRectCenterX(bj_mapInitialPlayableArea)
set CENTER_Y = GetRectCenterY(bj_mapInitialPlayableArea)
set SEARCH_LOCATION = Location(GetRandomReal(GetRectMinX(bj_mapInitialPlayableArea), GetRectMaxX(bj_mapInitialPlayableArea)), GetRandomReal(GetRectMinY(bj_mapInitialPlayableArea), GetRectMaxY(bj_mapInitialPlayableArea)))
set R = Rect(-AOE_ITEM_PICK, -AOE_ITEM_PICK, AOE_ITEM_PICK, AOE_ITEM_PICK)
call SetupSkillsAndItemTypes()
set t1 = null
endfunction
//===SETUP EVERYTHING:========================================
function SetEngageUnit takes unit u returns nothing
call Engage.onAttackSetup(u)
if ENABLE_PICK_UP_ITEM and GetPlayerController(GetOwningPlayer(u))==MAP_CONTROL_COMPUTER and IsUnitType(u, UNIT_TYPE_HERO) then
call ItemPick.onenumerateItem(u)
endif
if ENABLE_FOLLOW_HERO then
call FollowH.onFollow(u)
endif
if ENABLE_RETREAT then
set RETREAT_TRIGGER = CreateTrigger()
call TriggerRegisterUnitEvent(RETREAT_TRIGGER, u, EVENT_UNIT_ATTACKED)
call TriggerAddCondition(RETREAT_TRIGGER, Condition(function RetreatCond))
endif
endfunction
endlibrary
credits to watermelon_1234 for helping me to improve things...
Attachments
Last edited: