SineCosine
I'm still looking for my Tangent
- Reaction score
- 77
Well, I'm creating this Hero Survival map. (Was a Hero Defense, but is now a Hero Survival..)
And each level is supposed to be a different set of monsters, each with special abilities and a different strategy is required to defeat them.
The thing is, with special abilities, I'm going to need to develop an AI..
One that can tell the creeps when to cast a spell, how to group with each other, who is the leader, when to run, etc.
But..
There isn't any system like that.. (That I could find, maybe someone can find a system like that and save me from my misery..)
So, I decided to code a system like that myself..
Unfortunately, I have never done ANYTHING of the sort before..
And so, my codes are messy and I doubt everything is running smoothly.
This is all I have managed to do so far:
01) Create an AI for units to cast a Single Target Spell
02) Create an AI for units to group around a leader
03) When the 'leader' casts a Single Target Spell or attacks an enemy, all the other 'Followers' will attack the enemy
I'll upload a map with the System that's just started and I need comments =x
Remember, don't tell me, "It's horrible".
I'd rather read something specific like, "You can do it this way..."
Also, I can't figure out how to get the AI-Groups to do this..
01) Must attack lowest HP unit in area
02) But helping Leader is priority
03) If leader dies LOOK for another group to join
Things to note:
01) If any of the 2 felhounds survive.. Try tanking all the enemy creeps' damage, you'll see that as long as the felhound (Leader) attacks the hero the Orc Tamers (Follower) will ignore your felhound and attack you, instead. And that is supposed to happen.
02) There is a bug that, sometimes, 2 felhounds will 'Pounce' on the same unit. And that is not supposed to happen.
What's available:
01) [lJASS]function SpellInit takes integer UnitID, string STRING, real RANGE, integer BuffID, boolean CastOnEnemy, string BaseID, real TIME, real CoolDown returns nothing[/lJASS]
02)[lJASS] function AttachLeader takes unit Leader, integer NumberOfFollower, boolean SpecificUnitType, integer FollowerID, real RANGE returns nothing[/lJASS]
So..
Yea, looking for comments on how to improve what I already have and a bit of help on a few of the AI-Group functions.. =x
Full-Code (So Far..)
And each level is supposed to be a different set of monsters, each with special abilities and a different strategy is required to defeat them.
The thing is, with special abilities, I'm going to need to develop an AI..
One that can tell the creeps when to cast a spell, how to group with each other, who is the leader, when to run, etc.
But..
There isn't any system like that.. (That I could find, maybe someone can find a system like that and save me from my misery..)
So, I decided to code a system like that myself..
Unfortunately, I have never done ANYTHING of the sort before..
And so, my codes are messy and I doubt everything is running smoothly.
This is all I have managed to do so far:
01) Create an AI for units to cast a Single Target Spell
02) Create an AI for units to group around a leader
03) When the 'leader' casts a Single Target Spell or attacks an enemy, all the other 'Followers' will attack the enemy
I'll upload a map with the System that's just started and I need comments =x
Remember, don't tell me, "It's horrible".
I'd rather read something specific like, "You can do it this way..."
Also, I can't figure out how to get the AI-Groups to do this..
01) Must attack lowest HP unit in area
02) But helping Leader is priority
03) If leader dies LOOK for another group to join
Things to note:
01) If any of the 2 felhounds survive.. Try tanking all the enemy creeps' damage, you'll see that as long as the felhound (Leader) attacks the hero the Orc Tamers (Follower) will ignore your felhound and attack you, instead. And that is supposed to happen.
02) There is a bug that, sometimes, 2 felhounds will 'Pounce' on the same unit. And that is not supposed to happen.
What's available:
01) [lJASS]function SpellInit takes integer UnitID, string STRING, real RANGE, integer BuffID, boolean CastOnEnemy, string BaseID, real TIME, real CoolDown returns nothing[/lJASS]
02)[lJASS] function AttachLeader takes unit Leader, integer NumberOfFollower, boolean SpecificUnitType, integer FollowerID, real RANGE returns nothing[/lJASS]
So..
Yea, looking for comments on how to improve what I already have and a bit of help on a few of the AI-Group functions.. =x
Full-Code (So Far..)
JASS:
library AIL
globals
private constant integer Chk = 039;A010039;
endglobals
////This Is Where My GroupAI is..
private struct GroupAI
private static GroupAI data = 0
static GroupAI ATK = 0
unit Leader
integer NumberOfFollower
boolean SpecificUnitType
integer FollowerID
integer ticks
unit array Followers[1000]
real LeaderHP
real array FollowerHP[1000]
integer FollowerAmount
boolean LeaderAtk
integer MTick
static method AttackForLeader takes unit Targ returns nothing
local GroupAI g = GroupAI.ATK
local integer i = 1
set g.LeaderAtk = true
loop
exitwhen i > g.FollowerAmount
call IssueTargetOrder(g.Followers<i>, "attack", Targ)
set i = i + 1
endloop
endmethod
private method periodic takes nothing returns nothing
local GroupAI g = this
local integer i = 1
local integer OtherI = 1
if g.ticks < g.MTick then
loop
exitwhen i > g.FollowerAmount
if GetWidgetLife(g.Followers<i>) <= 1 then
set g.Followers<i> = null
loop
exitwhen OtherI > g.FollowerAmount
set g.Followers<i> = g.Followers[i+1]
set OtherI = OtherI + 1
endloop
set g.FollowerAmount = g.FollowerAmount - 1
endif
set i = i + 1
endloop
set g.ticks = g.ticks + 1
else
if g.ticks == (32*10) + 1 then
set g.LeaderAtk = false
set g.MTick = 33
endif
loop
exitwhen i > g.FollowerAmount
if g.LeaderAtk == false then
call IssueTargetOrder(g.Followers<i>, "move", g.Leader)
endif
set i = i + 1
endloop
set g.ticks = 1
endif
if g.LeaderAtk == true then
set g.MTick = (32*10) + 1
endif
if GetWidgetLife(g.Leader) <= 1 then
call g.stopPeriodic()
call g.destroy()
endif
endmethod
implement T32x
static method GetFollower takes nothing returns boolean
local GroupAI g = GroupAI.data
local unit u = GetFilterUnit()
local boolean b = false
local integer i = 1
loop
exitwhen i > g.FollowerAmount
if IsUnit(u, g.Followers<i>) == true then
set b = true
endif
set i = i + 1
endloop
if b == false and g.FollowerAmount != g.NumberOfFollower then
if g.SpecificUnitType == true then
if GetUnitTypeId(u) == g.FollowerID and GetWidgetLife(u) > 0 and IsUnitEnemy(u, GetOwningPlayer(g.Leader)) == false then
set g.FollowerAmount = g.FollowerAmount + 1
set g.FollowerHP[g.FollowerAmount] = GetWidgetLife(u)
set g.Followers[g.FollowerAmount] = u
endif
else
if GetWidgetLife(u) > 0 and IsUnitEnemy(u, GetOwningPlayer(g.Leader)) == false then
set g.FollowerAmount = g.FollowerAmount + 1
set g.FollowerHP[g.FollowerAmount] = GetWidgetLife(u)
set g.Followers[g.FollowerAmount] = u
endif
endif
endif
set u = null
return false
endmethod
static method Start takes unit Leader, integer NumberOfFollower, boolean SpecificUnitType, integer FollowerID, real RANGE returns nothing
local GroupAI g = GroupAI.create()
local integer i = 0
set g.Leader = Leader
set g.NumberOfFollower = NumberOfFollower
set g.SpecificUnitType = SpecificUnitType
set g.FollowerID = FollowerID
set g.ticks = 1
set g.LeaderHP = GetWidgetLife(g.Leader)
set g.FollowerAmount = 0
set g.LeaderAtk = false
set g.MTick = 33
set GroupAI.data = g
call GroupEnumUnitsInRange(GROUP, GetUnitX(g.Leader), GetUnitY(g.Leader), RANGE, function GroupAI.GetFollower)
if g.FollowerAmount == 0 then
call g.destroy()
else
call g.startPeriodic()
call SetUnitUserData(g.Leader, g)
endif
endmethod
method onDestroy takes nothing returns nothing
local integer i = 1
set .Leader = null
loop
exitwhen i > .FollowerAmount
set .Followers<i> = null
set i = i + 1
endloop
endmethod
endstruct
function AttachLeader takes unit Leader, integer NumberOfFollower, boolean SpecificUnitType, integer FollowerID, real RANGE returns nothing
call GroupAI.Start(Leader, NumberOfFollower, SpecificUnitType, FollowerID, RANGE)
endfunction
//This Detects When A Leader Is Attacking..
private function CLAAct takes nothing returns nothing
local GroupAI g = GetUnitUserData(GetAttacker())
local integer i = 1
set g.LeaderAtk = true
loop
exitwhen i > g.FollowerAmount
call IssueTargetOrder(g.Followers<i>, "attack", GetTriggerUnit())
call IssueTargetOrder(g.Leader, "attack", GetTriggerUnit())
set i = i + 1
endloop
endfunction
private function CLACond takes nothing returns boolean
local GroupAI g = GetUnitUserData(GetAttacker())
return g.Leader != null
endfunction
private function CheckLeaderAtk takes nothing returns nothing
local trigger t = CreateTrigger()
local integer i = 0
loop
exitwhen i == 12
call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_ATTACKED, null)
set i = i + 1
endloop
call TriggerAddCondition(t, Condition( function CLACond ))
call TriggerAddAction(t, function CLAAct)
endfunction
//This Is Where My SpellAI is..
private struct PC
unit caster
integer ticks
integer MTick
private method periodic takes nothing returns nothing
local PC pc = this
if pc.ticks < pc.MTick then
set pc.ticks = pc.ticks + 1
else
call pc.stopPeriodic()
call pc.destroy()
endif
endmethod
implement T32x
static method PCAct takes unit u, real time returns nothing
local PC pc = PC.allocate()
set pc.caster = u
set pc.ticks = 1
set pc.MTick = R2I(time / 0.03125)
call UnitRemoveAbility(pc.caster, Chk)
call pc.startPeriodic()
endmethod
method onDestroy takes nothing returns nothing
call UnitAddAbility(.caster, Chk)
set .caster = null
endmethod
endstruct
private struct UnitSpell
private static UnitSpell CastData = 0
private static UnitSpell TargData = 0
integer UnitID
real RANGE
integer BuffID
boolean CastOnEnemy
string BaseID
real CoolDown
group UnitsCasting = CreateGroup()
group Targets = CreateGroup()
integer Ticks
integer MAXTicks
unit CurrentUnit
static method TARGGET takes nothing returns boolean
local UnitSpell u = UnitSpell.TargData
local GroupAI g = GetUnitUserData(u.CurrentUnit)
local unit Targ = GetFilterUnit()
if u.BuffID != 0 then
if IsUnitEnemy(Targ, GetOwningPlayer(u.CurrentUnit)) == u.CastOnEnemy and GetUnitAbilityLevel(Targ, u.BuffID) == 0 and IsUnitInGroup(Targ, u.Targets) == false and GetWidgetLife(Targ) > 0 then
call GroupAddUnit(u.Targets, Targ)
call IssueTargetOrder(u.CurrentUnit, u.BaseID, Targ)
call PC.PCAct(u.CurrentUnit, u.CoolDown)
if IsUnit(u.CurrentUnit, g.Leader) == true then
set GroupAI.ATK = g
call GroupAI.AttackForLeader(Targ)
endif
endif
else
if IsUnitEnemy(Targ, GetOwningPlayer(u.CurrentUnit)) == u.CastOnEnemy and IsUnitInGroup(Targ, u.Targets) == false and GetWidgetLife(Targ) > 0 then
call GroupAddUnit(u.Targets, Targ)
call IssueTargetOrder(u.CurrentUnit, u.BaseID, Targ)
call PC.PCAct(u.CurrentUnit, u.CoolDown)
if IsUnit(u.CurrentUnit, g.Leader) == true then
set GroupAI.ATK = g
call GroupAI.AttackForLeader(Targ)
endif
endif
endif
set Targ = null
return false
endmethod
static method CASTGET takes nothing returns boolean
local UnitSpell u = UnitSpell.CastData
local unit Cast = GetFilterUnit()
if GetUnitTypeId(Cast) == u.UnitID and GetUnitAbilityLevel(Cast, Chk) > 0 and IsUnitInGroup(Cast, u.UnitsCasting) == false and GetWidgetLife(Cast) > 0 then
call GroupAddUnit(u.UnitsCasting, Cast)
set u.CurrentUnit = Cast
set UnitSpell.TargData = u
call GroupEnumUnitsInRange(GROUP2, GetUnitX(Cast), GetUnitY(Cast), u.RANGE, function UnitSpell.TARGGET)
endif
set Cast = null
return false
endmethod
private method periodic takes nothing returns nothing
local UnitSpell u = this
if u.Ticks == 1 then
call GroupClear(u.UnitsCasting)
call GroupClear(u.Targets)
set u.CurrentUnit = null
set u.Ticks = u.Ticks + 1
elseif u.Ticks < u.MAXTicks then
set u.Ticks = u.Ticks + 1
else
set UnitSpell.CastData = u
call GroupEnumUnitsInRange(GROUP, 0, 0, 99999999.0, function UnitSpell.CASTGET)
set u.Ticks = 1
endif
endmethod
implement T32x
static method Start takes integer UnitID, real RANGE, integer BuffID, boolean CastOnEnemy, string BaseID, real TIME, real CoolDown returns nothing
local UnitSpell u = UnitSpell.allocate()
set u.UnitID = UnitID
set u.RANGE = RANGE
set u.BuffID = BuffID
set u.CastOnEnemy = CastOnEnemy
set u.BaseID = BaseID
set u.MAXTicks = R2I(TIME / 0.03125) + 1
set u.Ticks = 1
set u.CoolDown = CoolDown
call u.startPeriodic()
endmethod
endstruct
function SpellInit takes integer UnitID, string STRING, real RANGE, integer BuffID, boolean CastOnEnemy, string BaseID, real TIME, real CoolDown returns nothing
if STRING == "UNIT_SPELL_AI" then
call UnitSpell.Start(UnitID, RANGE, BuffID, CastOnEnemy, BaseID, TIME, CoolDown)
endif
endfunction
endlibrary
</i></i></i></i></i></i></i></i>