HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

vJASS Questions...

03-13-2008, 04:44 AM#1
Tiku
So i have been trying to learn how to use vJASS, and so far it isn't to good...
I understand how to use it, and what its for, but some things im still not understanding....

-=[1st Question]=-
So i am currently testing some things with structs out... i have two triggs with structs
Okay Here is my trigger:
Collapse JASS:
globals
    integer st = 0
endglobals    

struct test2 
    timer t = CreateTimer()
    unit u
    real heal
    integer stop
endstruct

function Struct_Usage_2_Timer takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local test2 t2 = st
    local unit u = t2.u
    local real heal = t2.heal 
    local integer stop = t2.stop
    local real life = GetUnitState(u, UNIT_STATE_LIFE)
    
    call SetUnitLifeBJ(u, life+heal)
    set t2.stop = stop+1
    
    if stop >= 10 then
     call PauseTimer(t2.t)
     call DestroyTimer(t2.t)
     call t2.destroy()
    endif
    
    set u = null
endfunction

function Trig_Struct_Usage_2_Actions takes nothing returns nothing
    local unit u = udg_Hero
    local integer h = GetRandomInt(1, 2)
    local test2 t2 = test2.create() 
    
    if h == 1 then
     set t2.heal = 10
    endif
    if h == 2 then
     set t2.heal = 50
    endif
    
    set st = t2
    set t2.u = u
    call TimerStart(t2.t, 1.0, true, function Struct_Usage_2_Timer)
    
    set u = null
endfunction

//===========================================================================
function InitTrig_Struct_Usage_2 takes nothing returns nothing
    set gg_trg_Struct_Usage_2 = CreateTrigger(  )
    call TriggerRegisterPlayerChatEvent( gg_trg_Struct_Usage_2, Player(0), "heal", true )
    call TriggerAddAction( gg_trg_Struct_Usage_2, function Trig_Struct_Usage_2_Actions )
endfunction


On a random choice, it chooses how much life you gain back over 10 seconds.
I also know i dont need a struct for the "udg_Hero" but i just added that to test other things.... :)

My Problems with this trigger:
  • I am not sure if using globals in this way is most effective in retrieving the struct "base"
  • After i heal once over 10 seconds, and then retype "heal" it works only once, and doesn't heal over 10 seconds.
  • I think it isn't getting cleaned up correctly.
  • I tried testing this, and when i rapidly typed in "heal" like 7 times some words popped up.

Here is The Screenshot of the pop up words: Link.


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

-=[2nd Question]=-
One thing i also dont get is how to use it in a spell and allow "MUI"
I've tried Before, but it didnt work....
Shown Here: Link.

I have no idea of how to do it, but if you could tell me, I'd appeciate it.



Yes i have read the tutorials on vJASS but i am still not sure on what to do in some parts.
03-13-2008, 07:02 AM#2
Jazradel
You need to attach the struct to the timer using game cache, ABC, etc. Your global variable is getting overwritten everytime you run the trigger.
The double null error messages are occurring because the same struct is being destroyed twice because of that.

Your other trigger was a good start.
03-13-2008, 05:27 PM#3
Rising_Dusk
Quote:
* I am not sure if using globals in this way is most effective in retrieving the struct "base"
You can use globals, structs don't solve the whole "how to pass one value to another function" problem, but they simplify it tremendously. Rather than saving 12 variables to a unit, you just store a single index for some struct. Consider checking out some of the systems in our database for data storage, cohadar has made a few useful ones. (PUI, ABCT, TT)
Quote:
* After i heal once over 10 seconds, and then retype "heal" it works only once, and doesn't heal over 10 seconds.
Your problem is that you don't properly initialize the struct member "stop." See below:
Expand JASS:
You're using a value in arithmetic that hasn't been properly initialized, so the most likely result is thread crashing. (Hence it only working once and thread crashing the rest of the time) It's possible that the struct is defaulting to null for safety reasons, but at the very least initialize it to avoid potential errors.
Quote:
* I think it isn't getting cleaned up correctly.
Jaz is correct on this, because it isn't MUI, it's trying to destroy the same struct multiple times or an assortment of other things.
Quote:
* I tried testing this, and when i rapidly typed in "heal" like 7 times some words popped up.
That means wc3err is telling you that you're doing something wrong, clearly the double destroy error or an assortment of other conflicts that could be resulting from the aforementioned errors.

Quote:
I have no idea of how to do it, but if you could tell me, I'd appeciate it.
MUI isn't something you can just type into a spell and magickally make it work. That isn't how it works, it entirely depends upon the spell or trigger you're working with. Just think about it in terms of instances. Will multiple instances conflict? Can it be used multiple times without conflict? If the answers there are no and yes respectively, it's MUI.

There are multitudes of ways to approach it, though. The most common is a method of attachment to keep local variables 'local' for an instance of a spell. This is what I mentioned above and what Jaz mentioned before by attaching the values to other variables (Timers in your case). See my links above for some references there.

There are of course other methods, such as linked lists or simply running everything as a set of individuals. (Refer to my spell in the database, Bluefire Ward for a good example of this method) But really, just think things through and you'll know whether something is MUI or not, then approach it by trying to make it totally local in its running. That's the easiest way to think of it.
03-14-2008, 01:20 AM#4
Tiku
I am trying to learn how to use spells without the use of the systems (i know, i should) but i would like to keep a map as "low" as possible... and thank you for the advice....

But i was looking at your trigger Rising_Dusk and i had a few questions i was hoping you can answer..

Collapse JASS:
//***************************************************************************************************************
//*                                                                                                             *
//*                                     B L U E F I R E   W A R D                                               *
//*                                            Actual Code                                                      *
//*                                                v1.6                                                         *
//*                                                                                                             *
//*                                          By: Rising_Dusk                                                    *
//*                                                                                                             *
//***************************************************************************************************************

//******************************************************************************
//******************************************************************************
//* Constant functions for use in the spell configuration

//! scope BluefireWard
private constant function WardID takes nothing returns integer
    //*********************************************************
    //* This is the ward's unit raw data.
    return 'o000'
endfunction

private constant function DummyUnitID takes nothing returns integer
    //*********************************************************
    //* This is a dummy unit's raw data with movement > 0.
    return 'h000'
endfunction

private constant function AbilID takes nothing returns integer
    //*********************************************************
    //* This is the custom ability's raw data.
    return 'A000'
endfunction

private constant function DummyAbilID takes nothing returns integer
    //*********************************************************
    //* This is the custom finger of death ability's raw data.
    return 'A001'
endfunction

private constant function ManaBurn takes integer lvl returns real
    //*********************************************************
    //* This is how much mana is burned per second.
    return 5.+(5.*lvl)
endfunction

private constant function ManaBurnThreshold takes nothing returns real
    //*********************************************************
    //* This is how much mana a unit has to have to be considered
    //* for the mana burn.
    return 5.
endfunction

private constant function Radius takes integer lvl returns real
    //*********************************************************
    //* This is the ward's mana burning radius.
    return 400.+(0.*lvl)
endfunction

private constant function Height takes nothing returns real
    //*********************************************************
    //* This is the ward's height to tip.
    return 120.
endfunction

private function BoltCheck takes nothing returns boolean
    //*********************************************************
    //* This is to determine what units will be targeted for the
    //* mana burn.
    //*
    //* bj_ghoul[99] is the ward itself.
    return IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(bj_ghoul[99])) and GetUnitState(GetFilterUnit(), UNIT_STATE_MANA) > ManaBurnThreshold() and GetWidgetLife(GetFilterUnit()) > 0.405 and GetUnitAbilityLevel(GetFilterUnit(), 'Avul') <= 0
endfunction

//******************************************************************************
//******************************************************************************
//* The spell code itself.

private struct WardData
    unit Ward
    unit Dummy
    integer Level
endstruct

globals
    private timer Timer                                          = CreateTimer()
    private integer Counter                                      = 0
    private WardData array Wards
endglobals

private function Conditions takes nothing returns boolean
    return GetUnitTypeId(GetSummonedUnit()) == WardID()
endfunction

private function GroupStuff takes nothing returns nothing
    local unit u
    local unit d
    local unit s
    local WardData w = 0
    local integer i = Counter - 1
    local integer lvl
    local boolexpr b = Condition(function BoltCheck)
    local group g = CreateGroup()
    local real m
    local real r
    local real x
    local real y
    
    loop
        exitwhen i < 0
        set w = Wards[i]
        set u = w.Ward
        set d = w.Dummy
        set lvl = w.Level
        
        if GetWidgetLife(u) < 0.405 then
            call RemoveUnit(d)
            call w.destroy()
            set Counter = Counter - 1
            if Counter < 0 then
                set Counter = 0
            else
                set Wards[i] = Wards[Counter]
            endif
        else
            set x = GetUnitX(u)
            set y = GetUnitY(u)
            set bj_ghoul[99] = u
            call GroupEnumUnitsInRange(g, x, y, Radius(lvl), b)
            loop
                set s = FirstOfGroup(g)
                exitwhen s == null
                set r = ManaBurn(lvl)/2
                set m = GetUnitState(s, UNIT_STATE_MANA)
                if r > m then
                    set r = m
                endif
                call SetUnitState(s, UNIT_STATE_MANA, m - r)
                call IssueTargetOrderById(d, 852230, s)
                call UnitDamageTarget(u, s, r, false, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL, null)
                call GroupRemoveUnit(g, s)
            endloop
            call GroupClear(g)
        endif
        set i = i - 1
    endloop
    
    
    call GroupClear(g)
    call DestroyGroup(g)
    call DestroyBoolExpr(b)
    set b = null
    set g = null
    set u = null
    set d = null
    set s = null
endfunction

private function Actions takes nothing returns nothing
    local unit u = GetSummoningUnit()
    local unit d = GetSummonedUnit()
    local integer lvl = GetUnitAbilityLevel(u, AbilID())
    local WardData w = WardData.create()
    local real x = GetUnitX(d)
    local real y = GetUnitY(d)
    
    if Counter == 0 then
        call TimerStart(Timer, 0.50, true, function GroupStuff)
    endif
    set w.Ward = d
    set w.Dummy = CreateUnit(GetOwningPlayer(u), DummyUnitID(), x, y, 0)
    set w.Level = lvl
    call UnitAddAbility(w.Dummy, DummyAbilID())
    call UnitAddAbility(w.Dummy, 'Amrf')
    call UnitRemoveAbility(w.Dummy, 'Amrf')
    call SetUnitFlyHeight(w.Dummy, Height(), 0)
    call UnitRemoveAbility(w.Dummy, 'Amov')
    call SetUnitX(w.Dummy, x)
    call SetUnitY(w.Dummy, y)
    
    set Wards[Counter] = w
    set Counter = Counter + 1
    
    set u = null
    set d = null
endfunction

//******************************************************************************
//******************************************************************************
//* The InitTrig that breathes life into the husk that is my spell.

function InitTrig_Bluefire_Ward takes nothing returns nothing
    set gg_trg_Bluefire_Ward = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(gg_trg_Bluefire_Ward, EVENT_PLAYER_UNIT_SUMMON)
    call TriggerAddCondition(gg_trg_Bluefire_Ward, Condition(function Conditions))
    call TriggerAddAction(gg_trg_Bluefire_Ward, function Actions)
endfunction
//! endscope


I noticed in many spells, people add things in the globals, that im guessing help make the spell MUI?
Such As this part of the globals:
Collapse JASS:
    private integer Counter                                      = 0
    private WardData array Wards
what does "private WardData array Wards" do? are they actual units?


These globals are from your "shrapnade" spell used for the spell contest 10:
Collapse JASS:
    private integer Counter                        = 0
    private integer array Nades
What is the "private integer array Nades" suppose to be?

Am i right? and making a globals private, does that make it so its a "local" variable?

Also:
local integer i = Counter - 1 What does "integer i" signify?
What does "Counter" signify?
I Know counter a global integer, but what is it used for?

Sorry for the lot of questions, but i'd love it if you could help me out :)
I really would love to make great spells like you.. or at least better ones than i can at the moment...

Thanks :)

Also:
local WardData w = 0 Why did you set it to "0"
does WardData/any struct "base" always come out to be "0"?
03-14-2008, 01:25 AM#5
Joker
if a struct = 0, it has no data.
03-14-2008, 01:39 AM#6
Rising_Dusk
Quote:
I am trying to learn how to use spells without the use of the systems (i know, i should) but i would like to keep a map as "low" as possible... and thank you for the advice....
There's nothing wrong with using systems, I even make my own systems for my maps. It's a great thing, they make things so much easier than just trying to brute force your way through absolutely everything. You'll thank yourself if you use a few systems, just trust me there. :p
Quote:
what does "private WardData array Wards" do? are they actual units?
That is an array of struct references where I store every instance of the spell. I then loop through all instances of the struct (AKA all instances of the spell) in a timer callback. That's how I make things MUI in those types of spells. It doesn't always work, though, but it's a strong approach and a quick one. (Since everything runs out of one timer, it's really efficient and clean) What those struct references refer to can be found by looking at the structs. In the case of WardData, there is a dummy unit alongside other things stored within that struct.
Quote:
What is the "private integer array Nades" suppose to be?
Serves the same purpose as the array of WardData above.
Quote:
Am i right? and making a globals private, does that make it so its a "local" variable?
They are private because I want them to only be accessible within the scope and not conflict with things outside of the scope. They are still global variables, they just now take the prefix for the scope, making them localized. This means that people could copy and paste the spell code multiple times into their map and change only the scope name in order to make it a totally new spell ready for use.
Quote:
What does "integer i" signify?
What does "Counter" signify?
I Know counter a global integer, but what is it used for?
The variable 'i' is just a local reference to the counter variable so I don't have to type counter everytime I want it, I just type i. Counter counts the number of struct instances in existence at any given time, therefore I only need to loop up to counter-1. (Since I need to include the 0th index of the struct array)
Quote:
Sorry for the lot of questions, but i'd love it if you could help me out :)
Hey, that's what I'm here for.
Quote:
I really would love to make great spells like you.. or at least better ones than i can at the moment...
We all gotta start somewhere, better here and now than never!
Quote:
Also:
local WardData w = 0 Why did you set it to "0"
does WardData/any struct "base" always come out to be "0"?
Struct references are just integers, so if you feel like initializing it to something, you can always set it to be zero.