# [vJASS]Starting to understand structs by making this system. Could use some advice!

Status
Not open for further replies.

#### Sephalo

Level 18
Hey there.

I'm currently beginning on a system that's required for my map.
Well 'system' might be a big word, but it's a function that's going to be pretty common in the game itself. I'll explain what it is first.

There are Heros in the game that are inspiring other units with a specific ability. This means that the ability will be given to other units in range of the Hero, exactly like an aura. Let's say Keeper of the Grove has 'Inspire: Force of Nature'. Then this system should give units within his range the same ability, and remove that ability when they go out of range, or when Keeper of the Grove dies.
(Ignoring the fact that Force of Nature is a hero ability, and the others are units. In my map all abilities are simpel unit abilities.)

Now the tricky thing is that if a unit comes within range of the Keeper of the Grove, and he has the Force of Nature ability already, nothing should happen. But when that unit leaves range again, he should NOT lose the ability.

Now I got to understand that using a struct here would be a good way to handle it, so that's why I started trying to understand structs.
A good friend of mine made me a Floating Combat Text system once, and that's where I saw a basic struct being used. I'd like to base my self-made system on this way of coding so that I have an 'example' to look at.

JASS:
``````library CombatText initializer init needs DamageSystem

globals
private string S
endglobals

private struct Data
texttag t
string s
real size
real duration
boolean bool

static integer array Ar
static integer Total = 0
static timer Time = CreateTimer()

static method create takes texttag t, string s returns Data
local Data Dat = Data.allocate()

set Dat.t = t
set Dat.s = s
set Dat.size = 0.019
set Dat.bool = false
set Dat.duration = 0

if Dat.Total == 0 then
call TimerStart(Dat.Time,.03,true,function Data.Loop)
endif

set Dat.Ar[Dat.Total] = Dat
set Dat.Total = Dat.Total + 1

return Dat
endmethod

static method Loop takes nothing returns nothing
local Data Dat
local integer i = 0

loop
exitwhen i >= Dat.Total
set Dat = Dat.Ar[i]

set Dat.duration = Dat.duration + 0.03
if not Dat.bool then
set Dat.size = Dat.size + 0.0012
elseif Dat.bool and Dat.size >= 0.022 then
set Dat.size = Dat.size - 0.0012
endif
if Dat.size >= 0.0285 then
set Dat.bool = true
endif
call SetTextTagText(Dat.t,Dat.s,Dat.size)

if Dat.duration >= 2. then
set Dat.Total = Dat.Total - 1
set Dat.Ar[i] = Dat.Ar[Dat.Total]
set i = i - 1
call Dat.destroy()
endif

set i = i + 1
endloop
endmethod

endstruct

private function Actions takes nothing returns boolean
local texttag T
local unit u
local unit t
local integer dt = GetTriggerDamageType()
local real d
local integer R
local integer B
local integer G
local real Size
local integer id
local integer idt
local integer i
local Data Dat

if dt != DAMAGE_TYPE_EXTRA then
set T = CreateTextTag()
set u = GetTriggerDamageSource()
set t = GetTriggerDamageTarget()
set d = GetTriggerDamage()
set id = GetPlayerId(GetOwningPlayer(u))
set idt = GetPlayerId(GetOwningPlayer(t))
set Size = .019

if d != 0.00 then
if dt == DAMAGE_TYPE_ATTACK then
call SetWidgetLife(t,GetWidgetLife(t)+d)
elseif dt == DAMAGE_TYPE_PHYSICAL then
set S = I2S(R2I(d))
call Dat.create(T,S)
set R = 191
set B = 0
set G = 0
call SetTextTagVelocity(T, 0, .0277 )
elseif dt == DAMAGE_TYPE_MAGIC_HOLY then
set S = I2S(R2I(d))
call Dat.create(T,S)
set R = 242
set B = 57
set G = 187
call SetTextTagVelocity(T, 0, .0277 )
elseif dt == DAMAGE_TYPE_MAGIC_UNHOLY then
set S = I2S(R2I(d))
call Dat.create(T,S)
set R = 191
set B = 191
set G = 0
call SetTextTagVelocity(T, 0, .0277 )
endif

call SetTextTagVisibility(T, true)
call SetTextTagVisibility(T, false)

call SetTextTagColor(T,R,G,B, 255 )
call SetTextTagText(T,S,Size)
call SetTextTagPosUnit(T,t, 0 )
call SetTextTagPermanent(T, false)
call SetTextTagLifespan(T, 2)

set u = null
set t = null
set T = null

endif
endif

return false
endfunction

public function init takes nothing returns nothing
local trigger trg = CreateTrigger()
call TriggerRegisterDamageEvent(trg)
set trg = null
endfunction

endlibrary``````

I just see that as soon as
JASS:
``local Data Dat``
is being called in the actions function, apperantly the struct gets some information sent to itself so that it can start looping for every specific case of (in this case) floating text.
I'm not sure how to understand what that line
JASS:
``local Data Dat``
exactly does and how I should interpret it.

Would anyone like to give me some advice or info on this?

Last edited:

#### WaterKnight

Level 26
`local Data dat` declares a local variable called dat of type Data but does not assign a value. Infact your snippet does not create a struct instance at all.

@aura question: You can tag nearby units as "having the buff/ability" and assign them the source (Keeper of the Grove), so you can prevent other sources to repeat the effect as well as filter the ending condition. Or you make something like a ref count (count the sources a unit is affected by) but only add/remove the effect on first/last ref.

#### Sephalo

Level 18
`local Data dat` declares a local variable called dat of type Data but does not assign a value. Infact your snippet does not create a struct instance at all.

@aura question: You can tag nearby units as "having the buff/ability" and assign them the source (Keeper of the Grove), so you can prevent other sources to repeat the effect as well as filter the ending condition. Or you make something like a ref count (count the sources a unit is affected by) but only add/remove the effect on first/last ref.

My bad. I copied it wrong. Now there's a "call Dat.create(T,S)" line there too. And with that, I also understand it a bit better now haha.

And about the aura thing. I was just thinking of creating a unit group for the source, and every time a unit (that doesn't have the shared ability from himself yet) enters range he will join the unit group and get the ability. Then whenever a unit from the group leaves range it will also lose the ability.
Would that be a good way of doing this? Or is it bad to potentially end up with loads of unit groups at the same time because (maybe) they're a big heavy or something?

#### WaterKnight

Level 26
And about the aura thing. I was just thinking of creating a unit group for the source, and every time a unit (that doesn't have the shared ability from himself yet) enters range he will join the unit group and get the ability. Then whenever a unit from the group leaves range it will also lose the ability.
Would that be a good way of doing this? Or is it bad to potentially end up with loads of unit groups at the same time because (maybe) they're a big heavy or something?

Rather than enter/leave range, it should be a periodic check because the aura ranges may overlap and you do want to have the 2nd aura take over when the unit leaves the 1st one but already is within the radius of the 2nd one at that time, do you not?

The unit group is not a problem but not attaching the source unit to the target unit directly does implicate that if for example the target dies, you cannot directly access the aura caster to remove it from the unit group for example. You would have to iterate over all aura casters to find where the target is a member of or wait until the next check done by the caster itself.

#### Sephalo

Level 18
Rather than enter/leave range, it should be a periodic check because the aura ranges may overlap and you do want to have the 2nd aura take over when the unit leaves the 1st one but already is within the radius of the 2nd one at that time, do you not?

The unit group is not a problem but not attaching the source unit to the target unit directly does implicate that if for example the target dies, you cannot directly access the aura caster to remove it from the unit group for example. You would have to iterate over all aura casters to find where the target is a member of or wait until the next check done by the caster itself.

Well it's a bit complicated, but units wont leave/enter range by itself in the map. Units are stationary and only move with triggers, and if units near an 'aura' unit would move they would move together with the aura unit, so all in all I think it's no problem to add/remove units to a group whenever they enter/leave the hero's range since I can easily trigger that in the way the map works.
In the map all units have a specific unit Id, so maybe I could use that in a way to connect it to an aura group or something? To check out which group belongs to which aura-unit? Hmmm...

#### Zwiebelchen

Level 35
Aah, the age old custom aura problem...

I want to be completely honest here: the "naive" approach of having periodic enumerations and a group is more or less the best solution in this case.

Any further optimizations you could do on that go into diminishing returns, as:
- the enter range event is more or less just a periodic enumeration with a fixed interval anyway (unlike 'unit enters rect', this one is not instant!)
- you need to loop through all units anyway to compare the range towards your aura emitting units periodically to detect "leave range" dynamically, unless you use object data auras

Tbh, I'd definitely use object data auras for this. It gets rid of the tracking and the distance calculations. You just check for the buff icon to exist periodically and add/remove your ability on demand. Any additional triggering would just make it slower.

#### Wietlol

Level 24
Structs are simply a book from a library.
Structs can have static functions which can be used like any other functions (but are just called using the name of the struct with a dot just before the function call).

An instance of a struct (when you have called <StructName>.allocate()) creates "new" variables that are placed inside that struct.
In the case of "Data", the instance would "create":
JASS:
``````texttag t
string s
real size
real duration
boolean bool``````
One texttag, one string, two reals and a boolean.
(Static variables are like globals with the same rule as with static functions.)

Via that instance, you can call non-static functions declared inside the struct.
However there are no functions so all what this struct does is create some data.
The problem is that it doesnt "create" new variables, it just makes a new index because those texttag, string, reals and boolean are actually an array.
The "local Data dat = Data.allocate()" is actually an integer used in that array.

That is simply explained what a struct is.
And as far as I know, there is only one real use for structs that I have found in all the time I have been here.
Creating a static event with response without a trigger. (Ty muzzel.)

About your aura problem... If you give the ability yourself using group enumerations and giving the ability, you can also set a source of the "aura buff". (Which is impossible with normal auras afaik.)
When your unit is away from it's source (when it is out of range, when the source is dead, when whatever), you remove the effect.
Immediately after that, you give the new buffs to units near the existing sources that havent got that buff yet.

So triggerwise:
trigger buffs
- Every ... second of gametime.
- Loop for group of units with buff.
--- check if source is still active (should still give the buff).
--- if not, then remove buff.
- Loop for group of units known as source.
--- check for units near and give buffs.
endtrigger

Status
Not open for further replies.

Replies
13
Views
611
Replies
6
Views
784
Replies
16
Views
856
Replies
19
Views
735
[JASS] Slide Spell
Replies
1
Views
427