• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[JASS] Can someone help me to fix this issue?

Status
Not open for further replies.
Level 17
Joined
Jun 2, 2009
Messages
1,139
Hello everyone. I don't know about Jass and this trigger made by my friend.
When you attack enemy hero and if there are any creeps (friendly units) around them, attack the attacker
Example: Red Archmage attacks Purple Archmage, allied units around attacked unit (Red Archmage attacks Purple Archmage) should attack the Attacker (Red Archmage)
This trigger works until here but the problem starts in here.
I have shared 2 pictures for the details.



JASS:
library CreepSystem initializer Init
 
globals
    private constant real CREEP_ATTACK_FOG_REVEAL_TIME = 1.00
 
    private constant integer CREEP_ABILITY_ID = 'A0E6'
 

    public integer HeroIndex = 0
 
 
    private boolean OBS = false
    private constant integer ORDER_ID_MOVE = 851986
    //private constant integer STOP_ORDER_ID =
    private constant integer ORDER_ID_SMART = 851971
    private constant integer ORDER_ID_ATTACK = 851983
    private unit array HeroAttacker
endglobals
 
public function IsClanUnit takes unit u returns boolean
    return GetOwningPlayer(u) == udg_ClanDevilPlayer or GetOwningPlayer(u) == udg_ClanReaperPlayer
endfunction
 
public function IsRealHero takes unit u returns boolean
    return IsUnitType(u, UNIT_TYPE_HERO) == true and IsUnitIllusion(u) == false // and types
endfunction
 
public function CreepContinueSingle takes unit creep returns nothing
    if GetOwningPlayer(creep) == udg_ClanDevilPlayer then
        call IssuePointOrderLoc(creep, "attack", udg_DevilNextHedef[GetUnitAbilityLevel(creep, CREEP_ABILITY_ID)])
    elseif GetOwningPlayer(creep) == udg_ClanReaperPlayer then
        call IssuePointOrderLoc(creep, "attack", udg_ReaperNextHedef[GetUnitAbilityLevel(creep, CREEP_ABILITY_ID)])
    endif
endfunction
 
///////////////////////////////////////////////////////////////
 
private function RemoveCreepAttackReveal takes nothing returns nothing // function T2I
    local timer t = GetExpiredTimer()
    local fogmodifier f = LoadFogModifierHandle(udg_hash, GetHandleId(t), 0)
    call FogModifierStop(f)
    call DestroyFogModifier(f)
    call FlushChildHashtable(udg_hash, GetHandleId(t))
    call PauseTimer(t)
    call DestroyTimer(t)
    set t = null
    set f = null
endfunction
 
private function CreepAttackReveal takes player p, real time returns nothing // function T3I
    local timer t = CreateTimer()
    local fogmodifier f = CreateFogModifierRadius(p, FOG_OF_WAR_VISIBLE, GetUnitX(GetAttacker()), GetUnitY(GetAttacker()), 128.00, true, false)
    call FogModifierStart(f)
    call SaveFogModifierHandle(udg_hash, GetHandleId(t), 0, f)
    call TimerStart(t, time, false, function RemoveCreepAttackReveal)
    set t = null
    set f = null
endfunction
 
 
function CreepAttackVision takes nothing returns boolean // function NVO
    if GetOwningPlayer(GetTriggerUnit()) == udg_ClanDevilPlayer then
        if IsUnitFogged(GetAttacker(), udg_DevilPlayersArray[1]) or IsUnitFogged(GetAttacker(), udg_ReaperPlayersArray[1]) then
            call CreepAttackReveal(udg_DevilPlayersArray[1], CREEP_ATTACK_FOG_REVEAL_TIME)
        endif
    elseif GetOwningPlayer(GetTriggerUnit()) == udg_ClanReaperPlayer then
        if IsUnitFogged(GetAttacker(), udg_DevilPlayersArray[1]) or IsUnitFogged(GetAttacker(), udg_ReaperPlayersArray[1]) then
            call CreepAttackReveal(udg_ReaperPlayersArray[1],CREEP_ATTACK_FOG_REVEAL_TIME)
        endif
    endif
    return false
endfunction
 
private function RegisterClanUnits takes nothing returns nothing // function NEO
    local unit centerUnit = GetTriggerUnit()
    local unit attacker = HeroAttacker[GetUnitUserData(centerUnit)]
    call SetUnitPosition(centerUnit, GetUnitX(centerUnit), GetUnitY(centerUnit))
    if attacker != null and GetWidgetLife(attacker) > 0 and IsUnitVisible(attacker, GetOwningPlayer(attacker)) then
        call IssueTargetOrder(centerUnit, "attack", attacker)
    else
        call DisableTrigger(GetTriggeringTrigger())
        call CreepContinueSingle(centerUnit)
        //call IssuePointOrderLoc(centerUnit, "attack", udg_CreepHedefler[GetUnitAbilityLevel(centerUnit, CREEP_ABILITY_ID)])
        call EnableTrigger(GetTriggeringTrigger())
    endif
    set centerUnit = null
    set attacker = null
endfunction
 
private function CheckClanUnits takes nothing returns boolean // function NGO
    if IsClanUnit(GetTriggerUnit()) then
        call RegisterClanUnits()
    endif
    return false
endfunction
 
private function CreepHeroAttack takes nothing returns nothing // function NHO
    local unit mover = GetTriggerUnit()
    local unit heroAttacker = HeroAttacker[GetUnitUserData(mover)]
    call SetUnitPosition(mover, GetUnitX(mover), GetUnitY(mover))
    //call BJDebugMsg("B")
    if heroAttacker != null and GetWidgetLife(heroAttacker) > 0 and IsUnitVisible(heroAttacker, GetOwningPlayer(heroAttacker)) then
        call IssueTargetOrder(mover, "attack", heroAttacker)
    else
        call DisableTrigger(GetTriggeringTrigger())
        call CreepContinueSingle(mover)
        //call IssuePointOrderLoc(mover, "attack", udg_[GetUnitAbilityLevel(mover, CREEP_ABILITY_ID)])
        call EnableTrigger(GetTriggeringTrigger())
    endif
    set mover = null
    set heroAttacker = null
endfunction
 
private function CheckOrder takes nothing returns boolean // function NZO
    if GetIssuedOrderId() == ORDER_ID_MOVE then
        //call BJDebugMsg("C")
        call CreepHeroAttack()
    endif
    return false
endfunction
 
function Alliance takes nothing returns nothing
    local integer x = 0
    local integer y = 0
 
    call SetAllyColorFilterState(0)
 
    loop
        exitwhen x>5
        call SetPlayerAlliance(Player(0),udg_DevilPlayersArray[x],ALLIANCE_PASSIVE,true)
        call SetPlayerAlliance(Player(0),udg_DevilPlayersArray[x],ALLIANCE_SHARED_SPELLS,true)
        call SetPlayerAlliance(Player(0),udg_ReaperPlayersArray[x],ALLIANCE_PASSIVE,false)
        call SetPlayerAlliance(Player(0),udg_ReaperPlayersArray[x],ALLIANCE_SHARED_SPELLS,false)
        set x=x+1
    endloop
 
 
    set x=0
    set y=0
    loop
        exitwhen x>5
        loop
            exitwhen y>5
            if(x!=y)then
                call SetPlayerAlliance(udg_DevilPlayersArray[x],udg_DevilPlayersArray[y],ALLIANCE_PASSIVE,true)
                call SetPlayerAlliance(udg_DevilPlayersArray[x],udg_DevilPlayersArray[y],ALLIANCE_HELP_REQUEST,true)
                call SetPlayerAlliance(udg_DevilPlayersArray[x],udg_DevilPlayersArray[y],ALLIANCE_HELP_RESPONSE,true)
                call SetPlayerAlliance(udg_DevilPlayersArray[x],udg_DevilPlayersArray[y],ALLIANCE_SHARED_XP,true)
                call SetPlayerAlliance(udg_DevilPlayersArray[x],udg_DevilPlayersArray[y],ALLIANCE_SHARED_SPELLS,true)
                call SetPlayerAlliance(udg_DevilPlayersArray[x],udg_DevilPlayersArray[y],ALLIANCE_SHARED_VISION,true)
                call SetPlayerAlliance(udg_DevilPlayersArray[x],udg_DevilPlayersArray[y],ALLIANCE_SHARED_CONTROL,false)
                call SetPlayerAlliance(udg_DevilPlayersArray[x],udg_DevilPlayersArray[y],ALLIANCE_SHARED_ADVANCED_CONTROL,false)
                call SetPlayerAlliance(udg_ReaperPlayersArray[x],udg_ReaperPlayersArray[y],ALLIANCE_PASSIVE,true)
                call SetPlayerAlliance(udg_ReaperPlayersArray[x],udg_ReaperPlayersArray[y],ALLIANCE_HELP_REQUEST,true)
                call SetPlayerAlliance(udg_ReaperPlayersArray[x],udg_ReaperPlayersArray[y],ALLIANCE_HELP_RESPONSE,true)
                call SetPlayerAlliance(udg_ReaperPlayersArray[x],udg_ReaperPlayersArray[y],ALLIANCE_SHARED_XP,true)
                call SetPlayerAlliance(udg_ReaperPlayersArray[x],udg_ReaperPlayersArray[y],ALLIANCE_SHARED_SPELLS,true)
                call SetPlayerAlliance(udg_ReaperPlayersArray[x],udg_ReaperPlayersArray[y],ALLIANCE_SHARED_VISION,true)
                call SetPlayerAlliance(udg_ReaperPlayersArray[x],udg_ReaperPlayersArray[y],ALLIANCE_SHARED_CONTROL,false)
                call SetPlayerAlliance(udg_ReaperPlayersArray[x],udg_ReaperPlayersArray[y],ALLIANCE_SHARED_ADVANCED_CONTROL,false)
                call SetPlayerAlliance(udg_DevilPlayersArray[x],udg_ReaperPlayersArray[y],ALLIANCE_PASSIVE,false)
                call SetPlayerAlliance(udg_DevilPlayersArray[x],udg_ReaperPlayersArray[y],ALLIANCE_HELP_REQUEST,false)
                call SetPlayerAlliance(udg_DevilPlayersArray[x],udg_ReaperPlayersArray[y],ALLIANCE_HELP_RESPONSE,false)
                call SetPlayerAlliance(udg_DevilPlayersArray[x],udg_ReaperPlayersArray[y],ALLIANCE_SHARED_XP,false)
                call SetPlayerAlliance(udg_DevilPlayersArray[x],udg_ReaperPlayersArray[y],ALLIANCE_SHARED_SPELLS,false)
                call SetPlayerAlliance(udg_DevilPlayersArray[x],udg_ReaperPlayersArray[y],ALLIANCE_SHARED_VISION,false)
                call SetPlayerAlliance(udg_DevilPlayersArray[x],udg_ReaperPlayersArray[y],ALLIANCE_SHARED_CONTROL,false)
                call SetPlayerAlliance(udg_DevilPlayersArray[x],udg_ReaperPlayersArray[y],ALLIANCE_SHARED_ADVANCED_CONTROL,false)
                call SetPlayerAlliance(udg_ReaperPlayersArray[x],udg_DevilPlayersArray[y],ALLIANCE_PASSIVE,false)
                call SetPlayerAlliance(udg_ReaperPlayersArray[x],udg_DevilPlayersArray[y],ALLIANCE_HELP_REQUEST,false)
                call SetPlayerAlliance(udg_ReaperPlayersArray[x],udg_DevilPlayersArray[y],ALLIANCE_HELP_RESPONSE,false)
                call SetPlayerAlliance(udg_ReaperPlayersArray[x],udg_DevilPlayersArray[y],ALLIANCE_SHARED_XP,false)
                call SetPlayerAlliance(udg_ReaperPlayersArray[x],udg_DevilPlayersArray[y],ALLIANCE_SHARED_SPELLS,false)
                call SetPlayerAlliance(udg_ReaperPlayersArray[x],udg_DevilPlayersArray[y],ALLIANCE_SHARED_VISION,false)
                call SetPlayerAlliance(udg_ReaperPlayersArray[x],udg_DevilPlayersArray[y],ALLIANCE_SHARED_CONTROL,false)
                call SetPlayerAlliance(udg_ReaperPlayersArray[x],udg_DevilPlayersArray[y],ALLIANCE_SHARED_ADVANCED_CONTROL,false)
            endif
            set y=y+1
        endloop
        set y=0
        set x=x+1
    endloop
endfunction
 
private function CreepsContinueWay takes nothing returns nothing //function MTO
    // set custom value to 0?
    call SetUnitUserData(GetEnumUnit(), 0)
    call CreepContinueSingle(GetEnumUnit())
    //call IssuePointOrderLoc(GetEnumUnit(), "attack", udg_CreepHedefler[GetUnitAbilityLevel(GetEnumUnit(), CREEP_ABILITY_ID)])
endfunction
 
private function CreepAttackTimerCallback takes nothing returns nothing // function MUO
    local integer id = GetHandleId(LoadUnitHandle(udg_hash, GetHandleId(GetExpiredTimer()), 2))
    local integer heroIndex = LoadInteger(udg_hash, id, 143)
    local group g = LoadGroupHandle(udg_hash, id, 144)
    set HeroAttacker[heroIndex] = null
    call ForGroup(g, function CreepsContinueWay)
    call GroupClear(g)
    set g = null
endfunction
 
private function FilterCreepAttack takes nothing returns boolean // function MPO
    local integer id = GetUnitTypeId(GetFilterUnit())
    if id == 0 then // other ids here
        return false
    endif
    if IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(udg_TempUnit)) and IsClanUnit(GetFilterUnit()) and GetUnitUserData(GetFilterUnit()) == 0 then // and custom value equal to 0
        return true
    endif
    return false
endfunction
 
private function CallbackCreepAttack takes nothing returns nothing //function MRO upper function's callback
    call IssueTargetOrder(GetEnumUnit(), "attack", udg_TempUnit)
    call GroupAddUnit(udg_TempGroup, GetEnumUnit())
    call SetUnitUserData(GetEnumUnit(), udg_TempInteger)
    // set custom value of picked unit to targetIndex
endfunction
 
private function CreepsContinueWay2 takes nothing returns nothing // function MQO
    if GetUnitCurrentOrder(GetEnumUnit()) == 0 and IsUnitInRange(GetEnumUnit(), udg_TempUnit, GetUnitAcquireRange(GetEnumUnit())) == false then
        call GroupRemoveUnit(udg_TempGroup, GetEnumUnit())
        // set custom value to 0?
        call SetUnitUserData(GetEnumUnit(), 0)
        call CreepContinueSingle(GetEnumUnit())
        //call IssuePointOrderLoc(GetEnumUnit(), "attack", udg_CreepHedefler[GetUnitAbilityLevel(GetEnumUnit(), CREEP_ABILITY_ID)])
    endif
endfunction
 
private function SetHeroAttacker takes unit target, unit starter returns nothing//function N1O
    local integer id = GetHandleId(target)
    local group g = LoadGroupHandle(udg_hash, id, 144)
    local integer targetIndex = LoadInteger(udg_hash, id, 143)
    local unit heroAttacker = HeroAttacker[targetIndex]
    local group g2 = CreateGroup()
 
    if heroAttacker != null and heroAttacker != starter then
        call ForGroup(g, function CreepsContinueWay)
        call GroupClear(g)
    endif
 
    set HeroAttacker[targetIndex] = starter
    set udg_TempGroup = g
    set udg_TempUnit = starter
    set udg_TempInteger = targetIndex
    call ForGroup(g, function CreepsContinueWay2)
    call GroupEnumUnitsInRange(g2, GetUnitX(target), GetUnitY(target), 500.00, Condition(function FilterCreepAttack))
    call ForGroup(g2, function CallbackCreepAttack)
    call TimerStart(LoadTimerHandle(udg_hash, GetHandleId(target), 141), 2.00, false, function CreepAttackTimerCallback)
 
    call DestroyGroup(g2)
    set g2 = null
    set g = null
    set heroAttacker = null
endfunction
 
function HeroOrderingTarget takes nothing returns boolean // function N2O
    local unit orderer = GetTriggerUnit()
    local unit orderTarget = GetOrderTargetUnit()
    local integer orderId = GetIssuedOrderId()
    local integer orderTargetIndex
    if IsRealHero(orderTarget) and (orderId != ORDER_ID_MOVE or orderId != ORDER_ID_SMART) and IsUnitEnemy(orderer, GetOwningPlayer(orderTarget)) and IsUnitVisible(orderer, GetOwningPlayer(orderTarget)) then
        set orderTargetIndex = LoadInteger(udg_hash, GetHandleId(orderTarget), 143)
        if HeroAttacker[orderTargetIndex] == null or HeroAttacker[orderTargetIndex] == orderTarget or GetWidgetLife(HeroAttacker[orderTargetIndex]) <= 0 then
            if orderTargetIndex != 0 then
                call SetHeroAttacker(orderTarget, orderer)
            endif
        endif
    endif
    return false
endfunction
 
function HeroGettingAttacked takes nothing returns boolean // function N4O
    local unit attacker = GetAttacker()
    local unit attackedHero = GetTriggerUnit()
    local integer attackedIndex
    if IsClanUnit(attacker) == false then
        set attackedIndex = LoadInteger(udg_hash, GetHandleId(attackedHero), 143)
        if HeroAttacker[attackedIndex] == null or HeroAttacker[attackedIndex] == attackedHero or GetWidgetLife(HeroAttacker[attackedIndex]) <= 0 then
            if attackedIndex != 0 then
                call SetHeroAttacker(attackedHero, attacker)
            endif
        endif
    endif
    set attacker = null
    set attackedHero = null
    return false
endfunction
 
private function HeroEnteredGame takes unit hero returns nothing // function N5O
    local group g
    local trigger tr
    local timer t
    local integer id = GetHandleId(hero)
    set HeroIndex = HeroIndex + 1
    call SaveBoolean(udg_hash, id, 142, true)
    call SaveInteger(udg_hash, id, 143, HeroIndex)
    call SaveGroupHandle(udg_hash, id, 144, CreateGroup())
 
    set tr = CreateTrigger()
    call TriggerRegisterUnitEvent(tr, hero, EVENT_UNIT_ISSUED_TARGET_ORDER)
    call TriggerAddCondition(tr, Condition(function HeroOrderingTarget))
 
    set tr = CreateTrigger()
    call TriggerRegisterUnitEvent(tr, hero, EVENT_UNIT_ATTACKED)
    call TriggerAddCondition(tr, Condition(function HeroGettingAttacked))
 
    set t = CreateTimer()
    call SaveTimerHandle(udg_hash, id, 141, t)
    call SaveUnitHandle(udg_hash, GetHandleId(t), 2, hero)
 
    set g = null
    set t = null
    set tr = null
endfunction
 
private function HeroEntersGame takes nothing returns boolean // function N6O
    if IsRealHero(GetTriggerUnit()) and LoadBoolean(udg_hash, GetHandleId(GetTriggerUnit()), 142) == false then
        call HeroEnteredGame(GetTriggerUnit())
    endif
    return false
endfunction
 
private function RemoveCreepGuardPos takes nothing returns boolean
    if IsClanUnit(GetTriggerUnit()) and GetUnitAbilityLevel(GetTriggerUnit(), CREEP_ABILITY_ID) > 0 then
        if GetOwningPlayer(GetTriggerUnit()) == udg_ClanDevilPlayer then
           // call BJDebugMsg("A")
            call SetUnitOwner(GetTriggerUnit(), Player(1), false)
            call SetUnitCreepGuard(GetTriggerUnit(), false)
            call RemoveGuardPosition(GetTriggerUnit())
            call SetUnitOwner(GetTriggerUnit(), udg_ClanDevilPlayer, false)
        else
            call SetUnitOwner(GetTriggerUnit(), Player(7), false)
            call SetUnitCreepGuard(GetTriggerUnit(), false)
            call RemoveGuardPosition(GetTriggerUnit())
            call SetUnitOwner(GetTriggerUnit(), udg_ClanReaperPlayer, false)
        endif
    endif
 
    return false
endfunction
 
private function Register takes nothing returns boolean // function NWO and BO1
    local trigger t
    local group g
    local unit u
    local region re
    set OBS = GetPlayerController(Player(0)) == MAP_CONTROL_USER or GetPlayerController(Player(6)) == MAP_CONTROL_USER
    if OBS then
        call SetAllyColorFilterState(0)
        call Alliance()
 
        set t = CreateTrigger()
        call TriggerRegisterPlayerUnitEvent(t, udg_ClanDevilPlayer, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, null)
        call TriggerRegisterPlayerUnitEvent(t, udg_ClanReaperPlayer, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, null)
        call TriggerAddCondition(t, Condition(function CheckOrder))
        //call BJDebugMsg("D")
     
        set t = CreateTrigger()
        set g = CreateGroup()
        call GroupEnumUnitsOfPlayer(g, udg_ClanDevilPlayer, null)
        loop
            set u = FirstOfGroup(g)
            exitwhen u == null
            call GroupRemoveUnit(g, u)
            if GetUnitAcquireRange(u) != 0 then
                call TriggerRegisterUnitInRange(t, u, 600.00, null)
            endif
        endloop
        call GroupClear(g)
     
        call GroupEnumUnitsOfPlayer(g, udg_ClanReaperPlayer, null)
        loop
            set u = FirstOfGroup(g)
            exitwhen u == null
            call GroupRemoveUnit(g, u)
            // WHY THIS IF STATEMENT HAS STRUCTURE PART???
            if GetUnitAcquireRange(u) != 0 and IsUnitType(u, UNIT_TYPE_STRUCTURE) then
                call TriggerRegisterUnitInRange(t, u, 600.00, null)
            endif
        endloop
        call GroupClear(g)
        call DestroyGroup(g)
        call TriggerAddCondition(t, Condition(function CheckClanUnits))
     
        set t = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ATTACKED)
        call TriggerAddCondition(t, Condition(function CreepAttackVision))
     
     
     
    endif
 
    set t = CreateTrigger()
    set re = CreateRegion()
    call RegionAddRect(re, GetWorldBounds())
    call TriggerRegisterEnterRegion(t, re, null)
    call TriggerAddCondition(t, Condition(function HeroEntersGame))
 
    //set t = CreateTrigger()
    //set re = CreateRegion()
    //call RegionAddRect(re, GetWorldBounds())
    //call TriggerRegisterEnterRegion(t, re, null)
    //call TriggerAddCondition(t, Condition(function RemoveCreepGuardPos))
  
    set udg_ClanDevilPlayers = GetPlayersAllies(udg_ClanDevilPlayer)
    call ForceRemovePlayer(udg_ClanDevilPlayers, udg_ClanDevilPlayer)
    set udg_ClanDevilPlayerCount = CountPlayersInForceBJ(udg_ClanDevilPlayers)
  
    set udg_ClanReaperPlayers = GetPlayersAllies(udg_ClanReaperPlayer)
    call ForceRemovePlayer(udg_ClanReaperPlayers, udg_ClanReaperPlayer)
    set udg_ClanReaperPlayerCount = CountPlayersInForceBJ(udg_ClanReaperPlayers)
 
    call DisableTrigger(GetTriggeringTrigger())
 
    set t = null
    set g = null
    set u = null
    set re = null
 
    return false
endfunction
 
private function Init takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterTimerEvent(t, 0.50, false)
    call TriggerAddCondition(t, Condition(function Register))
endfunction
 
endlibrary
 

Attachments

  • 1.png
    1.png
    1.1 MB · Views: 15
  • 2.png
    2.png
    1.4 MB · Views: 14
Level 39
Joined
Feb 27, 2007
Messages
5,016
I don’t think you can actively control this to avoid what the sorceresses do unless you are programming/triggering all NPC AI in your map. Best you can do is spam some attack move commands in the correct direction and hope they don’t get stuck attacking a hero.

Avoiding it would involve telling each individual sorceress which unit it should be attacking at any given time rather then letting the AI target finding just take over. A lot of work.
 
Level 17
Joined
Jun 2, 2009
Messages
1,139
Wait. My English is not perfect and i don't understand one thing. Trigger already working. But it has unexpected behaviour.


--- Detailed explanation ---

Player 1 (my ally) are spawning footmens for the attack it's enemy Player 7 (your ally)
I have a 1 Hero and fighting with your ally Player 7
You are coming with your archer and you are attacking units of my ally Player 1.
Player 1 units are fighting with Player 7 units
You and me are not attacking each other. We are just killing units of Player 1 and Player 7 with gold.

When you decide to attack my hero, my ally (player 1) units are saying "wow enemy hero attacking JFA, we have to protect him and attack the Pyrogasm" and attacking you. It works nice until here.

--- And here is the problem begins ---

When units of my ally attacking you, units of your ally are starting to attack me even though i didn't attack you
It has work like this; When i attack you, units of your ally starts to attack me.
When i will not attack you, they have to continue what they are do.

The Jass code i was shared in this post are works but with this flaw. Is it hard work?
 
Level 39
Joined
Feb 27, 2007
Messages
5,016
I could be wrong but it's my understanding that the Game AI is what's telling the Sorceresses to attack when they shouldn't be. That's not something you can intercept and interrupt, they're just changing targets according to their own internal AI when given attack-move order to a location. Because the heroes nearby are in combat, they join combat too on a priority target. (There may also be something about setting the targeting priority of heroes lower than other units but I'm not sure that would fix it either). If that's the case, there is no order actually given to the Sorceresses to attack, so you can't prevent it from being issued. If that's the case, then the only thing you can do would be to somehow disable the AI entirely (but I don't think that's possible either) or explicitly re-order them to attack move again repeatedly and hope they don't just stay on the same target.

I might be wrong, though.
 
Level 39
Joined
Feb 27, 2007
Messages
5,016
I'm not saying that it's happening because it's JASS and not a GUI trigger. I just mean that I don't think ANY of the trigger code is causing it, just the normal wc3 combat priority behavior.



Because someone else makes your triggers for you, it's very hard to give feedback to you specifically since you often don't understand or know why the trigger is the way that it is, let alone how to fix it. So effectively someone who doesn't understand the code is asking other people who don't understand the code to come in and attempt to understand this somewhat hard-to-follow code and figure out what's going on. Then come up with a solution, and explain that solution to you... the person who didn't understand the code in the first place... so that you can make the appropriate changes and fix the code.

Get the person who writes your code to come here and post about fixing this. Or you should directly ask them to fix the problems with their code. Ask them to explore the ill-formed monstrosity of code they have put together and stumble blindly into a solution. If they never see these threads or never read anything any of us have to say regarding code feedback, then they will never learn/change/improve anything and you're gonna keep having shitty code. If they come here and read our feedback, maybe they get better at writing code and you have fewer problems in the future.



That being said... honestly this is another of your triggers (made by one of your friend who works on the map with you, not you specifically... I know) where there is just so much wrong I don't have any actual inspiration to correct/edit/fix any of it because you're not the guy who writes these anyway so none of my suggestions will ever reach the person who does.

Shit like moving a unit repeatedly to the same location it's already at, checking to see if the units are invisible to the player that owns them, multiple functions that do almost exactly the same thing but with different names, hardcoded behavior that should have been moved to function arguments, a whole slew of parallel arrays that use a unit indexer to sync up but have no actual explanation of what data they hold or why or how it's to be used, incorrectly checking the life of a unit to see if that unit is dead. Triggers being made in the middle of other triggers only to run one time before being disabled?

Why are you checking for when AI units are ordered to move to a point? No player is controlling them. If they are ordered to move, it's because a trigger told them to so having an event go off to catch it right after you've just done it is simply unnecessary. That being said, whenever one of these units is ordered to move... the first thing the move-order-trigger does is immediately reorder it to attack its HeroAttacker[] target if it has one! Instead you could just order them to attack HeroAttacker when relevant. I just don't understand why this trigger was made this way.

What is this bologna with the TriggerRegisterUnitInRange() calls for all the Reaper/Devil player units on the map at the start (non-structure units only for Reapers but not Devils... why? who knows) You're making a unit in range event for units that are probably going to be removed from the map/die/move/who-knows-whatever-else and then relying on those events to catch units moving through the map and do the "issue order to attack HeroAttacker[]" stuff to them.

'A unit is attacked' event is bad and doesn't work how you want it to. You know this because we've talked about it before. Do not use it if you can avoid it.

Saving things in a hashtable using raw integers as child keys without explaining what that key is supposed to represent makes it extremely hard to figure out what parts of this code are for/what they do. For example, what does key "143" mean when loaded from the attacked hero in HeroGettingAttacked()?
 
Last edited:
Level 17
Joined
Jun 2, 2009
Messages
1,139
Ok i understand what do you mean. But the problem is, i don't understand anything about this jass. And i don't understand what do you mean in here?
Prove to me the JASS is causing this. I don't think it is.
When i turn off this Jass, nothing happens when i attack enemy hero (the units around the attacked hero continues whatever they doing)
When i turn on this jass, they are attacking me when i attack enemy hero.

Or at least you can help me about that. I can create this aggro system by myself as i did before. But what is happens when i delete this Jass? I don't know what is doing.
 
Last edited:
@Pyrogasm

I've managed to annotate most of the script as clearly as I could. Perhaps this updated script should help with finding the critical bug as described by JFAMAP.
JASS:
library CreepSystem initializer Init
 
globals
    private constant real CREEP_ATTACK_FOG_REVEAL_TIME = 1.00
    private constant integer CREEP_ABILITY_ID = 'A0E6'
    public integer HeroIndex = 0
    private boolean OBS = false
    private constant integer ORDER_ID_MOVE = 851986
    private constant integer ORDER_ID_SMART = 851971
    private constant integer ORDER_ID_ATTACK = 851983
    private unit array HeroAttacker
endglobals
// Looks like this checks out whether a unit belongs to a neutral (controller) player.
public function IsClanUnit takes unit u returns boolean
    return GetOwningPlayer(u) == udg_ClanDevilPlayer or GetOwningPlayer(u) == udg_ClanReaperPlayer
endfunction
 
// Checks whether the unit is a legit hero or not.
public function IsRealHero takes unit u returns boolean
    return IsUnitType(u, UNIT_TYPE_HERO) and (not IsUnitIllusion(u)) // and types
endfunction
 
// Looks like this function is supposed to be called periodically.
// Why is the index based on the level of CREEP_ABILITY_ID? Possibly multi-lanes?
public function CreepContinueSingle takes unit creep returns nothing
    if GetOwningPlayer(creep) == udg_ClanDevilPlayer then
        call IssuePointOrderLoc(creep, "attack", udg_DevilNextHedef[GetUnitAbilityLevel(creep, CREEP_ABILITY_ID)])
    elseif GetOwningPlayer(creep) == udg_ClanReaperPlayer then
        call IssuePointOrderLoc(creep, "attack", udg_ReaperNextHedef[GetUnitAbilityLevel(creep, CREEP_ABILITY_ID)])
    endif
endfunction
 
///////////////////////////////////////////////////////////////
//  ====================================
//      Hash map:
//      - {0} - fog modifier
//      - {2} - creep attack timer callback
//      - {141} - timer handle
//      - {142} - flag? (Possibly determining whether a Hero is already registered to the system, or not)
//      - {143} - hero index?
//      - {144} - attacking group?
//  ====================================
private function RemoveCreepAttackReveal takes nothing returns nothing // function T2I
    local timer t = GetExpiredTimer()
    local fogmodifier f = LoadFogModifierHandle(udg_hash, GetHandleId(t), 0)
    call FogModifierStop(f)
    call DestroyFogModifier(f)
    call FlushChildHashtable(udg_hash, GetHandleId(t))
    call PauseTimer(t)
    call DestroyTimer(t)
    set t = null
    set f = null
endfunction
//  Why is GetAttacker used directly in here? 
private function CreepAttackReveal takes player p, real time returns nothing // function T3I
    local timer t = CreateTimer()
    local fogmodifier f = CreateFogModifierRadius(p, FOG_OF_WAR_VISIBLE, GetUnitX(GetAttacker()), GetUnitY(GetAttacker()), 128.00, true, false)
    call FogModifierStart(f)
    call SaveFogModifierHandle(udg_hash, GetHandleId(t), 0, f)
    call TimerStart(t, time, false, function RemoveCreepAttackReveal)
    set t = null
    set f = null
endfunction
//  Wait, why try to replicate normal game behavior here?
//  By default, attacking units are revealed through fog of war.
function CreepAttackVision takes nothing returns boolean // function NVO
    //  Looks like we're looking out for neutral (controller) players only.
    if GetOwningPlayer(GetTriggerUnit()) == udg_ClanDevilPlayer then
        if IsUnitFogged(GetAttacker(), udg_DevilPlayersArray[1]) or IsUnitFogged(GetAttacker(), udg_ReaperPlayersArray[1]) then
            call CreepAttackReveal(udg_DevilPlayersArray[1], CREEP_ATTACK_FOG_REVEAL_TIME)
        endif
    elseif GetOwningPlayer(GetTriggerUnit()) == udg_ClanReaperPlayer then
        if IsUnitFogged(GetAttacker(), udg_DevilPlayersArray[1]) or IsUnitFogged(GetAttacker(), udg_ReaperPlayersArray[1]) then
            call CreepAttackReveal(udg_ReaperPlayersArray[1],CREEP_ATTACK_FOG_REVEAL_TIME)
        endif
    endif
    return false
endfunction
//  Why not make this function take a unit as a parameter?
//  Based on how CheckClanUnits is written, I think making it
//  take a unit parameter would make it appear to be more logically consistent,
//  as well as not having to worry about nulling said parameter/
private function RegisterClanUnits takes nothing returns nothing // function NEO
    local unit centerUnit = GetTriggerUnit()
    local unit attacker = HeroAttacker[GetUnitUserData(centerUnit)]
    //  What's up with this? If this function runs whenever a unit enters the map,
    //  there'd be no need to do something like this.
    //  If the goal is to interrupt the unit, why not just issue a stop order immediately?
    call SetUnitPosition(centerUnit, GetUnitX(centerUnit), GetUnitY(centerUnit))
    if attacker != null and GetWidgetLife(attacker) > 0 and IsUnitVisible(attacker, GetOwningPlayer(attacker)) then
        call IssueTargetOrder(centerUnit, "attack", attacker)
    else
        call DisableTrigger(GetTriggeringTrigger())
        call CreepContinueSingle(centerUnit)
        //call IssuePointOrderLoc(centerUnit, "attack", udg_CreepHedefler[GetUnitAbilityLevel(centerUnit, CREEP_ABILITY_ID)])
        call EnableTrigger(GetTriggeringTrigger())
    endif
    set centerUnit = null
    set attacker = null
endfunction
private function CheckClanUnits takes nothing returns boolean // function NGO
    if IsClanUnit(GetTriggerUnit()) then
        call RegisterClanUnits()
    endif
    return false
endfunction
 
//  CreepHeroAttack appears to be an EXACT clone of RegisterClanUnits
private function CreepHeroAttack takes nothing returns nothing // function NHO
    local unit mover = GetTriggerUnit()
    local unit heroAttacker = HeroAttacker[GetUnitUserData(mover)]
    call SetUnitPosition(mover, GetUnitX(mover), GetUnitY(mover))
    //call BJDebugMsg("B")
    if heroAttacker != null and GetWidgetLife(heroAttacker) > 0 and IsUnitVisible(heroAttacker, GetOwningPlayer(heroAttacker)) then
        call IssueTargetOrder(mover, "attack", heroAttacker)
    else
        call DisableTrigger(GetTriggeringTrigger())
        call CreepContinueSingle(mover)
        //call IssuePointOrderLoc(mover, "attack", udg_[GetUnitAbilityLevel(mover, CREEP_ABILITY_ID)])
        call EnableTrigger(GetTriggeringTrigger())
    endif
    set mover = null
    set heroAttacker = null
endfunction
//  Just a usual check order trigger condition callback.
private function CheckOrder takes nothing returns boolean // function NZO
    if GetIssuedOrderId() == ORDER_ID_MOVE then
        //call BJDebugMsg("C")
        call CreepHeroAttack()
    endif
    return false
endfunction
/*
-  Newly introduced function.
-  Please bring up code reusability to whoever wrote this next time.
private function DefineAllianceState takes player p1, player p2, boolean flag returns nothing
    call SetPlayerAlliance(p1, p2, ALLIANCE_PASSIVE, flag)
    call SetPlayerAlliance(p1, p2, ALLIANCE_HELP_REQUEST, flag)
    call SetPlayerAlliance(p1, p2, ALLIANCE_HELP_RESPONSE, flag)
    call SetPlayerAlliance(p1, p2, ALLIANCE_SHARED_XP, flag)
    call SetPlayerAlliance(p1, p2, ALLIANCE_SHARED_SPELLS, flag)
    call SetPlayerAlliance(p1, p2, ALLIANCE_SHARED_VISION, flag)
    call SetPlayerAlliance(p1, p2, ALLIANCE_SHARED_CONTROL, false)
    call SetPlayerAlliance(p1, p2, ALLIANCE_SHARED_ADVANCED_CONTROL, false)
endfunction
*/
function Alliance takes nothing returns nothing
    local integer x = 0
    local integer y = 0
 
    call SetAllyColorFilterState(0)
    loop
        exitwhen x>5
        call SetPlayerAlliance(Player(0),udg_DevilPlayersArray[x],ALLIANCE_PASSIVE,true)
        call SetPlayerAlliance(Player(0),udg_DevilPlayersArray[x],ALLIANCE_SHARED_SPELLS,true)
        call SetPlayerAlliance(Player(0),udg_ReaperPlayersArray[x],ALLIANCE_PASSIVE,false)
        call SetPlayerAlliance(Player(0),udg_ReaperPlayersArray[x],ALLIANCE_SHARED_SPELLS,false)
        set x=x+1
    endloop
    // Looks like this nested loop block isn't fully optimized.
    set x=0
    set y=0
    loop
        exitwhen x>5
        //set y=x+1 - Added this line, so that the conditional statement nested within will
        //            never have to be evaluated.
        loop
            exitwhen y>5
            //  Holy moly, looks like the code here has a LOT of redundant sections.
            //  if(x!=y)then
            // Commented out a newly introduced function
            // call DefineAllianceState(udg_DevilPlayersArray[x], udg_DevilPlayersArray[y], true)
            // call DefineAllianceState(udg_ReaperPlayersArray[x], udg_ReaperPlayersArray[y], true)
            // call DefineAllianceState(udg_DevilPlayersArray[x], udg_ReaperPlayersArray[y], false)
            // call DefineAllianceState(udg_ReaperPlayersArray[x], udg_DevilPlayersArray[y], false)
            call SetPlayerAlliance(udg_DevilPlayersArray[x],udg_DevilPlayersArray[y],ALLIANCE_PASSIVE,true)
            call SetPlayerAlliance(udg_DevilPlayersArray[x],udg_DevilPlayersArray[y],ALLIANCE_HELP_REQUEST,true)
            call SetPlayerAlliance(udg_DevilPlayersArray[x],udg_DevilPlayersArray[y],ALLIANCE_HELP_RESPONSE,true)
            call SetPlayerAlliance(udg_DevilPlayersArray[x],udg_DevilPlayersArray[y],ALLIANCE_SHARED_XP,true)
            call SetPlayerAlliance(udg_DevilPlayersArray[x],udg_DevilPlayersArray[y],ALLIANCE_SHARED_SPELLS,true)
            call SetPlayerAlliance(udg_DevilPlayersArray[x],udg_DevilPlayersArray[y],ALLIANCE_SHARED_VISION,true)
            call SetPlayerAlliance(udg_DevilPlayersArray[x],udg_DevilPlayersArray[y],ALLIANCE_SHARED_CONTROL,false)
            call SetPlayerAlliance(udg_DevilPlayersArray[x],udg_DevilPlayersArray[y],ALLIANCE_SHARED_ADVANCED_CONTROL,false)
            call SetPlayerAlliance(udg_ReaperPlayersArray[x],udg_ReaperPlayersArray[y],ALLIANCE_PASSIVE,true)
            call SetPlayerAlliance(udg_ReaperPlayersArray[x],udg_ReaperPlayersArray[y],ALLIANCE_HELP_REQUEST,true)
            call SetPlayerAlliance(udg_ReaperPlayersArray[x],udg_ReaperPlayersArray[y],ALLIANCE_HELP_RESPONSE,true)
            call SetPlayerAlliance(udg_ReaperPlayersArray[x],udg_ReaperPlayersArray[y],ALLIANCE_SHARED_XP,true)
            call SetPlayerAlliance(udg_ReaperPlayersArray[x],udg_ReaperPlayersArray[y],ALLIANCE_SHARED_SPELLS,true)
            call SetPlayerAlliance(udg_ReaperPlayersArray[x],udg_ReaperPlayersArray[y],ALLIANCE_SHARED_VISION,true)
            call SetPlayerAlliance(udg_ReaperPlayersArray[x],udg_ReaperPlayersArray[y],ALLIANCE_SHARED_CONTROL,false)
            call SetPlayerAlliance(udg_ReaperPlayersArray[x],udg_ReaperPlayersArray[y],ALLIANCE_SHARED_ADVANCED_CONTROL,false)
            call SetPlayerAlliance(udg_DevilPlayersArray[x],udg_ReaperPlayersArray[y],ALLIANCE_PASSIVE,false)
            call SetPlayerAlliance(udg_DevilPlayersArray[x],udg_ReaperPlayersArray[y],ALLIANCE_HELP_REQUEST,false)
            call SetPlayerAlliance(udg_DevilPlayersArray[x],udg_ReaperPlayersArray[y],ALLIANCE_HELP_RESPONSE,false)
            call SetPlayerAlliance(udg_DevilPlayersArray[x],udg_ReaperPlayersArray[y],ALLIANCE_SHARED_XP,false)
            call SetPlayerAlliance(udg_DevilPlayersArray[x],udg_ReaperPlayersArray[y],ALLIANCE_SHARED_SPELLS,false)
            call SetPlayerAlliance(udg_DevilPlayersArray[x],udg_ReaperPlayersArray[y],ALLIANCE_SHARED_VISION,false)
            call SetPlayerAlliance(udg_DevilPlayersArray[x],udg_ReaperPlayersArray[y],ALLIANCE_SHARED_CONTROL,false)
            call SetPlayerAlliance(udg_DevilPlayersArray[x],udg_ReaperPlayersArray[y],ALLIANCE_SHARED_ADVANCED_CONTROL,false)
            call SetPlayerAlliance(udg_ReaperPlayersArray[x],udg_DevilPlayersArray[y],ALLIANCE_PASSIVE,false)
            call SetPlayerAlliance(udg_ReaperPlayersArray[x],udg_DevilPlayersArray[y],ALLIANCE_HELP_REQUEST,false)
            call SetPlayerAlliance(udg_ReaperPlayersArray[x],udg_DevilPlayersArray[y],ALLIANCE_HELP_RESPONSE,false)
            call SetPlayerAlliance(udg_ReaperPlayersArray[x],udg_DevilPlayersArray[y],ALLIANCE_SHARED_XP,false)
            call SetPlayerAlliance(udg_ReaperPlayersArray[x],udg_DevilPlayersArray[y],ALLIANCE_SHARED_SPELLS,false)
            call SetPlayerAlliance(udg_ReaperPlayersArray[x],udg_DevilPlayersArray[y],ALLIANCE_SHARED_VISION,false)
            call SetPlayerAlliance(udg_ReaperPlayersArray[x],udg_DevilPlayersArray[y],ALLIANCE_SHARED_CONTROL,false)
            call SetPlayerAlliance(udg_ReaperPlayersArray[x],udg_DevilPlayersArray[y],ALLIANCE_SHARED_ADVANCED_CONTROL,false)
            //  endif
            set y=y+1
        endloop
        // set y=0
        set x=x+1
    endloop
endfunction
 
private function CreepsContinueWay takes nothing returns nothing //function MTO
    // set custom value to 0?
    //  Hold on, why must this modify user data?
    call SetUnitUserData(GetEnumUnit(), 0)
    call CreepContinueSingle(GetEnumUnit())
    //call IssuePointOrderLoc(GetEnumUnit(), "attack", udg_CreepHedefler[GetUnitAbilityLevel(GetEnumUnit(), CREEP_ABILITY_ID)])
endfunction
private function CreepAttackTimerCallback takes nothing returns nothing // function MUO
    local integer id = GetHandleId(LoadUnitHandle(udg_hash, GetHandleId(GetExpiredTimer()), 2))
    local integer heroIndex = LoadInteger(udg_hash, id, 143)
    local group g = LoadGroupHandle(udg_hash, id, 144)
    set HeroAttacker[heroIndex] = null
    //  This feels .. temporary?
    //  Based on prior assumptions of timer callbacks, I believe this
    //  might be one of the roots behind the problem.
    call ForGroup(g, function CreepsContinueWay)
    call GroupClear(g)
    set g = null
endfunction
//  It'd be best to just store GetFilterUnit into a local variable, based on its usage here.
private function FilterCreepAttack takes nothing returns boolean // function MPO
    local integer id = GetUnitTypeId(GetFilterUnit())
    //  Just return the boolean result directly
    //  return (id != 0) and IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(udg_TempUnit)) and /*
    //       */ IsClanUnit(GetFilterUnit()) and (GetUnitUserData(GetFilterUnit()) == 0)
    if id == 0 then // other ids here
        return false
    endif
    if IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(udg_TempUnit)) and IsClanUnit(GetFilterUnit()) and GetUnitUserData(GetFilterUnit()) == 0 then // and custom value equal to 0
        return true
    endif
    return false
endfunction
 
//  Based on how SetUnitUserData is used, it might be for mapping out the
//  target of the enumerated unit GetEnumUnit() for ease of access in
//  subsequent calls to GetUnitUserData
private function CallbackCreepAttack takes nothing returns nothing //function MRO upper function's callback
    call IssueTargetOrder(GetEnumUnit(), "attack", udg_TempUnit)
    call GroupAddUnit(udg_TempGroup, GetEnumUnit())
    call SetUnitUserData(GetEnumUnit(), udg_TempInteger)
    // set custom value of picked unit to targetIndex
endfunction
private function CreepsContinueWay2 takes nothing returns nothing // function MQO
    if GetUnitCurrentOrder(GetEnumUnit()) == 0 and (not IsUnitInRange(GetEnumUnit(), udg_TempUnit, GetUnitAcquireRange(GetEnumUnit()))) then
        call GroupRemoveUnit(udg_TempGroup, GetEnumUnit())
        // set custom value to 0?
        call SetUnitUserData(GetEnumUnit(), 0)
        call CreepContinueSingle(GetEnumUnit())
        //call IssuePointOrderLoc(GetEnumUnit(), "attack", udg_CreepHedefler[GetUnitAbilityLevel(GetEnumUnit(), CREEP_ABILITY_ID)])
    endif
endfunction
 
private function SetHeroAttacker takes unit target, unit starter returns nothing//function N1O
    local integer id = GetHandleId(target)
    local group g = LoadGroupHandle(udg_hash, id, 144)
    local integer targetIndex = LoadInteger(udg_hash, id, 143)
    local unit heroAttacker = HeroAttacker[targetIndex]
    local group g2 = CreateGroup()
 
    if heroAttacker != null and heroAttacker != starter then
        call ForGroup(g, function CreepsContinueWay)
        call GroupClear(g)
    endif
 
    //  Why are GUI temp variables used here? If memory space is not an issue,
    //  why not make your own temp variables directly in vJASS?
    set HeroAttacker[targetIndex] = starter
    set udg_TempGroup = g
    set udg_TempUnit = starter
    set udg_TempInteger = targetIndex
    call ForGroup(g, function CreepsContinueWay2)
    //  What's this magic float doing here? (500.0)
    //  Shouldn't that be documented?
    call GroupEnumUnitsInRange(g2, GetUnitX(target), GetUnitY(target), 500.00, Condition(function FilterCreepAttack))
    call ForGroup(g2, function CallbackCreepAttack)
    call TimerStart(LoadTimerHandle(udg_hash, GetHandleId(target), 141), 2.00, false, function CreepAttackTimerCallback)
 
    call DestroyGroup(g2)
    set g2 = null
    set g = null
    set heroAttacker = null
endfunction
 
function HeroOrderingTarget takes nothing returns boolean // function N2O
    local unit orderer = GetTriggerUnit()
    local unit orderTarget = GetOrderTargetUnit()
    local integer orderId = GetIssuedOrderId()
    local integer orderTargetIndex
    if IsRealHero(orderTarget) and (orderId != ORDER_ID_MOVE or orderId != ORDER_ID_SMART) and IsUnitEnemy(orderer, GetOwningPlayer(orderTarget)) and IsUnitVisible(orderer, GetOwningPlayer(orderTarget)) then
        set orderTargetIndex = LoadInteger(udg_hash, GetHandleId(orderTarget), 143)
        if HeroAttacker[orderTargetIndex] == null or HeroAttacker[orderTargetIndex] == orderTarget or GetWidgetLife(HeroAttacker[orderTargetIndex]) <= 0 then
            if orderTargetIndex != 0 then
                call SetHeroAttacker(orderTarget, orderer)
            endif
        endif
    endif
    //  Forgot to properly dereference local unit variables 
    //  set orderer = null
    //  set orderTarget = null
    return false
endfunction
 
function HeroGettingAttacked takes nothing returns boolean // function N4O
    local unit attacker = GetAttacker()
    local unit attackedHero = GetTriggerUnit()
    local integer attackedIndex
    if IsClanUnit(attacker) == false then
        set attackedIndex = LoadInteger(udg_hash, GetHandleId(attackedHero), 143)
        if HeroAttacker[attackedIndex] == null or HeroAttacker[attackedIndex] == attackedHero or GetWidgetLife(HeroAttacker[attackedIndex]) <= 0 then
            if attackedIndex != 0 then
                call SetHeroAttacker(attackedHero, attacker)
            endif
        endif
    endif
    set attacker = null
    set attackedHero = null
    return false
endfunction
//  WATCH OUT for save game and load game events. From what I recall,
//  v.1.30 or v.1.31 might cause the triggers below to not respond at all
//  after reloading the map.
private function HeroEnteredGame takes unit hero returns nothing // function N5O
    local group g
    local trigger tr
    local timer t
    local integer id = GetHandleId(hero)
    set HeroIndex = HeroIndex + 1
    call SaveBoolean(udg_hash, id, 142, true)
    call SaveInteger(udg_hash, id, 143, HeroIndex)
    call SaveGroupHandle(udg_hash, id, 144, CreateGroup())
 
    set tr = CreateTrigger()
    call TriggerRegisterUnitEvent(tr, hero, EVENT_UNIT_ISSUED_TARGET_ORDER)
    call TriggerAddCondition(tr, Condition(function HeroOrderingTarget))
 
    set tr = CreateTrigger()
    call TriggerRegisterUnitEvent(tr, hero, EVENT_UNIT_ATTACKED)
    call TriggerAddCondition(tr, Condition(function HeroGettingAttacked))
 
    set t = CreateTimer()
    call SaveTimerHandle(udg_hash, id, 141, t)
    call SaveUnitHandle(udg_hash, GetHandleId(t), 2, hero)
 
    set g = null
    set t = null
    set tr = null
endfunction
//  Runs whenever a unit (a Hero in particular) enters a map.
//  On another note, why not forego the use of SetUnitUserData
//  and use a Unit Indexer here, which provides the same event
//  for detecting unit creation?
private function HeroEntersGame takes nothing returns boolean // function N6O
    // I'd go for HaveSavedBoolean here instead of LoadBoolean.
    if IsRealHero(GetTriggerUnit()) and LoadBoolean(udg_hash, GetHandleId(GetTriggerUnit()), 142) == false then
        call HeroEnteredGame(GetTriggerUnit())
    endif
    return false
endfunction
 
private function RemoveCreepGuardPos takes nothing returns boolean
    local unit creep    = GetTriggerUnit()
    if (not IsClanUnit(creep)) or (GetUnitAbilityLevel(creep, CREEP_ABILITY_ID) == 0) then
        set creep       = null
        return false
    endif
    if GetOwningPlayer(creep) == udg_ClanDevilPlayer then
        //  What's up with Player 2 and Player 8? (Player(n) refers to Player {n + 1} in-game)
        call SetUnitOwner(creep, Player(1), false)
        call SetUnitCreepGuard(creep, false)
        call RemoveGuardPosition(creep)
        call SetUnitOwner(creep, udg_ClanDevilPlayer, false)
    else
        call SetUnitOwner(creep, Player(7), false)
        call SetUnitCreepGuard(creep, false)
        call RemoveGuardPosition(creep)
        call SetUnitOwner(creep, udg_ClanReaperPlayer, false)
    endif
    set creep           = null
    return false
endfunction

// Not to worry, this function will run once, and only once.
private function Register takes nothing returns boolean // function NWO and BO1
    local trigger t
    local group g
    local unit u
    local region re
    set OBS = GetPlayerController(Player(0)) == MAP_CONTROL_USER or GetPlayerController(Player(6)) == MAP_CONTROL_USER
    if OBS then
        call SetAllyColorFilterState(0)
        call Alliance()
 
        set t = CreateTrigger()
        call TriggerRegisterPlayerUnitEvent(t, udg_ClanDevilPlayer, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, null)
        call TriggerRegisterPlayerUnitEvent(t, udg_ClanReaperPlayer, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, null)
        call TriggerAddCondition(t, Condition(function CheckOrder))
        //call BJDebugMsg("D")
     
        //  It appears that this trigger will only register pre-placed units.
        //  What's up with that?
        //  Why refer to a static 600.00 unit range?
        set t = CreateTrigger()
        set g = CreateGroup()
        call GroupEnumUnitsOfPlayer(g, udg_ClanDevilPlayer, null)
        loop
            set u = FirstOfGroup(g)
            exitwhen u == null
            call GroupRemoveUnit(g, u)
            if GetUnitAcquireRange(u) != 0 then
                call TriggerRegisterUnitInRange(t, u, 600.00, null)
            endif
        endloop
        call GroupClear(g)
     
        call GroupEnumUnitsOfPlayer(g, udg_ClanReaperPlayer, null)
        loop
            set u = FirstOfGroup(g)
            exitwhen u == null
            call GroupRemoveUnit(g, u)
            // WHY THIS IF STATEMENT HAS STRUCTURE PART???
            // One part I can agree with you.
            if GetUnitAcquireRange(u) != 0 and IsUnitType(u, UNIT_TYPE_STRUCTURE) then
                call TriggerRegisterUnitInRange(t, u, 600.00, null)
            endif
        endloop
        call GroupClear(g)
        call DestroyGroup(g)
        call TriggerAddCondition(t, Condition(function CheckClanUnits))
     
        set t = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ATTACKED)
        call TriggerAddCondition(t, Condition(function CreepAttackVision))
    endif
    //  The detection of unit creation should be outsourced to a Unit Indexer.
    set t = CreateTrigger()
    set re = CreateRegion()
    call RegionAddRect(re, GetWorldBounds())
    call TriggerRegisterEnterRegion(t, re, null)
    call TriggerAddCondition(t, Condition(function HeroEntersGame))
 
    //set t = CreateTrigger()
    //set re = CreateRegion()
    //call RegionAddRect(re, GetWorldBounds())
    //call TriggerRegisterEnterRegion(t, re, null)
    //call TriggerAddCondition(t, Condition(function RemoveCreepGuardPos))
  
    set udg_ClanDevilPlayers = GetPlayersAllies(udg_ClanDevilPlayer)
    call ForceRemovePlayer(udg_ClanDevilPlayers, udg_ClanDevilPlayer)
    set udg_ClanDevilPlayerCount = CountPlayersInForceBJ(udg_ClanDevilPlayers)
  
    set udg_ClanReaperPlayers = GetPlayersAllies(udg_ClanReaperPlayer)
    call ForceRemovePlayer(udg_ClanReaperPlayers, udg_ClanReaperPlayer)
    set udg_ClanReaperPlayerCount = CountPlayersInForceBJ(udg_ClanReaperPlayers)
    call DisableTrigger(GetTriggeringTrigger())
 
    set t = null
    set g = null
    set u = null
    set re = null
 
    return false
endfunction

//  Okay, this one looks normal, except the part where it initializes 0.5 seconds after the
//  game officially starts.
//  What happens if the events are initialized during map initialization? Will the system
//  break? Why not use a timer to call Register function after the delay? Why not call it
//  directly?
private function Init takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterTimerEvent(t, 0.50, false)
    call TriggerAddCondition(t, Condition(function Register))
endfunction
 
endlibrary
 
Level 17
Joined
Jun 2, 2009
Messages
1,139
I have a no idea what are you talking about you two :D just tell me that. What is that Jass does? If it is about this aggro thing i will remove this Jass and create this system by myself. Is it includes something important? It looks bit of long for an aggro system.
 
It's basically a convoluted process of forcing the enemy (neutral controlled) units to attack the assaulting Hero. Looking back at the initial situation, I might have a lingering suspicion that this system is actually working as intended, but to confirm it, the following function has to be debugged.

JASS:
// This function has been registered to a trigger that runs whenever a Hero is being attacked.
function HeroGettingAttacked takes nothing returns boolean // function N4O
    local unit attacker = GetAttacker()
    local unit attackedHero = GetTriggerUnit()
    local integer attackedIndex
    if IsClanUnit(attacker) == false then
        set attackedIndex = LoadInteger(udg_hash, GetHandleId(attackedHero), 143)
        if HeroAttacker[attackedIndex] == null or HeroAttacker[attackedIndex] == attackedHero or GetWidgetLife(HeroAttacker[attackedIndex]) <= 0 then
            if attackedIndex != 0 then
                call SetHeroAttacker(attackedHero, attacker)
            endif
        endif
    endif
    set attacker = null
    set attackedHero = null
    return false
endfunction

Since the two Archmagi (test Heroes) have the same attack range, it would stand to reason that the EVENT_UNIT_ATTACKED unit event will run for both of them, drawing creep aggro. Still, it would be best to confirm it by debugging the function above.
 
Status
Not open for further replies.
Top