• 🏆 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!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[JASS] Small library

Status
Not open for further replies.
Level 6
Joined
Jun 19, 2010
Messages
143
JASS:
library Unit
    globals
        private group grp=null
    endglobals
    public function filter1 takes unit u, integer ID returns boolean
        return GetUnitTypeId(u)==ID
    endfunction
    public function CountNUnitsInGroup takes player p, integer unitID returns integer
        local unit FoG=null
        local integer i=0
        call GroupEnumUnitsOfPlayer(grp,p, function Unit_filter1(GetEnumUnit(),unitID))
        loop
            set FoG=FirstOfGroup(grp)
            set i=i+1
            exitwhen FoG==null
            call GroupRemoveUnit(grp,FoG)
        endloop
        return i
    endfunction
endlibrary
I got syntax error unexpected "(?" in here
call GroupEnumUnitsOfPlayer(grp,p, function Unit_filter1(GetEnumUnit(),unitID))
How to make the filter1 in the booleanexpr in that GroupEnumUnitsOfPlayer work?
 
Level 25
Joined
Jun 5, 2008
Messages
2,572
You cannot have a filter function that requires parameters.
JASS:
globals
 private integer TEMP_ID
endglobals
JASS:
public function filter1 nothing returns boolean
        return GetUnitTypeId(GetFilterUnit())==TEMP_ID
endfunction
JASS:
set TEMP_ID = unitId
call GroupEnumUnitsOfPlayer(grp, p, function Unit_filter1)

That should fix everything.
 
Level 6
Joined
Jun 19, 2010
Messages
143
Also about filter, I make this
JASS:
scope dagger initializer Daggers
globals
    private constant integer ITEM1='I001'
    private constant integer ITEM2='I002'
    private constant integer ITEM3='I003'
endglobals
    private function filter takes nothing returns boolean
        return GetItemTypeId(GetManipulatedItem())==ITEM1 or GetItemTypeId(GetManipulatedItem())==ITEM2 or GetItemTypeId(GetManipulatedItem())==ITEM3
    endfunction
    private function DaggerLeveling takes integer itemID1, integer itemID2 returns nothing
        if Item_GetNumberItemsAUnitHas(GetManipulatingUnit(),itemID1) == 2 then
            call Item_RemoveNItemsFromUnit(2,itemID1,GetManipulatingUnit())
            call UnitAddItemById( GetManipulatingUnit(), itemID2 )
        endif
    endfunction
    private function DaggersCond takes nothing returns boolean
        local integer item1
        local integer item2
        if GetItemTypeId(GetManipulatedItem())==ITEM1 then
            call DaggerLeveling(ITEM1,ITEM2)
        elseif GetItemTypeId(GetManipulatedItem())==ITEM2 then
            call DaggerLeveling(ITEM2,ITEM3)
            elseif GetItemTypeId(GetManipulatedItem())==ITEM3 then
                call DaggerLeveling(ITEM3,'I004')
        endif
    return false
    endfunction
    private function Daggers takes nothing returns nothing
        local trigger t=CreateTrigger()
        local integer i=0
        loop
            exitwhen i>11
            call TriggerRegisterPlayerUnitEvent(t,Player(i),EVENT_PLAYER_UNIT_PICKUP_ITEM,function filter)
            set i=i+1
        endloop
        call TriggerAddCondition(t,Condition(function DaggersCond))
        set t=null
    endfunction
endscope

This works with my own library and works in game the way I wanted.
However, any change I can get rid of these ifs below? b'cuz like this I'm using
GetItemTypeId(GetManipulatedItem())==ITEM1 twice (1 in filter, 1 in trigger action). It's inefficient, I want to keep using the filter and use boolean==ITEM1 once only.

JASS:
if GetItemTypeId(GetManipulatedItem())==ITEM1 then
            call DaggerLeveling(ITEM1,ITEM2)
        elseif GetItemTypeId(GetManipulatedItem())==ITEM2 then
            call DaggerLeveling(ITEM2,ITEM3)
            elseif GetItemTypeId(GetManipulatedItem())==ITEM3 then
                call DaggerLeveling(ITEM3,'I004')
        endif

I want it to be more efficient, I tried this but it doesn't work
JASS:
globals
    private constant integer ITEM1='I001'
    private constant integer ITEM2='I002'
    private constant integer ITEM3='I003'
    private integer itemid1=0
    private integer itemid2=0
endglobals
    private function filter takes nothing returns boolean
        if GetItemTypeId(GetManipulatedItem())==ITEM1 then
            set itemid1= ITEM1
            set itemid2= ITEM2
            return true
        elseif GetItemTypeId(GetManipulatedItem())==ITEM2 then
            set itemid1= ITEM2
            set itemid2= ITEM3
            return true
            elseif GetItemTypeId(GetManipulatedItem())==ITEM3 then
                set itemid1= ITEM3
                set itemid2= 'I004'
                return true
        endif
        return false
    endfunction
 
Level 37
Joined
Mar 6, 2006
Messages
9,240
Save the item type you upgrade to into a hashtable in a configuration block.

call SaveInteger(hash, 'I000', 0, 'I001')
I000 upgrades to I001.

To check if an item type upgrades

JASS:
if HaveSavedInteger(hash, itemTypeId, 0) then
    call DaggerLeveling(itemTypeId, LoadInteger(hash, itemTypeId, 0)
endif
 
Level 6
Joined
Jun 19, 2010
Messages
143
So the filter will be like this ? should I define
JASS:
private hashtable hash
in the library. I'm not used to the hash but I can learn to use it by now. Please I still need more helps.
The more concise and efficient the better.

JASS:
private function filter takes nothing returns boolean
        if GetItemTypeId(GetManipulatedItem())=='I001' then
            call SaveInteger(hash, 'I001', 0, 'I002')
            return true
        elseif GetItemTypeId(GetManipulatedItem())=='I002' then
            call SaveInteger(hash, 'I002', 0, 'I003')
            return true
            elseif GetItemTypeId(GetManipulatedItem())=='I003' then
                call SaveInteger(hash, 'I003', 0, 'I004')
                return true
        endif
        return false
    endfunction
 
Level 25
Joined
Jun 5, 2008
Messages
2,572
Hash works by saving data in a giant table.
Now you can directly use item handles in your case or you can use item types as keys to save data.

The example of what maker mentioned for example.
You save the value of the upgraded item Type to the hashtable using primary key of 'I000', secondary key of 0 and value of 'I001'.

Now if you wanted to know to what item 'I000' upgrades you can just read it from the hashtable and know the id ('I001').
 
Level 6
Joined
Jun 19, 2010
Messages
143
b'cuz i want the trigger to be working selectively & quickly for those items. You don't have to create the trigger for any item then add condition func to check for the correct items and do the swapping. It only creates the trigger selectively for the right items to be swapped. That'd be more efficient ?
 
Level 31
Joined
Jul 10, 2007
Messages
6,306
This is what they meant by using a hashtable. Instead of chaining a ton of if statements together, you can simply use 1 if statement.

A hashtable can be thought of as a 2D array that can take any index and is essentially of infinite size. This isn't really what a hashtable is, but for simplicity, just think of it like this. It is slower than an array because it needs to use an algorithm to convert inputted values into an index and then search for the correct value corresponding to that index.


Consider this
JASS:
        if GetItemTypeId(GetManipulatedItem())==ITEM1 then
            call DaggerLeveling(ITEM1,ITEM2)
        elseif GetItemTypeId(GetManipulatedItem())==ITEM2 then
            call DaggerLeveling(ITEM2,ITEM3)
        elseif GetItemTypeId(GetManipulatedItem())==ITEM3 then
            call DaggerLeveling(ITEM3,'I004')
        endif

Here, you are chaining your if statements together.

Try this instead.
JASS:
call SaveInteger(table, ITEM1, 0, ITEM2)
call SaveInteger(table, ITEM2, 0, ITEM3)
call SaveInteger(table, ITEM3, 0, ITEM4)

Allowing you to do this
call DaggerLeveling(GetItemTypeId(GetManipulatedItem()),LoadInteger(table, GetItemTypeId(GetManipulatedItem())))

And within the DaggerLeveling
JASS:
if (0 == itemID2) then
    return
endif

Also, within a trigger condition, you always want it to be false. Only use trigger actions when you absolutely have to.

edit
For your first snippet of code, do not use a filter. Every filter is dynamically evaluated (like TriggerEvaluate), which is extremely slow. Simply putting the if statement into the first of group loop is much faster.

JASS:
library Unit
    globals
        private group grp=null
    endglobals
    public function CountNUnitsInGroup takes player p, integer unitID returns integer
        local unit FoG=null
        local integer i=0
        call GroupEnumUnitsOfPlayer(grp, p, null)
        loop
            set FoG=FirstOfGroup(grp)
            exitwhen FoG==null
            call GroupRemoveUnit(grp,FoG)

            if (unitID = GetUnitTypeId(u)) then
                set i=i+1
            endif
        endloop
        return i
    endfunction
endlibrary

Simpler and faster.

Also, I shouldn't have to say this, but public functions are essentially forbidden due to their ugliness in usage -> Unit_CountNUnitsInGroup. If you want to do something like a Unit lib, do struct Unit extends array so that you can have Unit.countNUnitsInGroup instead of Unit_CountNUnitsInGroup. Also, I'd recommend you change this to CountUnitsOfTypeOfPlayer(player whichPlayer, integer unitTypeId)
 
Status
Not open for further replies.
Top