• 🏆 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] Just Another( Or not ) Struct Question

Status
Not open for further replies.
Level 18
Joined
Jan 21, 2006
Messages
2,552
In that case you'll need a function to determine what bonus should be applied to an enumerated unit.

JASS:
function GetUnitAuraBonus takes unit onSubject returns integer
    // Returns the integer value of the bonus that should be
    // applied to the "onSubject" unit using the hero array.
    local integer i = 0
    local integer m = 0
    loop
        exitwhen i == HeroWithAuraCount
        if IsUnitInRange(HeroWithAura[i], onSubject, LONG_RANGE) then
            // In order to optimize things a bit, the following code should
            // only be executed if the enumerated unit is within range of
            // a hero's aura. If it isn't, then immediately progress to
            // the next without determining the bonus.
            if IsUnitInRange(HeroWithAura[i], onSubject, CLOSE_RANGE) then
                if CLOSE_RANGE_BONUS > m then
                    set m = CLOSE_RANGE_BONUS
                endif
            elseif IsUnitInRange(HeroWithAura[i], onSubject, MEDIUM_RANGE) then
                if MEDIUM_RANGE_BONUS > m then
                    set m = MEDIUM_RANGE_BONUS
                endif
            else
                if LONG_RANGE_BONUS > m then
                    set m = LONG_RANGE_BONUS
                endif
            endif
        endif
        set i = i + 1
    endloop
    return m
endfunction

I just read your post about quitting... I can keep helping you if you like I'm not trying to get you to quit, I'm trying to get you to do something more on your level. If you're just giving up because it's too complicated, then don't, but if it's because you're not learning anything then you should. So far it doesn't sound like you're really understanding what's going on here.

Anyways, once you determine what a unit's aura-bonus will be then you can apply the integer bonus and save it in a hash-table using the unit's GetHandleId() value. From here you'll have to add the unit to a group that is iterated through on a periodic interval, that removes the previously attached buff and applies a new one.

JASS:
globals
    hashtable storeTable = InitHashtable()
endglobals

function ApplyBonus takes unit whichUnit, integer bonus returns nothing
    if HaveSavedInteger(storeTable, GetHandleId(whichUnit), 1) then
        call SetHeroStr(whichUnit, GetHeroStr(whichUnit)-LoadInteger(storeTable, GetHandleId(whichUnit), 1))
        if bonus == 0 then
            call RemoveSavedInteger(storeTable, GetHandleId(whichUnit), 1)
        else
            call SaveInteger(storeTable, GetHandleId(whichUnit), bonus)
        endif
    else
        if bonus != 0 then
            call SaveInteger(storeTable, GetHandleId(whichUnit), 1, bonus)
        endif
    endif
    call SetHeroStr(whichUnit, GetHeroStr(whichUnit) + bonus)
endfunction

So each time you use ApplyBonus in this case it will check to see if the unit is under the effects of a bonus already. If it is not under the effects of a bonus, then it will assign it to a hash-table value and then increase it's strength. If it is already under the effects of the aura, then it will need to refer to the assigned hash-table value and remove that saved amount of strength. Once this is done it will be able to apply the new buff. By the way, notice that if the unit does not have any bonuses and a 0 bonus is applied it won't do anything.

Now the hard part is ensuring that all necessary units are constantly having bonuses applied so that it refreshes the value of the bonus. This part requires the use of a unit-group (preferably a global/static one).

JASS:
private function doLoop takes nothing returns nothing
    set tempGrp = CreateGroup()
    call GroupEnumUnitsInRect(tempGrp, GetWorldBounds(), Filter(function hasBuff))
    // Enumerates all units after the conditions
    call ForGroup(tempGrp, function Data.ForGroupFuncs)
    // Picks all units in the Group, and does these actions.
endfunction

Going through this, it won't work. You're creating the unit-group in the doLoop iteration, which is not what I showed you to do. In my example I was only creating it once, when it was declared. The way you have it set up it will leak a unit-group each timer iteration, which is very bad, so avoid that. All you have to do is move set tempGrp = CreateGroup() to the global declarations or to an initialization function/method.

Anyways, using this same group you can do what I was talking about before. Just look.

JASS:
private function doLoopPre takes nothing returns nothing
    call ApplyBonus(GetEnumUnit(), GetUnitAuraBonus(GetEnumUnit()))
endfunction

private function doLoop takes nothing returns nothing

    call ForGroup(tempGrp, function doLoopPre)

    call GroupEnumUnitsInRect(tempGrp, GetWorldBounds(), Filter(function hasBuff))
    call ForGroup(tempGrp, function Data.ForGroupFuncs)    
    // The "tempGrp" unit-group will not be empty, it will have every unit in the
    // map with the aura buff. This is useful because we can use this group upon
    // the next timer iteration to apply the bonus function.

endfunction

Now, it's not that complicated.

The result is something like this. I just typed it up quick in the World Editor. It should compile fine (not sure if it functions 100% though). I figured I would post it since in the code above I do not have all the right parameters, such as the second boolean parameter in GetHeroStr.

JASS:
scope StrengthAura initializer init

    globals
    
        public      constant integer        AURA_ABIL_ID        = 'A000'
        public      constant integer        AURA_BUFF_ID        = 'B000'
    
        public      constant real           LONG_RANGE          = 600
        public      constant integer        LONG_RANGE_BONUS    = 3
        
        public      constant real           MEDIUM_RANGE        = 400
        public      constant integer        MEDIUM_RANGE_BONUS  = 6
        
        public      constant real           CLOSE_RANGE         = 200
        public      constant integer        CLOSE_RANGE_BONUS   = 9
    
        private     hashtable               table               = InitHashtable()
        private     unit array              heroes
        private     integer                 count               = 0
        private     group                   tmpGrp              = CreateGroup()
    
    endglobals


    private function ApplyBonus takes unit u, integer bonus returns nothing
        if HaveSavedInteger(table, GetHandleId(u), 1) then
            call SetHeroStr(u, GetHeroStr(u, true)-LoadInteger(table, GetHandleId(u), 1), false)
            if bonus == 0 then
                call RemoveSavedInteger(table, GetHandleId(u), 1)
            else
                call SaveInteger(table, GetHandleId(u), 1, bonus)
            endif
        else
            if bonus != 0 then
                call SaveInteger(table, GetHandleId(u), 1, bonus)
            endif
        endif
        call SetHeroStr(u, GetHeroStr(u, true)+bonus, false)
    endfunction
    
    private function GetUnitAuraBonus takes unit u returns integer
        local integer i = 0
        local integer m = 0
        loop
            exitwhen i == count
            if IsUnitInRange(u, heroes[i], LONG_RANGE) then
            
                if IsUnitInRange(u, heroes[i], CLOSE_RANGE) then
                    if CLOSE_RANGE_BONUS > m then
                        set m = CLOSE_RANGE_BONUS
                    endif
                elseif IsUnitInRange(u, heroes[i], MEDIUM_RANGE) then
                    if MEDIUM_RANGE_BONUS > m then
                        set m = MEDIUM_RANGE_BONUS
                    endif
                else
                    if LONG_RANGE_BONUS > m then
                        set m = LONG_RANGE_BONUS
                    endif
                endif
            
            endif
            set i = i + 1
        endloop
        return 0
    endfunction
    
    
    public function hasBuff takes nothing returns boolean
        return GetUnitAbilityLevel(GetFilterUnit(), AURA_BUFF_ID) > 0
    endfunction
    
    public function loopFuncEnum takes nothing returns nothing
        call ApplyBonus(GetEnumUnit(), GetUnitAuraBonus(GetEnumUnit()))    
    endfunction
    public function loopFunc takes nothing returns nothing
        
        call ForGroup(tmpGrp, function loopFuncEnum)
        call GroupEnumUnitsInRect(tmpGrp, GetWorldBounds(), Filter(function hasBuff))
        call ForGroup(tmpGrp, function loopFuncEnum)
        
    endfunction
    
    
    public function compare takes nothing returns boolean
        return GetLearnedSkill() == AURA_ABIL_ID and GetLearnedSkillLevel() == 1
    endfunction
    
    public function onLearn takes nothing returns nothing
        set heroes[count] = GetTriggerUnit()
        set count = count + 1
    endfunction
    
    public function init takes nothing returns nothing
        local trigger learn = CreateTrigger()
        local integer i     = 0
        
        call TimerStart(CreateTimer(), 0.5, true, function loopFunc)
        
        loop
            exitwhen i == 16
            call TriggerRegisterPlayerUnitEvent(learn, Player(i), EVENT_PLAYER_HERO_SKILL, null)
            set i = i + 1
        endloop
        call TriggerAddCondition(learn, Filter(function compare))
        call TriggerAddAction(learn, function onLearn)
    endfunction


endscope
 
Last edited:
Level 18
Joined
Jan 21, 2006
Messages
2,552
Still code, does nothing, and I dont see why. :p

The code I posted? Or your code? Please post your code if it's your code. If it's my code, then make sure the constants are the right values (because right now I just have it set up as 'A000' and 'B000').

I'm trying to get what you are doing with the ForGroup before the enum.

Because if the unit leaves the range of the aura then GetUnitAuraBonus will return 0. If this happens, then the hash-table will be appropriately cleared and the bonus will be removed. It then proceeds to enumerate all units with the buff (which may or may not include the units from the previous iteration) and apply the bonus again. This covers units that were in the group and units that are currently in the group, leaving no leaks in hash-table references or anything.
 
Level 6
Joined
Jul 18, 2009
Messages
200
Berb said:
The code I posted? Or your code? Please post your code if it's your code. If it's my code, then make sure the constants are the right values (because right now I just have it set up as 'A000' and 'B000' ).

The code doesnt work. My Rawcodes is right.

Question:

The object editor made aura, which range should it have? 0? :thumbs_up:
 
Status
Not open for further replies.
Top