• 🏆 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!
  • 🏆 Hive's 6th HD Modeling Contest: Mechanical is now open! Design and model a mechanical creature, mechanized animal, a futuristic robotic being, or anything else your imagination can tinker with! 📅 Submissions close on June 30, 2024. Don't miss this opportunity to let your creativity shine! Enter now and show us your mechanical masterpiece! 🔗 Click here to enter!

[JASS] Just Another( Or not ) Struct Question

Status
Not open for further replies.
Level 6
Joined
Jul 18, 2009
Messages
200
I have just learned how to use Structs( Yay? ).
But i dont know their purpose.

Can't someone tell me their purpose, and show me an simple code,
showing how to create( And use them( Good))?

I can get this code for you, to show my level of coding structs :p :wink:

JASS:
library Test initializer Init

struct Data
    unit Caster
    unit Target
    real Damage
    // Could( and Can ) make more variables, but just a test. :D
    
    static method DealDamage takes nothing returns nothing
        local Data d = Data.allocate()
        set d.Caster = GetTriggerUnit()
        set d.Target = GetSpellTargetUnit()
        set d.Damage = (45 * GetUnitAbilityLevel(d.Caster,'A000'))
        call AddSpecialEffectTarget( "Abilities\\Spells\\NightElf\\Blink\\BlinkTarget.mdl", d.Target , "origin")
        call UnitDamageTarget( d.Caster, d.Target, d.Damage, true, true, ATTACK_TYPE_NORMAL,DAMAGE_TYPE_ACID,null)
    endmethod
    
    static method Conds takes nothing returns boolean
        if GetSpellAbilityId() == 'A000' then
            call DealDamage()
        endif
    return false
    endmethod
    
endstruct

private function Init takes nothing returns nothing
    local trigger t = CreateTrigger (      )
    call TriggerRegisterAnyUnitEventBJ( t , EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition( t  ,  Condition( function Data.Conds))
endfunction
endlibrary

Thanks :D
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
Well your code looks pretty good, actually, though you're only implementing the static features of structs. In this case, there would be no reason for you to really use structs. Let me show you an example of a simple library that handles damage over time.

JASS:
library DurationDamage

private struct data
	public	unit	target	= null
	public	unit	source	= null
	public	real	damage
	public	real	duration

	private static	timer		dmg__tmr	= CreateTimer()
	private static	constant real	dmg__tmrRef	= 0.05

	private static	thistype array	dmg__stack
	private static	integer		dmg__stacksize	= 0

	method damageTarget takes nothing returns boolean
		if duration > 0 then
			call UnitDamageTarget(source, target, damage, false, false, /*
					*/ATTACK_TYPE_MAGIC, DAMAGE_TYPE_NORMAL, null)
			return true
		endif
		return false
	endmethod

	static method loopFunc takes nothing returns nothing
		local integer i = dmg__stacksize-1
		loop
			exitwhen(i < 0)
			set dmg__stack[i].duration = dmg__stack[i].duration-dmg__tmrRef
			if dmg__stack[i].duration <= 0 then
				set dmg__stacksize = dmg__stacksize - 1
				set dmg__stack[i]  = dmg__stack[dmg__stacksize]
				if dmg__stacksize == 0 then
					call PauseTimer(dmg__tmr)

				endif
			else
				call dmg__stack[i].damageTarget()
			
			endif
			set i = i - 1
		endloop
	endmethod

	static method create takes unit source, unit target, real damage, real duration returns thistype
		local thistype d = allocate()
		set d.target = target
		set d.source = source
		set d.damage = (damage/duration) * dmg__tmrRef
		set d.duration = duration
		if dmg__stacksize == 0 then
			call TimerStart(dmg__tmr, dmg__tmrRef, true, function thistype.loopFunc)

		endif
		set dmg__stack[dmg__stacksize] = d
		set dmg__stacksize = dmg__stacksize+1
		return d
	endmethod
		
endstruct

endlibrary

Few things to note here are instance methods, without the static keyword. Notice how in the static methods we need to reference the static stack, but once we've done that we can simply call instance methods and use all of the members that were declared above.
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
Well, internally, an instance method is just a static method that takes an integer parameter (which is the specific struct, because structs are integer indexes for parallel arrays). The usefulness of this extends beyond that, though. Here, another example:

JASS:
struct Unit
    public unit self = null

    method setPosition takes real x, real y returns nothing
        call SetUnitX(self, x, y)
        //notice how we can reference "self" even though it hasn't been defined in
        //the function -or- as a global (well, it -is- a global, but not directly).
    endmethod
 
    method addAbility takes integer abilid returns nothing
        call UnitAddAbility(self, abilid)
    endmethod

    static method create takes player for, integer id, real x, real y, real face returns thistype
        local thistype d = allocate() //static methods do not need the name of the struct when they
                                                    //are being referenced from other static methods in the same struct.
        set d.self = CreateUnit(for, id, x, y, face)
        return d
    endmethod
endstruct
 
Last edited:
Level 6
Joined
Jul 18, 2009
Messages
200
Someone gave me this code:
( Cant Remeber :p EDIT: Berb You did))

JASS:
library StrengthAura initializer Init
globals
    constant integer  CLOSE_RANGE_BONUS    = 15
    constant integer  MEDIUM_RANGE_BONUS   = 10
    constant integer  LONG_RANGE_BONUS     = 5
    constant real     CLOSE_RANGE          = 50
    constant real     MEDIUM_RANGE         = 75
    constant real     LONG_RANGE           = 100
    real globX
    real globY
endglobals

struct Data
    unit picked
    real x
    real y
    real range
    real xx
    real yy
    real r
    group g

    static method ForGroupFuncs takes nothing returns nothing
        local Data d = Data.allocate()
        set d.picked=GetEnumUnit()
        set d.x=GetUnitX(picked)
        set d.y=GetUnitY(picked)
    if(IsUnitType(d.picked, UNIT_TYPE_HERO)) then

        set range=SquareRoot((d.x-globX)*(d.x-globX) + (d.y-globY)*(d.y-globY))

        if(d.range<=CLOSE_RANGE) then
            call SetHeroStr(d.picked, GetHeroStr(d.picked,FALSE)+CLOSE_RANGE_BONUS,FALSE)
        elseif(d.range<=MEDIUM_RANGE) then
            call SetHeroStr(d.picked, GetHeroStr(d.picked,FALSE)+MEDIUM_RANGE_BONUS,FALSE)
        else 
            call SetHeroStr(d.picked, GetHeroStr(d.picked,FALSE)+LONG_RANGE_BONUS,FALSE)
        endif
    endif

    set d.picked=null
endmethod

static method EnumerateUnits takes nothing returns nothing
    local Data d = Data.allocate()
    set d.g=CreateGroup()
    set d.xx=0 
    set d.yy=0
    set d.r=100

    set d.r=LONG_RANGE

    set globX=d.xx
    set globY=d.yy

    call GroupEnumUnitsInRange(d.g, d.xx, d.yy, d.r, null)
    call ForGroup(d.g, function Data.ForGroupFuncs)
    call DestroyGroup(d.g)
    set d.g=null
endmethod

endstruct

private function Init takes nothing returns nothing
    local Data d = Data.create()
    local trigger t = CreateTrigger( )
    call TriggerRegisterUnitInRange( t , d.picked,d.r,null)
endfunction
endlibrary

would like to detect when a unit comes in range, and when it leaves,
When it enters( Gets the Strength )
When Leaves range ( The Strength removes ).

Thanks.
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
There are a few ways to do this. You could have a single periodic timer that expires every 0.05 seconds and enumerates all units in the map that have a buff (which is emitted by a Warcraft aura) or you could pick units within a range of the main unit emitting the "aura" and add them to a group. Then every periodic interval you can iterate through the group and remove the buff/bonus for units that are no longer within the designated area.
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
Okay, well that's a good way to setup your timer. In order to "pick" units on the map just do:

JASS:
call GroupEnumUnitsInRect(someGroup, GetWorldBounds(), Filter(function hasBuff))
 
Level 6
Joined
Jul 18, 2009
Messages
200
Okay.

I will edit my post when im "Done".

EDIT: Fast question: How to check buff? UnitHasBuffBJ

EDITEDIT:
THIS DOES NOT WORK
JASS:
library StrengthAura initializer Init
globals
    constant integer  CLOSE_RANGE_BONUS    = 15
    constant integer  MEDIUM_RANGE_BONUS   = 10
    constant integer  LONG_RANGE_BONUS     = 5
    constant real     CLOSE_RANGE          = 50
    constant real     MEDIUM_RANGE         = 75
    constant real     LONG_RANGE           = 100
    private boolean   FULL_STR             = TRUE
    private integer   SPELL_ID             = 'A00I'
    real globX
    real globY
endglobals

struct Data
    public unit picked
    public real x
    public real y
    public real range
    public real xx
    public real yy
    public real r
    static group g

    static method ForGroupFuncs takes nothing returns nothing
        local Data d = Data.allocate()
        set d.picked=GetEnumUnit()
        set d.x=GetUnitX(d.picked)
        set d.y=GetUnitY(d.picked)
    if(IsUnitType(d.picked, UNIT_TYPE_HERO)) then

        set d.range=SquareRoot((d.x-globX)*(d.x-globX) + (d.y-globY)*(d.y-globY))

        if(d.range<=CLOSE_RANGE) then
            call SetHeroStr(d.picked, GetHeroStr(d.picked,FULL_STR)+CLOSE_RANGE_BONUS,FULL_STR)
        elseif(d.range<=MEDIUM_RANGE) then
            call SetHeroStr(d.picked, GetHeroStr(d.picked,FULL_STR)+MEDIUM_RANGE_BONUS,FULL_STR)
        else 
            call SetHeroStr(d.picked, GetHeroStr(d.picked,FULL_STR)+LONG_RANGE_BONUS,FULL_STR)
        endif
    endif

    set d.picked=null
endmethod

static method Actions takes nothing returns nothing
    local Data d = Data.allocate()
    set d.g=CreateGroup()
    set d.xx=0 
    set d.yy=0
    set d.r=100

    set d.r=LONG_RANGE

    set globX=d.xx
    set globY=d.yy

    call GroupEnumUnitsInRange(d.g, d.xx, d.yy, d.r, null)
    call ForGroup(d.g, function Data.ForGroupFuncs)
    call DestroyGroup(d.g)
    set d.g=null
endmethod

    static method Conditions takes nothing returns boolean
        return GetLearnedSkill() == SPELL_ID
    endmethod
    
    static method hasBuff takes nothing returns boolean
        local Data d = Data.allocate()
        return UnitHasBuffBJ( d.picked , 'B00C') and/*
        */ IsUnitInGroup( d.picked , d.g )
    endmethod
    
endstruct

private function Init takes nothing returns nothing
    local Data d = Data.create()
    local trigger t = CreateTrigger( )
    call GroupEnumUnitsInRect( Data.g , GetWorldBounds() , Filter(function Data.hasBuff))
    call TriggerAddCondition( t , Condition(function Data.Conditions ) )
    call TriggerAddAction( t , function Data.Actions)
endfunction
endlibrary
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
Well that's a BJ function that just returns another native function.

JASS:
function UnitHasBuffBJ takes unit whichUnit, integer buffcode returns boolean
    return (GetUnitAbilityLevel(whichUnit, buffcode) > 0)
endfunction

So just check if it has the buff the same way this function does it.
 
Level 6
Joined
Jul 18, 2009
Messages
200
This code, doesnt work.

The units, does now get the aura buff. And they are in the range.
I dont get it.
JASS:
library StrengthAura initializer Init
globals
    constant integer  CLOSE_RANGE_BONUS    = 15
    constant integer  MEDIUM_RANGE_BONUS   = 10
    constant integer  LONG_RANGE_BONUS     = 5
    constant real     CLOSE_RANGE          = 200
    constant real     MEDIUM_RANGE         = 400
    constant real     LONG_RANGE           = 600
    private boolean   FULL_STR             = TRUE
    private integer   SPELL_ID             = 'A00I'
    private integer   BUFF                 = 'B00C'
    real globX
    real globY
endglobals

struct Data
    static unit picked
    public real x
    public real y
    public real range
    public real xx
    public real yy
    public real r
    static group g

    static method ForGroupFuncs takes nothing returns nothing
        local Data d = Data.allocate()
        set d.picked=GetEnumUnit()
        set d.x=GetUnitX(d.picked)
        set d.y=GetUnitY(d.picked)
    if(IsUnitType(d.picked, UNIT_TYPE_HERO)) then

        set d.range=SquareRoot((d.x-globX)*(d.x-globX) + (d.y-globY)*(d.y-globY))

        if(d.range<=CLOSE_RANGE) then
            call SetHeroStr(d.picked, GetHeroStr(d.picked,FULL_STR)+CLOSE_RANGE_BONUS,FULL_STR)
        elseif(d.range<=MEDIUM_RANGE) then
            call SetHeroStr(d.picked, GetHeroStr(d.picked,FULL_STR)+MEDIUM_RANGE_BONUS,FULL_STR)
        else 
            call SetHeroStr(d.picked, GetHeroStr(d.picked,FULL_STR)+LONG_RANGE_BONUS,FULL_STR)
        endif
    endif

    set d.picked=null
endmethod

static method Actions takes nothing returns nothing
    local Data d = Data.allocate()
    set d.g=CreateGroup()
    set d.xx=0 
    set d.yy=0
    set d.r=100

    set d.r=LONG_RANGE

    set globX=d.xx
    set globY=d.yy

    call GroupEnumUnitsInRange(d.g, d.xx, d.yy, d.r, null)
    call ForGroup(d.g, function Data.ForGroupFuncs)
    call DestroyGroup(d.g)
    set d.g=null
endmethod

    static method hasBuff takes nothing returns boolean
    local Data d = Data.allocate()
    return GetUnitAbilityLevel(d.picked, BUFF) >= 0 and /*
        */ IsUnitInGroup( d.picked , d.g ) and /*
        */ UnitHasBuffBJ( d.picked , BUFF )
    endmethod
    
endstruct

private function Init takes nothing returns nothing
    local Data d = Data.create()
    local trigger t = CreateTrigger( )
    local integer i = 0
    call GroupEnumUnitsInRect( Data.g , GetWorldBounds() , Filter(function Data.hasBuff))
    call TriggerAddAction( t , function Data.Actions)
    set t = CreateTrigger( )
    loop
        exitwhen i == 15
        set i = i + 1
        call TriggerRegisterUnitEvent( t , Data.picked , EVENT_UNIT_HERO_SKILL )
    endloop
endfunction
endlibrary
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
Wait, so what?

"The units does now get the aura buff" - So the aura is being applied to nearby units properly now?

JASS:
    static method hasBuff takes nothing returns boolean
    local Data d = Data.allocate()
    return GetUnitAbilityLevel(d.picked, BUFF) >= 0 and /*
        */ IsUnitInGroup( d.picked , d.g ) and /*
        */ UnitHasBuffBJ( d.picked , BUFF )
    endmethod

I don't see what you're trying to do here. Why do you allocate a Data struct (not to mention you're not destroying it, so you're going to run out of struct instances fast)?

It seems to me that you really don't know how structs work...
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,202
The purpose of structs is to group global arrays together (variables making up the struct) in such a way that they can be created and destroyed while each individual struct entry maintains a constant position for its life (will always be at an index until destroyed).

That is basically everything they do and keep the mechanics behind doing it (a a few functions and globals) hidden from you the programmer.

Methods are nothing more than eye candy meant to make programming easier. They automatically make the function named acording to the struct and also allow for simple inheritence.
 
Level 6
Joined
Jul 18, 2009
Messages
200
Wait, so what?

"The units does now get the aura buff" - So the aura is being applied to nearby units properly now?

JASS:
    static method hasBuff takes nothing returns boolean
    local Data d = Data.allocate()
    return GetUnitAbilityLevel(d.picked, BUFF) >= 0 and /*
        */ IsUnitInGroup( d.picked , d.g ) and /*
        */ UnitHasBuffBJ( d.picked , BUFF )
    endmethod

I don't see what you're trying to do here. Why do you allocate a Data struct (not to mention you're not destroying it, so you're going to run out of struct instances fast)?

It seems to me that you really don't know how structs work...

I dont know how to structs work.

I know how to get info from them, but not destroying, nor using properly.

The units get the buff from the aura created in the Object Editor :p
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
Well as Dr Super Good said, a struct is just an integer index of a large global parallel array (all of the struct members). Allocating a struct will gather an index for the struct. Destroying will allow that index to be recycled.

I think you need to lay out your spell better first, though, from the sound of it you don't really know what you want to happen.

JASS:
private function Init takes nothing returns nothing
    local Data d = Data.create()
    local trigger t = CreateTrigger( )
    call GroupEnumUnitsInRect( Data.g , GetWorldBounds() , Filter(function Data.hasBuff))
    call TriggerAddCondition( t , Condition(function Data.Conditions ) )
    call TriggerAddAction( t , function Data.Actions)
endfunction

JASS:
static method Actions takes nothing returns nothing
    local Data d = Data.allocate()
    set d.g=CreateGroup()
    set d.xx=0 
    set d.yy=0
    set d.r=100

    set d.r=LONG_RANGE

    set globX=d.xx
    set globY=d.yy

    call GroupEnumUnitsInRange(d.g, d.xx, d.yy, d.r, null)
    call ForGroup(d.g, function Data.ForGroupFuncs)
    call DestroyGroup(d.g)
    set d.g=null
endmethod

These are your only two functions that enumerate units and they only occur "once". I really don't know why you're trying to enumerate units at map initialization, no idea what you were thinking. The other situation you enumerate units is when a hero learns the ability, which means that the bonus will only be applied once when the hero learns the ability. I don't see anywhere that you have given a logical interpretation of what you want to happen in your code, it seems like you just bunched together random ideas and called it at that.
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
Right, so first set up your periodic timer.

JASS:
function doLoop takes nothing returns nothing
//... Now you are here

endfunction

function init takes nothing returns nothing
    call TimerStart(CreateTimer(), 0.05, true, function doLoop)
endfunction

Then you're going to enumerate all units in the map, so...


JASS:
globals
    group tempGrp = CreateGroup()
endglobals

function hasBuff takes nothing returns boolean
    return GetUnitAbilityLevel(GetFilterUnit(), BUFF_ID) > 0
endfunction

function doLoop takes nothing returns nothing
    call GroupEnumUnitsInRect(tempGrp, GetWorldBounds(), Filter(function hasBuff))
    // Now you're here, but you're going to need to clear the group so it can be 
    // re-used.

    call GroupClear(tempGrp)
endfunction

function init takes nothing returns nothing
    call TimerStart(CreateTimer(), 0.05, true, function doLoop)
endfunction
 
Level 6
Joined
Jul 18, 2009
Messages
200
There are some things in the world that frikz me out.

One: Girls crying over their nails.
Two: BOYS CRYING OVER THEIR NAILS.
Three:

Code that is freakin long, and still fucks with me.

JASS:
library StrengthAura initializer Init

globals
    constant integer  CLOSE_RANGE_BONUS    = 15
    constant integer  MEDIUM_RANGE_BONUS   = 10
    constant integer  LONG_RANGE_BONUS     = 5
    constant real     CLOSE_RANGE          = 200
    constant real     MEDIUM_RANGE         = 400
    constant real     LONG_RANGE           = 600
    private boolean   FULL_STR             = TRUE
    private integer   SPELL_ID             = 'A00I'
    private integer   BUFF_ID              = 'B00C'
    real globX
    real globY
    group tempGrp
endglobals

struct Data
    static unit picked
    public real x
    public real y
    public real range
    public real xx
    public real yy
    public real r

    static method ForGroupFuncs takes nothing returns nothing
        local Data d = Data.allocate()
        set d.picked=GetEnumUnit()
        set d.x=GetUnitX(d.picked)
        set d.y=GetUnitY(d.picked)
    if(IsUnitType(d.picked, UNIT_TYPE_HERO)) then

        set d.range=SquareRoot((d.x-globX)*(d.x-globX) + (d.y-globY)*(d.y-globY))

        if(d.range<=CLOSE_RANGE) then
            call SetHeroStr(d.picked, GetHeroStr(d.picked,FULL_STR)+CLOSE_RANGE_BONUS,FULL_STR)
        elseif(d.range<=MEDIUM_RANGE) then
            call SetHeroStr(d.picked, GetHeroStr(d.picked,FULL_STR)+MEDIUM_RANGE_BONUS,FULL_STR)
        else 
            call SetHeroStr(d.picked, GetHeroStr(d.picked,FULL_STR)+LONG_RANGE_BONUS,FULL_STR)
        endif
    endif

    set d.picked=null
endmethod

endstruct

private function hasBuff takes nothing returns boolean
    return GetUnitAbilityLevel(GetFilterUnit(), BUFF_ID) > 0
endfunction

private function Conditions takes nothing returns boolean
    return GetLearnedSkill() == SPELL_ID
endfunction
    
private function doLoop takes nothing returns nothing
    call GroupEnumUnitsInRect(tempGrp, GetWorldBounds(), Filter(function hasBuff))
    // Now you're here, but you're going to need to clear the group so it can be
    // re-used.

    call GroupClear(tempGrp)
endfunction

private function Init takes nothing returns nothing
    local trigger t = CreateTrigger()
    local integer i = 0
    local timer ti = CreateTimer()
    call TimerStart( ti , 0.05 , true , function doLoop )
    loop
        exitwhen i == 15
        set i = i + 1
            call TriggerRegisterPlayerUnitEvent( t , Player(i) , EVENT_PLAYER_HERO_SKILL , Filter(function hasBuff))
            call TriggerAddCondition( t , Condition(function Conditions ))
    endloop
        
endfunction
endlibrary
Four: 12 pages of homework.
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
Five: Forum members who have problems they can't solve.

Lol. Just joking.

Okay, this is the first thing I see:

JASS:
    loop
        exitwhen i == 15
        set i = i + 1
            call TriggerRegisterPlayerUnitEvent( t , Player(i) , EVENT_PLAYER_HERO_SKILL , Filter(function hasBuff))
            call TriggerAddCondition( t , Condition(function Conditions ))
    endloop

You initialize "i" to 0, and before you've registered any player-events you increase its value by 1. This means that the first player registered is Player(1), which by default game standards, is Player 2 Blue.

JASS:
private function doLoop takes nothing returns nothing
    call GroupEnumUnitsInRect(tempGrp, GetWorldBounds(), Filter(function hasBuff))
    // Now you're here, but you're going to need to clear the group so it can be
    // re-used.

    call GroupClear(tempGrp)
endfunction

As Bribe pointed out earlier, you do not need to perform a GroupClear since GroupEnumUnitsInRect already clears the unit-group before enumerating new units.

Okay, now that you've got those things cleared up, tell me what is this poorly indented piece of code supposed to do:

JASS:
    static method ForGroupFuncs takes nothing returns nothing
        local Data d = Data.allocate()
        set d.picked=GetEnumUnit()
        set d.x=GetUnitX(d.picked)
        set d.y=GetUnitY(d.picked)
    if(IsUnitType(d.picked, UNIT_TYPE_HERO)) then

        set d.range=SquareRoot((d.x-globX)*(d.x-globX) + (d.y-globY)*(d.y-globY))

        if(d.range<=CLOSE_RANGE) then
            call SetHeroStr(d.picked, GetHeroStr(d.picked,FULL_STR)+CLOSE_RANGE_BONUS,FULL_STR)
        elseif(d.range<=MEDIUM_RANGE) then
            call SetHeroStr(d.picked, GetHeroStr(d.picked,FULL_STR)+MEDIUM_RANGE_BONUS,FULL_STR)
        else 
            call SetHeroStr(d.picked, GetHeroStr(d.picked,FULL_STR)+LONG_RANGE_BONUS,FULL_STR)
        endif
    endif

    set d.picked=null
endmethod

I can see you've copied my code up to a certain point, but you don't have any other actions that you're performing in your doLoop function. The units have been enumerated in the group (given they have the buff) and then you've left it at that. There still needs to be actions performed on the enumerated units, which I am guessing the above code is for; though I have absolutely no idea what you're doing with local Data d = Data.allocate().

JASS:
    constant integer  CLOSE_RANGE_BONUS    = 15
    constant integer  MEDIUM_RANGE_BONUS   = 10
    constant integer  LONG_RANGE_BONUS     = 5
    constant real     CLOSE_RANGE          = 200
    constant real     MEDIUM_RANGE         = 400
    constant real     LONG_RANGE           = 600

I also noticed that all of your global declarations have no scope definition; this isn't a good idea for generic names such as CLOSE_RANGE as naming conflicts can arise quite easily.

JASS:
            call TriggerRegisterPlayerUnitEvent( t , Player(i) , EVENT_PLAYER_HERO_SKILL , Filter(function hasBuff))

Why are you filtering heroes that learn the aura with Filter(function hasBuff)? The heroes that are learning the aura do not need to be under the effects of the aura. Also, what you're going to need to do (I see this trigger isn't very complete at all) is add the hero that learns the aura to a group so you can iterate through all instances of the aura being emitted.

JASS:
            call TriggerAddCondition( t , Condition(function Conditions ))

You have this in the contents of the control loop. You don't want to add the conditions 15 times, you only want to add it once. The event is added many times for many different players. There is still quite a bit to be done. I recommend fixing up some of the logical problems and careless errors that I've presented, post back here when you've caught up.
 
Last edited:
Level 18
Joined
Jan 21, 2006
Messages
2,552
Well no, you'd still set it to 0, but you would move the +1 down below your trigger registrations.Bribe please don't just do it for him, if he's not able to logically work himself through it then he'll be back here in a couple of days with a new problem. Teach the man to fish, don't just catch a fish for him.
 
Level 6
Joined
Jul 18, 2009
Messages
200
Well no, you'd still set it to 0, but you would move the +1 down below your trigger registrations.Bribe please don't just do it for him, if he's not able to logically work himself through it then he'll be back here in a couple of days with a new problem. Teach the man to fish, don't just catch a fish for him.

Thanks.

Berb and Bribe.


Okay, i set i = 0 then
loop
exitwhen i = 15
set i = i + 0 + 1 ??

EDIT:

JASS:
library StrengthAura initializer Init

globals
    constant integer  CLOSE_RANGE_BONUS    = 15
    constant integer  MEDIUM_RANGE_BONUS   = 10
    constant integer  LONG_RANGE_BONUS     = 5
    constant real     CLOSE_RANGE          = 200
    constant real     MEDIUM_RANGE         = 400
    constant real     LONG_RANGE           = 600
    private boolean   FULL_STR             = TRUE
    private integer   SPELL_ID             = 'A00I'
    private integer   BUFF_ID              = 'B00C'
    real globX
    real globY
    group tempGrp
endglobals

struct Data
    static unit picked
    public real x
    public real y
    public real range
    public real xx
    public real yy
    public real r

    static method ForGroupFuncs takes nothing returns nothing
        local Data d = Data.allocate()
        set d.picked=GetEnumUnit()
        set d.x=GetUnitX(d.picked)
        set d.y=GetUnitY(d.picked)
    if(IsUnitType(d.picked, UNIT_TYPE_HERO)) then

        set d.range=SquareRoot((d.x-globX)*(d.x-globX) + (d.y-globY)*(d.y-globY))

        if(d.range<=CLOSE_RANGE) then
            call SetHeroStr(d.picked, GetHeroStr(d.picked,FULL_STR)+CLOSE_RANGE_BONUS,FULL_STR)
        elseif(d.range<=MEDIUM_RANGE) then
            call SetHeroStr(d.picked, GetHeroStr(d.picked,FULL_STR)+MEDIUM_RANGE_BONUS,FULL_STR)
        else 
            call SetHeroStr(d.picked, GetHeroStr(d.picked,FULL_STR)+LONG_RANGE_BONUS,FULL_STR)
        endif
    endif

    set d.picked=null
endmethod

endstruct

private function hasBuff takes nothing returns boolean
    return GetUnitAbilityLevel(GetFilterUnit(), BUFF_ID) > 0
endfunction

private function Conditions takes nothing returns boolean
    return GetLearnedSkill() == SPELL_ID
endfunction
    
private function doLoop takes nothing returns nothing
    call GroupEnumUnitsInRect(tempGrp, GetWorldBounds(), Filter(function hasBuff))
    // Now you're here, but you're going to need to clear the group so it can be
    // re-used.
endfunction

private function Init takes nothing returns nothing
    local trigger t = CreateTrigger()
    local integer i = 0
    local timer ti = CreateTimer()
    call TimerStart( ti , 0.05 , true , function doLoop )
    loop
        exitwhen i == 15
            call TriggerRegisterPlayerUnitEvent( t , Player(i) , EVENT_PLAYER_HERO_SKILL , Filter(function hasBuff))
            call TriggerAddCondition( t , Condition(function Conditions ))
        set i = i + 1
    endloop
        
endfunction
endlibrary

Does. Not. Work
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
Dude you haven't even changed everything I said. You're still adding your conditions 15 times, also you can exit the loop when "i" is 16, not 15.

Does. Not. Work

So go back and re-read the shit I said before you obviously missed some of it, and then if it still doesn't work post back with an actual description of what it is that isn't working. By the way, you're not even close to finished the spell so obviously it's not going to work fully yet. I'm starting to think maybe coding isn't your cup of tea because you're so bloody impatient with your code yet you put absolutely no work into it.
 
Level 6
Joined
Jul 18, 2009
Messages
200
I'm so sorry for this bullshit ive came up with.

Problems:
In object editor, the spell's based on Vampiric Aura( Should be? ).
I've set an AoE. The units does now get the buff.( From the Object Editor Edited Spell ).
This Vampiric Aura gives nothing( no lifesteal ).
//------------------------------------------

Shouldnt it be a ForGroup() func after the GroupEnum?
Added; Still doesnt work.

//-----------------------------------------
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
When you call GroupEnumUnitsInRect it adds those units to the group if they are not caught by the filter. Once you've got a group of units, then you are supposed to use a ForGroup to address each unit in the group.
 
Level 6
Joined
Jul 18, 2009
Messages
200
BERB!
IT FUCKING WORKS!
Now the problems is that, they get Strength all the time...
After a minute, they have 3m HP...

How to disable this?

WORKS!!
EDIT: Updated code abit. Still the same problem as above.
JASS:
library StrengthAura initializer Init

globals
    constant integer  CLOSE_RANGE_BONUS    = 15
    constant integer  MEDIUM_RANGE_BONUS   = 10
    constant integer  LONG_RANGE_BONUS     = 5
    constant real     CLOSE_RANGE          = 200
    constant real     MEDIUM_RANGE         = 400
    constant real     LONG_RANGE           = 600
    private boolean   FULL_STR             = TRUE
    private integer   SPELL_ID             = 'A00I'
    private integer   BUFF_ID              = 'B00C'
    real globX
    real globY
    group tempGrp
    unit picked
    unit Owner
    player Owna
endglobals

private constant function TYPES takes nothing returns boolean
    return IsUnitType(picked, UNIT_TYPE_HERO)
endfunction

struct Data
    public real x
    public real y
    public real range
    public real xx
    public real yy
    public real r

    static method ForGroupFuncs takes nothing returns nothing
        local thistype this = allocate()
        set picked=GetEnumUnit()
        set Owner = GetLearningUnit()
        set globX = GetUnitX(picked)
        set globY = GetUnitY(picked)
        set x=GetUnitX(picked)
        set y=GetUnitY(picked)
        if TYPES() == true then
          set range=SquareRoot((x-globX)*(x-globX) + (y-globY)*(y-globY))
          
            if(range<=CLOSE_RANGE) then
            
                call SetHeroStr(picked, GetHeroStr(picked,FULL_STR)+CLOSE_RANGE_BONUS,FULL_STR)
            elseif(range<=MEDIUM_RANGE) then
            
                call SetHeroStr(picked, GetHeroStr(picked,FULL_STR)+MEDIUM_RANGE_BONUS,FULL_STR)
                
            else 
                call SetHeroStr(picked, GetHeroStr(picked,FULL_STR)+LONG_RANGE_BONUS,FULL_STR)
        endif
    endif
    
    set picked=null
endmethod

endstruct
//==================================================================================================================

private function hasBuff takes nothing returns boolean
    return GetUnitAbilityLevel(GetFilterUnit(), BUFF_ID) > 0
    // Filter, which picks all units in the range Which has the buff.
endfunction

//==================================================================================================================

private function Conditions takes nothing returns boolean
    return GetLearnedSkill() == SPELL_ID
    // Gets the Learned Skill.
endfunction

//==================================================================================================================
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
//==================================================================================================================
//==================================================================================================================
    private function Init takes nothing returns nothing
        local trigger t = CreateTrigger()
        local integer i = 0
        local timer ti = CreateTimer()
        call TimerStart( ti , 0.05 , true , function doLoop )
            loop
                exitwhen i == 16
                    call TriggerRegisterPlayerUnitEvent( t , Player(i) , EVENT_PLAYER_HERO_SKILL , Filter(function Conditions))
                    call TriggerAddCondition( t , Condition(function Conditions ))
                set i = i + 1
            endloop
            
endfunction
//==================================================================================================================
//==================================================================================================================
endlibrary
 
Last edited:
Level 18
Joined
Jan 21, 2006
Messages
2,552
JASS:
            loop
                exitwhen i == 16
                    call TriggerRegisterPlayerUnitEvent( t , Player(i) , EVENT_PLAYER_HERO_SKILL , Filter(function Conditions))
                    call TriggerAddCondition( t , Condition(function Conditions ))
                set i = i + 1
            endloop

You're still adding the condition 16 times. Also, when a hero/unit learns the aura you need to add that unit to a unit-group (or a unit-array would be better).

JASS:
globals
    unit array HeroWithAura
    integer HeroWithAuraCount = 0
endglobals

function onLearnActions takes nothing returns nothing
    set HeroWithAura[ HeroWithAuraCount ] = GetTriggerUnit()
    set HeroWithAuraCount = HeroWithAuraCount + 1
endfunction

It'd be something like this.
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
Okay, so I've given you a basic layout of what your "hero" array would look like. You can define the global variables in your globals block, there's nothing too confusing about that. The unit-array consists of all the heroes in the game that have learned the aura ability. This array is used so that in your group enumeration ForGroup you can loop through each unit and find out which one is rendering the effects of the aura. The integer is the size of the array, since this has to be recorded manually with arrays. It is used as an "end-point" to the loop that I described earlier.

The onLearnActions is just a basic demonstration of how you would go about adding a unit to the array. This would be done when a hero learns the aura ability.

The reason this is all necessary is because you cannot determine what unit is the source of a buff, nor what level the buff is (and what bonuses it inflicts).
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
Dude I told you twice now. When a hero learns the aura skill (you already have the event setup for that, and a condition that is still being added 15 times) it should be included in the array.

I'm finding it irritating how you still haven't fixed your condition that is added 15 times instead of just once, especially when that was addressed long ago. If you're not going to do the work required (and simply just copy my code) then you're not going to learn. You're better off just posting in the Requests section.
 
Level 6
Joined
Jul 18, 2009
Messages
200
SO:

When a unit learns skill -
TriggerAddAction?( trigger , AddHeroFunction )
Then, ?

Berb.

I really aprecciate your help, but i've got some problems to understand.
Still, i want this to be my first spell created with some help.
( No request. )

And i have updated the code a little( Hope those conditions dont make you angry :S )

JASS:
library StrengthAura initializer Init

globals
    // CLOSE_RANGE_BONUS = How much strength you get when in Close Range
    private constant integer    CLOSE_RANGE_BONUS       = 10
    // MEDIUM_RANGE_BONUS = How much strength you get when in Medium Range
    private constant integer    MEDIUM_RANGE_BONUS      = 5
    // LONG_RANGE_BONUS = How much strength you get when in Long Range
    private constant integer    LONG_RANGE_BONUS        = 10000000
    // CLOSE_RANGE = Indicates how long Close Range is.
    private constant real       CLOSE_RANGE             = 200
    // MEDIUM_RANGE = Indicates how long Medium Range is.
    private constant real       MEDIUM_RANGE            = 400
    // LONG_RANGE = Indicates how long Long Range is.
    private constant real       LONG_RANGE              = 600
    // FULL_STR = Should it Include Bonuses from strength gain??
    private constant boolean    FULL_STR                = TRUE
    // SPELL_ID = ...
    private constant integer    SPELL_ID                = 'A00I'
    // BUFF_ID = ...
    private constant integer    BUFF_ID                 = 'B00C'
    // TIMERTICK = Every X seconds ticks, checking and adding strength.
    private constant real       TIMERTICK               = .05
    
//Dont Touch. Just dont do it.
//=============================================|
/*          */real globX                    //=|
/*          */real globY                    //=|
/*          */group tempGrp                 //=|
/*          */unit picked                   //=|
/*          */unit Owner                    //=|
/*          */timer ti                      //=|
/*          */unit array HeroWithAura       //=|
/*          */integer HeroWithAuraCount = 0 //=|
//=============================================|
endglobals

private constant function TYPES takes nothing returns boolean
return IsUnitType(picked, UNIT_TYPE_HERO) and not /*
    */ IsUnitType(picked, UNIT_TYPE_ANCIENT) and not/*
    */ IsUnitType(picked, UNIT_TYPE_ETHEREAL) and not/*
    */ IsUnitType(picked, UNIT_TYPE_MAGIC_IMMUNE) and not/*
    */ IsUnitType(picked, UNIT_TYPE_SUMMONED) and/*
    */ IsUnitInGroup(picked, tempGrp)
endfunction

//==================================================================================================================

private struct Data
    public real x
    public real y
    public real range
    public real xx
    public real yy
    public real r

    static method ForGroupFuncs takes nothing returns nothing
        local thistype this = allocate()
        set picked=GetEnumUnit() // The Picked units.
        set Owner = GetLearningUnit() // The Hero, owning the Aura
        set globX = GetUnitX(Owner) // X of the Picked unit
        set globY = GetUnitY(Owner) 
        set x=GetUnitX(picked)
        set y=GetUnitY(picked)
        if TYPES() == true then
          set range=SquareRoot((x-globX)*(x-globX) + (y-globY)*(y-globY))
            if(range<=CLOSE_RANGE) then
                call SetHeroStr(picked, GetHeroStr(picked,FULL_STR)+CLOSE_RANGE_BONUS,FULL_STR)
            elseif(range<=MEDIUM_RANGE) then
                call SetHeroStr(picked, GetHeroStr(picked,FULL_STR)+MEDIUM_RANGE_BONUS,FULL_STR)
            else 
                call SetHeroStr(picked, GetHeroStr(picked,FULL_STR)+LONG_RANGE_BONUS,FULL_STR)
        endif
    endif
    
    set picked=null
endmethod

endstruct

//==================================================================================================================

private function onLearnActions takes nothing returns nothing //THIS
    set HeroWithAura[ HeroWithAuraCount ] = GetTriggerUnit() //How to use?
    set HeroWithAuraCount = HeroWithAuraCount + 1 // Same.
endfunction //Endread.

//==================================================================================================================

private function hasBuff takes nothing returns boolean
    return GetUnitAbilityLevel(GetFilterUnit(), BUFF_ID) > 0
    // Filter, which picks all units in the range Which has the buff.
endfunction

//==================================================================================================================

private function Conditions takes nothing returns boolean
    return GetLearnedSkill() == SPELL_ID
    // Gets the Learned Skill.
endfunction

//==================================================================================================================
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
//==================================================================================================================
//==================================================================================================================
    private function Init takes nothing returns nothing
        local trigger t = CreateTrigger()
        local integer i = 0
        set ti = CreateTimer()
        call TimerStart( ti , TIMERTICK , true , function doLoop )
        //==========================================================
        set t = CreateTrigger()
            loop
                exitwhen i == 16
                    call TriggerRegisterPlayerUnitEvent( t , Player(i) , EVENT_PLAYER_HERO_SKILL , Filter(function Conditions))
                set i = i + 1
            endloop
        call TriggerAddCondition( t , Condition(function Conditions )) // This right?
        call TriggerAddAction( t , function onLearnActions ) //Same?
        //===========================================================
            
endfunction
//==================================================================================================================
//==================================================================================================================
endlibrary
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
JASS:
        call TriggerAddCondition( t , Condition(function Conditions )) // This right?
        call TriggerAddAction( t , function onLearnActions ) //Same?

Finally. That is much better.

JASS:
private function onLearnActions takes nothing returns nothing //THIS
    set HeroWithAura[ HeroWithAuraCount ] = GetTriggerUnit() //How to use?
    set HeroWithAuraCount = HeroWithAuraCount + 1 // Same.
endfunction //Endread.

By the way, you're only going to want to add the unit to the array if GetLearnedSkillLevel() == 1 since units that are learning it for a second level should not be added again. This is a simple if-statement.

The reason I want you to add these units to an array is so that you can easily iterate through each of them and determine which unit should be applying the bonuses to the enumerated targets (that you enumerated with GroupEnumUnitsInRect).

JASS:
    static method ForGroupFuncs takes nothing returns nothing
        local thistype this = allocate()
        set picked=GetEnumUnit() // The Picked units.
        set Owner = GetLearningUnit() // The Hero, owning the Aura
        set globX = GetUnitX(Owner) // X of the Picked unit
        set globY = GetUnitY(Owner) 
        set x=GetUnitX(picked)
        set y=GetUnitY(picked)
        if TYPES() == true then
          set range=SquareRoot((x-globX)*(x-globX) + (y-globY)*(y-globY))
            if(range<=CLOSE_RANGE) then
                call SetHeroStr(picked, GetHeroStr(picked,FULL_STR)+CLOSE_RANGE_BONUS,FULL_STR)
            elseif(range<=MEDIUM_RANGE) then
                call SetHeroStr(picked, GetHeroStr(picked,FULL_STR)+MEDIUM_RANGE_BONUS,FULL_STR)
            else 
                call SetHeroStr(picked, GetHeroStr(picked,FULL_STR)+LONG_RANGE_BONUS,FULL_STR)
        endif
    endif

Now, you're trying to reference GetLearningUnit() but the function doLoop which calls your static method is being performed on a periodic timer, not in an event response. This won't refer to anything. Besides that, there is no point in using GetLearningUnit() since GetTriggerUnit() will yield the same effect, and is more efficient due to the speed it is executed.

Anyways, you're going to need to be able to figure out which aura you are under the effects of. This means which unit (from the array) is close enough to you to be applying the aura, and the level of the ability on that unit (the highest level of nearby aura will be used).

JASS:
globals
    unit unitSource = null
endglobals

function GetAuraSource takes unit affected returns unit
    local integer i = 0
    local integer lvl
    local integer lvlr = 0
    loop
        exitwhen i == HeroWithAuraCount
        set lvl = GetUnitAbilityLevel(HeroWithAura[i], SPELL_ID)
        if IsUnitInRange(HeroWithAura[i], affected, LONG_RANGE) and lvl > lvlr then
            set lvlr = lvl
            set unitSource = HeroWithAura[i]
        endif
        set i = i + 1
    endloop
    return unitSource
endfunction

What this should do is determine which unit should be the designated "source" of the aura. Since range is not prioritized, it doesn't matter which hero is closer; so long as they are within range. This is going to be a lot more complicated if you're trying to prioritize which source is closer, since you've got various effects for different magnitudes of the aura effect.

The complexity of what you're trying to do may vary depending on what exactly you want certain, specific scenarios to result in. I'll give you an example that I want you to answer for me; that is what is supposed to happen when several units that bestow this aura are bestowing it upon the same unit. Should this stack both the effects (of both auras) or act as normal auras do, and only bestow the one that is most "potent" (the highest level, or the highest bonus in this case).

This is something that I would have to think about myself, and I've been using vJass for years. If this is the first spell that you're trying to code using vJass, I would suggest you move to something much less complicated. If you're intent about finishing this spell, then I can keep helping you for as long as you need, but it may be fairly difficult for you to keep up.
 
Level 6
Joined
Jul 18, 2009
Messages
200
Berb, i read your post 12 times( True ), and i was getting much info.

Should this stack both the effects (of both auras) or act as normal auras do, and only bestow the one that is most "potent" (the highest level, or the highest bonus in this case).

My aura should act like normal auras.

-------------------------------------------------

Anyway, i think it's best i quit this spell.( :sad: ), cuz it's way too complicated, and yes, ive made some spells before, but they are not with Structs( Very Simple ).
Structs is the thing in vJASS. Thats why i tested. No i got problems. And i got no way to complete my Aura. I would love to do my spell done, but it's way too difficult.( Suppose ).

Wish i knew vJASS on your level...
 
Status
Not open for further replies.
Top