HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Help With Learning Structs and Using Them

01-07-2008, 07:13 PM#1
Blue_Jeans
I have been over at the Hive Workshop for a while and pretty much everything uses the Handle Vars system. I just barely learned Handle Vars when I heard about structs. They seem to be a better way at a glance, at least. I've read one of Vex's tutorials and I kind of understand. I think I'll want to go past that tutorial and learn methods eventually, but for now I need to understand this tutorial better.

I recently recreated Blur, an ability of the Phantom Assassin from DotA. (Off topic: ever opened the .j files for DotA? The coding is flat-out horrible... It's a nightmare in many places...) Anyways, the basic code is this:
Collapse JASS:
globals
    integer array Blur
endglobals
function Conditions takes nothing returns boolean
    return GetLearnedSkill()==Blur[0] and IsUnitIllusion(GetTriggerUnit())==false
endfunction
function Actions takes nothing returns nothing
    local integer i=GetUnitAbilityLevel(GetTriggerUnit(),Blur[0])
    call SetUnitVertexColor(GetTriggerUnit(),255,255,255,Blur[i])
endfunction
function InitTrig_Blur takes nothing returns nothing
    set Blur[0] = 'A000'
    set Blur[1] = 60
    set Blur[2] = 40
    set Blur[3] = 20
    set Blur[4] = 2
    set gg_trg_Blur=CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(gg_trg_Blur,EVENT_PLAYER_HERO_SKILL)
    call TriggerAddCondition(gg_trg_Blur,Condition(function Conditions))
    call TriggerAddAction(gg_trg_Blur,function Actions)
endfunction

I do realize there are many things to be done to the coding to make it efficient, but the problem with it aside from that is that if you cast a spell such as Wind Walk, then when it wears off it doesn't reset the vertex coloring. The same goes for being revived. So I did some more work and created a reoccurring 2-second timer when a unit learned the spell for the first time and created a Refresh function. As I knew Handle Vars (not very well, I'll admit) I used it. This is also what DotA uses. Even my crude code was more efficient than theirs, but it doesn't cut it. Then I heard about structs but I'm not sure how to implement them in this case.

Basically from what I've learned, my code using structs will look something like this:
Collapse JASS:
struct BlurData
    unit u
    boolean wantDestroy = false
endstruct
globals
    integer array Blur 
    BlurData array BlurData_Ar
    integer BlurData_total = 0
endglobals
function BlurRefresh takes nothing returns nothing
    local unit u //an unnecessary variable I think, it's just a placeholder for the current unit
    local integer i
    //here I need to grab the struct data, then
    //loop through each unit if I end up needing an array
        set i=GetUnitAbilityLevel(u,Blur[0])
        if(GetUnitState(u,UNIT_STATE_LIFE)>1)then //there was some reason I only set it if they had life, but the reason is forgotten.  This may be an unnecessary if.
            call SetUnitVertexColor(u,255,255,255,Blur[i])
        endif
    //endloop
endfunction
function BlurConditions takes nothing returns boolean 
    set Blur[0] = 'A000'
    set Blur[1] = 60
    set Blur[2] = 40
    set Blur[3] = 20
    set Blur[4] = 2
    return GetLearnedSkill()==Blur[0] and IsUnitIllusion(GetTriggerUnit())==false
endfunction
function BlurActions takes nothing returns nothing
    local unit u=GetTriggerUnit()
    local integer i=GetUnitAbilityLevel(u,Blur[0])
    local trigger t
    //I think I need a local BlurData b=BlurData.create(), don't I?
    if(i==1)then
        call SetUnitVertexColor(u,255,255,255,Blur[i])
        //I really only need one timer for ALL the instances, don't I?  Not sure how I'd do that...
        set t=CreateTrigger()
        call TriggerRegisterTimerEvent(t,2, true)
        call TriggerAddAction(t,function BlurRefresh)
        //add the unit to my struct array
        //something like set b.u=u?
    else
        call SetUnitVertexColor(u,255,255,255,Blur[i])
    endif
endfunction
function InitTrig_Blur takes nothing returns nothing
    set gg_trg_Blur=CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(gg_trg_Blur,EVENT_PLAYER_HERO_SKILL)
    call TriggerAddCondition(gg_trg_Blur,Condition(function BlurConditions))
    call TriggerAddAction(gg_trg_Blur,function BlurActions)
endfunction

Could someone please show how to do it and then explain each part quickly? I commented the code well enough I think you can see what I'm trying to do. Normally I'd continue to tank through the code but I'm lost already so I figured this was a good place to stop and ask for help.

The edit was to fix a few typos. Oh, and in the meantime I'll just keep rereading the tutorial in the hopes it sinks in.
01-07-2008, 08:47 PM#2
Vexorian
Quote:
Collapse JASS:
globals
    integer array Blur
endglobals
function Conditions takes nothing returns boolean
    return GetLearnedSkill()==Blur[0] and IsUnitIllusion(GetTriggerUnit())==false
endfunction
function Actions takes nothing returns nothing
    local integer i=GetUnitAbilityLevel(GetTriggerUnit(),Blur[0])
    call SetUnitVertexColor(GetTriggerUnit(),255,255,255,Blur[i])
endfunction
function InitTrig_Blur takes nothing returns nothing
    set Blur[0] = 'A000'
    set Blur[1] = 60
    set Blur[2] = 40
    set Blur[3] = 20
    set Blur[4] = 2
    set gg_trg_Blur=CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(gg_trg_Blur,EVENT_PLAYER_HERO_SKILL)
    call TriggerAddCondition(gg_trg_Blur,Condition(function Conditions))
    call TriggerAddAction(gg_trg_Blur,function Actions)
endfunction

I keep reading that code and I still don't get what's the part that needs structs in it, unless it is that whole array abuse that would be replaced with something easier to understand, but I am not sure...
01-07-2008, 09:17 PM#3
Blue_Jeans
That was the basic trigger, not the revised one to update every two seconds. When I posted that, I didn't have access to my HandleVars one, but now I do. Here it is:
Collapse JASS:
globals
    integer array Blur
    gamecache MyCache
endglobals
// ===========================
function H2I takes handle h returns integer
    return h
    return 0
endfunction
function H2S takes handle h returns string
    return I2S(H2I(h))
endfunction
function I2U takes string I011IO,string IIOO1O returns unit
    return GetStoredInteger(MyCache,I011IO,IIOO1O)
    return null
endfunction
//function StoreIntegerWrapper takes string str1,string str2,handle u returns nothing
//    call StoreInteger(MyCache,str1,str2,H2I(u))
//endfunction
// ===========================
function Refresh takes nothing returns nothing 
    local unit u=I2U(H2S(GetTriggeringTrigger()),"PhantomAssassin")
    local integer i=GetUnitAbilityLevel(u,Blur[0])
    if(GetUnitState(u,UNIT_STATE_LIFE)>1)then
        call DisplayTextToPlayer(Player(0), 0, 0, "I fire!")
        call SetUnitVertexColor(u,255,255,255,Blur[i])
    endif
endfunction
function Conditions takes nothing returns boolean 
    set Blur[0] = 'A001'
    set Blur[1] = 60
    set Blur[2] = 40
    set Blur[3] = 20
    set Blur[4] = 2
    return GetLearnedSkill()==Blur[0] and IsUnitIllusion(GetTriggerUnit())==false
endfunction
function Actions takes nothing returns nothing
    local integer i=GetUnitAbilityLevel(GetTriggerUnit(),Blur[0])
    local trigger t
    local unit u=GetTriggerUnit()
    if(i==1.0)then
        call SetUnitVertexColor(u,255,255,255,Blur[i])
        set t=CreateTrigger()        
        call TriggerAddAction(t,function Refresh)
        call TriggerRegisterTimerEventPeriodic(t,2)
        call StoreInteger(MyCache,H2S(t),"PhantomAssassin",H2I(u))
    else
        call SetUnitVertexColor(u,255,255,255,Blur[i])
    endif
endfunction
function InitTrig_Blur takes nothing returns nothing
    set gg_trg_Blur=CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(gg_trg_Blur,EVENT_PLAYER_HERO_SKILL)
    call TriggerAddCondition(gg_trg_Blur,Condition(function Conditions))
    call TriggerAddAction(gg_trg_Blur,function Actions)
endfunction

Edit: I think I have it, shouldn't the below code work?
Edit2: I updated the trigger considerably:
Collapse JASS:
struct BlurUnit
    unit u
endstruct

scope Blur

globals
    constant integer AID_BLUR='A000'
    integer array Blur
endglobals

private function Refresh takes nothing returns nothing
    local BlurUnit b=BlurUnit(R2I(10000000*(TimerGetTimeout(GetExpiredTimer())-1))+1)
    local integer i=GetUnitAbilityLevel(b.u,AID_BLUR)
    call SetUnitVertexColor(b.u,255,255,255,Blur[i])
endfunction
private function Conditions takes nothing returns boolean
    return GetLearnedSkill()==AID_BLUR and IsUnitIllusion(GetTriggerUnit())==false
endfunction
private function Actions takes nothing returns nothing
    local BlurUnit b=BlurUnit.create()
    local integer i=GetUnitAbilityLevel(GetTriggerUnit(),AID_BLUR)
    set b.u=GetTriggerUnit()
    set Blur[1] = 80
    set Blur[2] = 60
    set Blur[3] = 40
    set Blur[4] = 20
    call SetUnitVertexColor(b.u,255,255,255,Blur[i])
    call TimerStart(CreateTimer(),1+I2R(b)/10000000,true,function Refresh)
endfunction
public function InitTrig takes nothing returns nothing
    local trigger trig=CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(trig,EVENT_PLAYER_HERO_SKILL)
    call TriggerAddCondition(trig,Condition(function Conditions))
    call TriggerAddAction(trig,function Actions)
endfunction

endscope 

Any help to optimize what I have or to make improvements would be very appreciated! I'd ideally like to only have one timer for ALL units for optimization's sake, but I doubt that anyone would use more than one instance of this anyways. If you could show me how, that would be nice.