• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

[JASS] Natives and Local variables ...

Status
Not open for further replies.
Level 15
Joined
Oct 16, 2010
Messages
942
I will switch to JNGP someday...

You should really switch to it right now. You can use the regular WE if you ever wanted to code in GUI (for hashtable support). But for all jass-related coding, you want JNGP.

It has syntax highlighting, additional capabilities, and comes with a function list that includes the vast majority of all the natives and BJs.
 
Level 22
Joined
Nov 14, 2008
Messages
3,256
JASSCraft sucks.

So let me explain a little further what DSG meant with the "Skip Remaining Actions" that is in GUI.

Basic it will look like this:

JASS:
function something takes nothing returns nothing
local integer i = GetRandomInt(1,2)
local boolean b = false
if i == 2 then
set b = true
endif
if b then
return //this is what in GUI is called, skip remaining actions
endif
//it will skip any action below this line so
call BJDebug("This will not show up if the integer i equals to 2")
endfunction

Sorry that I didn't align it but I'm just writing at free hand here.

Yet that was a function that returned nothing what DSG said is that it has a built-in return at the bottom line of the function. So what happens if we have a function that returns something else?

JASS:
function something2 takes nothing returns real
/* this will not work as there are no 
returns and the function should return 
a real value so this will give you 
a syntax error with JNGP
*/
endfunction

This below will work as it returns a real variable although the returned value will be 0. as the real has just been declared. Yet we can have all these other real actions for no purpose. Let's give them one.

JASS:
function something3 takes nothing returns real
local real sum
local real a = GetRandomReal(5.,10.)
local real b = (GetRandomReal(0., 50.) / a) + a
local real c = GetRandomReal(0., 50.) + b - a
return sum
endfunction

This will return a completly random value.

JASS:
function something4 takes nothing returns real
local real sum
local real a = GetRandomReal(5.,10.)
local real b = (GetRandomReal(0., 50.) / a) + a
local real c = GetRandomReal(0., 50.) + b - a
set sum = a + b + c
return sum
endfunction
 
well, I understand a few but not all coz Im loaded now, still have a map to finish, :)...

EDIT:

OK Im making a spell, but with GUI to text of course but I changed some lines...

Is this pure JASS or correct?...

JASS:
function Trig_Blood_Curse_Conditions takes nothing returns boolean
    return ( GetUnitAbilityLevelSwapped('A006', GetTriggerUnit()) > 0 ) 
    return ( UnitHasBuffBJ(GetTriggerUnit(), 'B000') == false ) 
endfunction
function Trig_Blood_Curse_Actions takes nothing returns nothing
    local unit hero = GetTriggerUnit()
    local location loc = GetUnitLoc(hero)
    call CreateNUnitsAtLoc( 1, 'h001', GetOwningPlayer(hero), loc, bj_UNIT_FACING )
    call UnitAddAbilityBJ( 'A005', GetLastCreatedUnit() )
    call UnitApplyTimedLifeBJ( 1.00, 'BTLF', GetLastCreatedUnit() )
    call SetUnitAbilityLevelSwapped( 'A005', GetLastCreatedUnit(), GetUnitAbilityLevelSwapped('A006', hero ))
    call IssueTargetOrderBJ( GetLastCreatedUnit(), "unholyfrenzy", hero )
    set hero = null
    set loc = null
endfunction
//===========================================================================
function InitTrig_Blood_Curse takes nothing returns nothing
    set gg_trg_Blood_Curse = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Blood_Curse, EVENT_PLAYER_UNIT_ATTACKED )
    call TriggerAddCondition( gg_trg_Blood_Curse, Condition( function Trig_Blood_Curse_Conditions ) )
    call TriggerAddAction( gg_trg_Blood_Curse, function Trig_Blood_Curse_Actions )
endfunction
 
Last edited:
No, that is more like GUI jass.

First of all, you can check out the function CreateNUnitsAtLoc() in jasscraft or in the JNGP function list. You will notice that it actually works much like a function you would create yourself, and is basically just made by blizzard to fit the parameters you enter in the GUI editor. This is how it looks:

JASS:
function CreateNUnitsAtLoc takes integer count, integer unitId, player whichPlayer, location loc, real face returns group
    call GroupClear(bj_lastCreatedGroup)
    loop
        set count = count - 1
        exitwhen count < 0
        call CreateUnitAtLocSaveLast(whichPlayer, unitId, loc, face)
        call GroupAddUnit(bj_lastCreatedGroup, bj_lastCreatedUnit)
    endloop
    return bj_lastCreatedGroup
endfunction

It assumes that you want to create more than one unit, and therefore commences a loop that calls another BJ, CreateUnitAtLocSaveLast(), which is made to store the "last created unit" variable that you can find in GUI. Inside this funciton, you can finally find the native function; "CreateUnit()".

CreateUnit requires the folowing parameters:

JASS:
native        CreateUnit           takes player id, integer unitid, real x, real y, real face returns unit

As most things in JASS, it uses x/y values instead of locations, since they are much faster and does not leak (and since they're not handles, you don't even have to null the variables when you're done).

If instead you replace CreateNUnitsAtLoc with this function, you will get this:

JASS:
local unit u = CreateUnit(GetOwningPlayer(hero), 'h001', GetUnitX(hero), GetUnitY(hero), 0.)

Now GetLastCreatedUnit will not be saved, and neither will GetLastCreatedGroup, but instead you can use the local handle "u" to reference the unit you just created. Your computer also don't have to take the long way around, calling two other functions before it can call the native that actually creates the unit!

After this, we have the oh, so vain function UnitAddAbilityBJ().
This is how it looks:

JASS:
function UnitAddAbilityBJ takes integer abilityId, unit whichUnit returns boolean
    return UnitAddAbility(whichUnit, abilityId)
endfunction

As you can see, it merely calls the native and does nothing more!
Instead, you should change it to this:

JASS:
call UnitAddAbility(u,  'A005')

And it already looks much more tidy.

JNGP will show BJ functions in red text as a way of sayong "OH YOU BAD BOY!", informing you that it has a native nested inside it. You can look up all the other functions you have that are displayed in red and see what natives they are calling, and try to replace them with theese, and your code will be much more efficient.


EDIT: Also notice that your condition is using two returns on top of eachother. This means that the function will ONLY return the first one, since the function automatically ends after returning.
In other words, it will never check if a unit has the buff 'B000', and only return wether the unit has a certain ability. You should place your "true" return inside an "if" statement instead, and have the "false" return at the end of the function. This means that the condition will return "true" if your "if" statement is passed, and otherwise read the "false" return if the "if" doesn't pass.
 
Level 22
Joined
Sep 24, 2005
Messages
4,821
no vjass:
JASS:
//===========================================================================
//=                             Blood Curse                                 =
//=                           by mckill 2009                                =
//===========================================================================

globals
//===========================================================================
//=                         Blood Curse Constants                           =
//===========================================================================
    constant integer    BC_SPELL_ID             = 'A006'
    constant integer    BC_SPELL_BUFF_ID        = 'B000'
    constant integer    BC_SPELL_DUMMY_SPELL    = 'A005'
    constant integer    BC_SPELL_DUMMY_ORDER_ID = OrderId("unholyfrenzy")
    
    constant integer    BC_SPELL_DUMMY_ID       = 'h001'
//===========================================================================
endglobals

//===========================================================================
//=                        Blood Curse Conditions                           =
//===========================================================================
function BloodCurseCondition takes nothing returns boolean
    return (not (GetUnitAbilityLevel(GetTriggerUnit(),BC_SPELL_ID)==0)) and (not (GetUnitAbilityLevel(GetTriggerUnit(), BC_SPELL_BUFF_ID)==0))
endfunction
//===========================================================================

//===========================================================================
//=                         Blood Curse Actions                             =
//===========================================================================
function BloodCurseAction takes nothing returns nothing
    local unit hero=GetTriggerUnit()
    // Instead of using locations, you could just use reals
    local real posX=GetUnitX(hero)
    local real posY=GetUnitY(hero)
    // I like using variables to easily understand its use, you can inline them for more speed.
    local integer level=GetUnitAbilityLevel(hero,BC_SPELL_DUMMY_SPELL)
    // CreateUnit returns a unit, so we could immediately set it to a local variable/pointer
    local unit dummy=CreateUnit(GetOwningPlayer(hero),BC_SPELL_DUMMY_ID,posX,posY,0)
    
    // Execute the dummy actions.
    call UnitAddAbility(dummy,BC_SPELL_DUMMY_SPELL)
    call SetUnitAbilityLevel(dummy,BC_SPELL_DUMMY_SPELL,level)
    call IssueTargetOrderById(dummy,BC_SPELL_DUMMY_ORDER_ID,hero)
    //==================================================
    
    // Kill the dummy.
    call SetUnitExploded(dummy,true)
    call UnitApplyTimedLife(dummy,'BTLF',1.0)
    //==================================================
    
    // Destroy local handles and remove pointer to objects.
    // Note: You forgot to remove the location in your original script.
    set hero=null
    set dummy=null
endfunction
//===========================================================================

//===========================================================================
//=                      Blood Curse Initialization                         =
//===========================================================================
function InitTrig_Blood_Curse takes nothing returns nothing
    local trigger t=CreateTrigger()

    call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_ATTACKED)
    call TriggerAddCondition(t,Condition(function BloodCurseCondition))
    call TriggerAddAction(t,function BloodCurseAction)
    
    // just in case you want the trigger referenced.
    set gg_trg_Blood_Curse=t
endfunction
//===========================================================================
 
Good JASS version:

JASS:
function Blood_Curse_OnAttack takes nothing returns boolean
    local unit hero = GetTriggerUnit()
    local unit dummy
    if (GetUnitAbilityLevel(hero, 'A006') > 0 and GetUnitAbilityLevel(hero, 'B000') == 0) then
        set dummy = CreateUnit(GetTriggerPlayer(), 'h001', GetUnitX(hero), GetUnitY(hero), bj_UNIT_FACING)
        call UnitAddAbility(dummy, 'A005')
        call UnitApplyTimedLife(dummy, 'BTLF', 1.00)
        call SetUnitAbilityLevel(dummy, 'A005', GetUnitAbilityLevel(hero, 'A006'))
        call IssueTargetOrder(dummy, "unholyfrenzy", hero)
        set dummy = null
    endif
    set hero = null
    return false
endfunction

//===========================================================================
function InitTrig_Blood_Curse takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ATTACKED)
    call TriggerAddCondition(t, Condition(function Blood_Curse_OnAttack))
    set t = null
endfunction
 

Dr Super Good

Spell Reviewer
Level 65
Joined
Jan 18, 2005
Messages
27,290
You do not cache the ability level of the hero spell.
To improve integrity, you should use global constants for types which are referenced more than once (like 'A006') as that means 1 change sufices to update all references unlike the current scheeme where bugs could be inroduced if someone forgets to update one of the references.
 
Level 22
Joined
Sep 24, 2005
Messages
4,821
The simple answer is, if you want to modify the trigger, perhaps you wanted to destroy or pause it, you need to use a global variable. If you don't want to modify it any longer, then there is no point of remembering where the said object is in memory.

You can't use local variables outside the function instance that declared them. When you call a function, a private space is provided for the function, after the execution of the said function, all that was inside that private space is removed, that's why local variables can no longer be used outside the function instance that declared it. Also, creating a trigger isn't the same as declaring a variable, the trigger handle is stored somewhere else and is independent of both global and local variables.

JASS:
function Taho takes nothing returns nothing
    call CreateTrigger()
endfunction

Look at the code above, the CreateTrigger function creates a trigger handle in memory, which consumes memory, but we didn't reference it by using a variable, hence it is unreferenced and we cannot retrieve it from memory (imagine having to call a friend and forgetting his name, how would you call him? Hey ass!). This trigger in memory isn't useful, it just lies there and consumes space, we also can't remove it because the engine forgot where he put the trigger. That is called a memory leak.

Memory leaks exists not only in jass, but also on other programming languages, even in our brains lol. If you forgot something, that's a memory leak, or Alzheimer's[?].
 
Last edited:
No vJass, no problem.

JASS:
constant function BloodCurseSpell takes nothing returns integer
    return 'A006'
endfunction

constant function BloodCurseBadBuff takes nothing returns integer
    return 'B000'
endfunction

constant function BloodCurseDummyId takes nothing returns integer
    return 'h001'
endfunction

constant function BloodCurseDummySpell takes nothing returns integer
    return 'A005'
endfunction

function BloodCurseOnAttack takes nothing returns boolean
    local unit hero = GetTriggerUnit()
    local unit dummy
    if (GetUnitAbilityLevel(hero, BloodCurseSpell()) > 0 and GetUnitAbilityLevel(hero, BloodCurseBadBuff()) == 0) then
        set dummy = CreateUnit(GetTriggerPlayer(), BloodCurseDummyId(), GetUnitX(hero), GetUnitY(hero), bj_UNIT_FACING)
        call UnitAddAbility(dummy, BloodCurseDummySpell())
        call UnitApplyTimedLife(dummy, 'BTLF', 1.00)
        call SetUnitAbilityLevel(dummy, BloodCurseDummySpell(), GetUnitAbilityLevel(hero, BloodCurseSpell()))
        call IssueTargetOrder(dummy, "unholyfrenzy", hero)
        set dummy = null
    endif
    set hero = null
    return false
endfunction

//===========================================================================
function InitTrig_Blood_Curse takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_ATTACKED)
    call TriggerAddCondition(t, Condition(function BloodCurseOnAttack))
    set t = null
endfunction
 
Ok now I'm confused again...

some codes has...

"function BloodCurseSpell takes nothing returns integer"
"constant function BloodCurseSpell takes nothing returns integer"
"scope function BloodCurseSpell takes nothing returns integer"
"native function BloodCurseSpell takes nothing returns integer"

what are those?, constant, native, scope etc...and more???...
 
Level 22
Joined
Nov 14, 2008
Messages
3,256
Those functions returns the id of the spells in the object editor. Search them up yourself and press CTRL + D and you will see the 4 digit ID of your ability. Every single object in the object editor has one, check it out yourself.

In gui you're probably familiar with ability variables or unittype variables. In JASS those aren't necessary and in JASS we use Integers instead, put the 4 digit id between two 'yoid' and it will return the id of your object.

The constant stands for, constant. It will always return the same value all the time and therefore I *think* it will have better performance if you put them as constants. Seems like Bribe's answer was better :D

Native, in JASS there are two things about functions. Functions from the Blizzard.j and natives from the common.j (two files within the war3 mpq file). The natives are pure functions made in C which cannot be simplyfied no more. BJs are usually a bunch of natives collected together or even worse, they can be calling the real function straight away. Like PauseUnitBJ, it looks like this when you look up this function

JASS:
function PauseUnitBJ takes boolean pause, unit whichUnit returns nothing
    call PauseUnit(whichUnit, pause)
endfunction

So it calls the real native straight away. Vex's optimizer fixes loads of these but not all so basic in JASS, do not use BJs but there are a few exceptions.
Like TriggerRegisterAnyUnitEventBJ which is constantly used in spellmaking. Or GroupPickRandomUnit, useless to remake as the output will be exactly the same.

Scopes are things we use in vJASS so if you're not going to learn that, I will not explain that.

Btw these

"scope function BloodCurseSpell takes nothing returns integer"
"native function BloodCurseSpell takes nothing returns integer"

Does not exist.
 
Level 22
Joined
Sep 24, 2005
Messages
4,821
Lua is usually used for the scripting of game configurations. IIRC, warcraft 3's engine was written in C++ not C. I liked the alpha version better...
 
Level 22
Joined
Sep 24, 2005
Messages
4,821
I've only seen it in videos though. Alpha's special effects were better, the building scaling was realistic, it wasn't RTS, more like an Action RPG kind of game.
 
Ok, here's another topic...

I've noticed that Hash GUI is this:
child key, parent key and Hash

But in JASS, it's reverse:
Hash first, the Parent and the child

my questions is this, is this ALWAYS the case? to save and load?...

Also I've experimented this:

JASS:
function hashon takes nothing returns nothing
    local unit attacker = GetAttacker()
    local hashtable hash1 = InitHashtable()
    local integer ID = GetHandleId(attacker)
    call SaveUnitHandle(hash1, StringHash("unit"), ID, attacker)
    call KillUnit(LoadUnitHandle(hash1, StringHash("unit"), ID))
    set attacker = null
    //Is this the correct null?, or should I put also:
    // set hash1 = null
    // set ID = null
endfunction
//===========================================================================
function InitTrig_Hashtest takes nothing returns nothing
    local trigger trigtest = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ(trigtest, EVENT_PLAYER_UNIT_ATTACKED)
    call TriggerAddAction(trigtest, function hashon )
    set trigtest = null
endfunction

so is the trigger correct?...
 
Level 22
Joined
Sep 24, 2005
Messages
4,821
You should also null global handles that point to destroyed objects, so that the destroyed object's handleId can be recycled.
 
Ok guys, this is the one I made...falling corpses from the sky...

Take note that most of the functions are in GUI...I know it's not really
good but is it FAIR?...coz I'm just appying the one I know...


  • Fallen Corpse Bombardment
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Fallen Corpse Bombardment
    • Actions
      • Set FCB_Pt[1] = (Target point of ability being cast)
      • Set FCB_Unit = (Triggering unit)
      • Custom script: set udg_FCB_Level = GetUnitAbilityLevelSwapped('A02M', udg_FCB_Unit)
      • Unit - Create 1 Dummy (caster-for all) for (Owner of FCB_Unit) at FCB_Pt[1] facing Default building facing degrees
      • Custom script: set udg_FCB_Dummy = GetLastCreatedUnit()
      • Custom script: set udg_FCB_ID = GetHandleId(udg_FCB_Dummy)
      • Unit - Add Falling Corpse Bom (FCB SP1) to FCB_Dummy
      • Unit - Set level of Falling Corpse Bom (FCB SP1) for FCB_Dummy to FCB_Level
      • Hashtable - Save Handle OfFCB_Pt[1] as (Key fcbloc) of FCB_ID in Hash_01
      • Custom script: call SaveInteger(udg_Hash_01, StringHash("fcblevel"), udg_FCB_ID, udg_FCB_Level)
      • Custom script: call SaveUnitHandle(udg_Hash_01, StringHash("fcbcaster"), udg_FCB_ID, udg_FCB_Unit)
      • Custom script: call SaveReal(udg_Hash_01, StringHash("fcbdur"), udg_FCB_ID, 6.00)
      • Unit Group - Add FCB_Dummy to FCB_Grp
      • Custom script: call EnableTrigger(gg_trg_Fallen_Corpse_Bombardment_Loop)
  • Fallen Corpse Bombardment Loop
    • Events
      • Time - Every 0.30 seconds of game time
    • Conditions
    • Actions
      • Unit Group - Pick every unit in FCB_Grp and do (Actions)
        • Loop - Actions
          • Custom script: set udg_FCB_Dummy = GetEnumUnit()
          • Custom script: set udg_FCB_ID = GetHandleId(udg_FCB_Dummy)
          • Custom script: set udg_FCB_Unit = LoadUnitHandle(udg_Hash_01, StringHash("fcbcaster"), udg_FCB_ID)
          • Custom script: set udg_FCB_Timer = LoadReal(udg_Hash_01, StringHash("fcbdur"), udg_FCB_ID)
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (FCB_Unit is alive) Equal to True
              • FCB_Timer Greater than 0.00
            • Then - Actions
              • Custom script: call SaveReal(udg_Hash_01, StringHash("fcbdur"), udg_FCB_ID, udg_FCB_Timer - 0.3)
              • Set FCB_Pt[1] = (Load (Key fcbloc) of FCB_ID in Hash_01)
              • Set FCB_Pt[2] = (FCB_Pt[1] offset by (Random real number between 50.00 and 250.00) towards (Random real number between 0.00 and 360.00) degrees)
              • Unit - Create 1 Falling Corpse for (Owner of FCB_Unit) at FCB_Pt[2] facing Default building facing degrees
              • Custom script: set udg_FCB_CorpseFalling = GetLastCreatedUnit()
              • Custom script: set udg_FCB_CorpseID = GetHandleId(udg_FCB_CorpseFalling)
              • Custom script: set udg_FCB_Level = LoadInteger(udg_Hash_01, StringHash("fcblevel"), udg_FCB_ID)
              • Custom script: set udg_FCB_Dam = udg_FCB_Level
              • Custom script: call SaveInteger(udg_Hash_01, StringHash("fcb2level"), udg_FCB_CorpseID, udg_FCB_Dam)
              • Custom script: call SaveUnitHandle(udg_Hash_01, StringHash("fcbcaster2"), udg_FCB_CorpseID, udg_FCB_Unit)
              • Animation - Change (Last created unit) flying height to 0.00 at 1000.00
              • Unit - Add a 1.00 second Generic expiration timer to (Last created unit)
              • Custom script: call RemoveLocation(udg_FCB_Pt[2])
            • Else - Actions
              • Custom script: call RemoveLocation(udg_FCB_Pt[1])
              • Custom script: call ExplodeUnitBJ(udg_FCB_Dummy)
              • Custom script: call UnitApplyTimedLifeBJ( 0.01, 'BTLF', udg_FCB_Dummy )
              • Unit Group - Remove FCB_Dummy from FCB_Grp
              • Hashtable - Clear all child hashtables of child FCB_ID in Hash_01
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • (FCB_Grp is empty) Equal to True
                • Then - Actions
                  • Trigger - Turn off (This trigger)
                • Else - Actions
  • Fallen Corpse Bombardment Dies
    • Events
      • Unit - A unit Dies
    • Conditions
      • (Unit-type of (Triggering unit)) Equal to Falling Corpse
    • Actions
      • Custom script: set udg_FCB_CorpseFalling = GetTriggerUnit()
      • Custom script: set udg_FCB_CorpseID = GetHandleId(udg_FCB_CorpseFalling)
      • Custom script: set udg_FCB_Dam = LoadInteger(udg_Hash_01, StringHash("fcb2level"), udg_FCB_CorpseID)
      • Custom script: set udg_FCB_Unit = LoadUnitHandle(udg_Hash_01, StringHash("fcbcaster2"), udg_FCB_CorpseID)
      • Set FCB_Pt[3] = (Position of (Triggering unit))
      • Special Effect - Create a special effect at FCB_Pt[3] using Abilities\Spells\Other\Stampede\StampedeMissileDeath.mdl
      • Special Effect - Destroy (Last created special effect)
      • Custom script: set bj_wantDestroyGroup = true
      • Unit Group - Pick every unit in (Units within 100.00 of FCB_Pt[3] matching ((((Matching unit) belongs to an enemy of (Owner of FCB_Unit)) Equal to True) and (((Matching unit) is alive) Equal to True))) and do (Actions)
        • Loop - Actions
          • Unit - Cause FCB_Unit to damage (Picked unit), dealing (15.00 x (Real(FCB_Dam))) damage of attack type Chaos and damage type Divine
      • Custom script: call RemoveLocation(udg_FCB_Pt[3])
      • Hashtable - Clear all child hashtables of child FCB_CorpseID in Hash_01
      • Unit - Remove (Triggering unit) from the game
 
Level 22
Joined
Nov 14, 2008
Messages
3,256
You should also null global handles that point to destroyed objects, so that the destroyed object's handleId can be recycled.

Right, this applies to JASS as no one does it in GUI ;)

@mckill

Useless BJ
set udg_FCB_Level = GetUnitAbilityLevelSwapped('A02M', udg_FCB_Unit)

Change it to GetUnitAbilityLevel(udg_FCB_Unit, 'A02M')

  • Custom script: set udg_FCB_Dummy = GetLastCreatedUnit()
Useless to do in customscript as it does just like that in GUI.

Why you try to change your BJs and you still keep some?
  • Hashtable - Save Handle OfFCB_Pt[1] as (Key fcbloc) of FCB_ID in Hash_01
  • Custom script: call EnableTrigger(gg_trg_Fallen_Corpse_Bombardment_Loop)
Same as GUI, use GUI.

  • Custom script: set udg_FCB_Dummy = GetEnumUnit()
Also same as GUI "Picked Unit"

Sorry to say this but don't use points that are arrayed unless you're going to use 100 of them "temporarly". Make 2 variables instead as arrayed takes much more space.

  • Custom script: set udg_FCB_CorpseFalling = GetLastCreatedUnit()
Converted GUI BJ, either use the GUI or make it real JASS.

  • Set FCB_Pt[1] = (Load (Key fcbloc) of FCB_ID in Hash_01)
Leaks as you don't remove it in the then part. You stilled saved it in the hash, don't worry.

  • Custom script: call ExplodeUnitBJ(udg_FCB_Dummy)
Use the GUI if you cannot remove the BJ proper. Read about what's behind the BJs.

  • Custom script: call UnitApplyTimedLifeBJ( 0.01, 'BTLF', udg_FCB_Dummy )
Useless as you remove the unit instantly afterwards before the 0.01 timer hasn't even started.

Stop create spells in GUI, convert the whole trigger instead and start from there. Much more fun than judging GUI code.
 
Aha!, no wonder why "GetUnitAbilityLevel" did not work coz I used "GetUnitAbilityLevel('A02M', udg_FCB_Unit)...

Sorry to say this but don't use points that are arrayed unless you're going to use 100 of them "temporarly". Make 2 variables instead as arrayed takes much more space.

Roger!

The reason why Im doin all this in custom script so that I can familiarize
the codes of saving & loading in hash without the help of JNGP (next time I will)...

Now I know a little like SaveUnitHandle, SaveInteger, etc... and how to
load them...

As I go step by step in doing this, I wil soon realize the importance of making it in REAL JASS...thanks to you guys!
 
Another practice...Im studing coordinates...is this true JASS?...

JASS:
function WodSpell takes nothing returns boolean
    return (GetSpellAbilityId()=='A002') 
endfunction
 
function WodAct takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local real x1 = GetUnitX(u)
    local real y1 = GetUnitY(u)
    local real x2 = GetSpellTargetX()
    local real y2 = GetSpellTargetY()    
    local unit o = CreateUnit (GetOwningPlayer(u), 'hfoo', x1,y1, 0)
    call IssuePointOrder(o, "move", x2, y2)
    set u = null
    set o = null    
endfunction
 
//===========================================================================
 
function InitTrig_Wind_of_Decay takes nothing returns nothing
    local trigger t = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ      (t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition                (t, Condition(function WodSpell))
    call TriggerAddAction                   (t, function WodAct )
    set t = null
endfunction
 
Level 22
Joined
Nov 14, 2008
Messages
3,256
In JASS, you don't use any actions (you better learn this right away). You merge them with the conditions so instead of your trigger it will be like this:

JASS:
function WodSpell takes nothing returns boolean
    local unit u
    local unit o
    if GetSpellAbilityId()=='A002' then
        set u = GetTriggerUnit()
        set o = CreateUnit(GetTriggerPlayer(), 'hfoo', GetUnitX(u), GetUnitY(u), 0.)
        call IssuePointOrder(o, "move", GetSpellTargetX(), GetSpellTargetY())
        set u = null
        set o = null
    endif
    return false
endfunction

//===========================================================================
 
function InitTrig_Wind_of_Decay takes nothing returns nothing
    local trigger t = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ      (t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition                (t, Condition(function WodSpell))
    set t = null
endfunction
 
Level 22
Joined
Sep 24, 2005
Messages
4,821
In the end, everything is compiled to jass, even the doodad placing; what you should ask for is if your script is optimized. I meant no offense, just clarifying.

Now back on topic: that's a good start, using reals instead of location handles are better because they don't need allocation.

<EDIT>
Yeah baassee is right, triggercondition's execute faster because they don't support TriggerSleeps a.k.a Wait actions. It's like a one shot thread that the engine won't ever return to, think local variables. Also, it's not too bright to use waits when you're already scripting directly lol. I remembered one time... XD
 
Level 22
Joined
Nov 14, 2008
Messages
3,256
SetUnitX/Y doesn't interrupt orders. SetUnitPosition does. Both are using coordinates.

It's the trigger condition. It has to return a boolean value and because we're not using any actions, it should return false always no matter what as it would else fire the actions when there are any. There are no else part in the if statement.
 
Status
Not open for further replies.
Top