• 🏆 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!

[VJASS][System] Igs- ItemGroup

Level 5
Joined
Dec 4, 2006
Messages
110
Igs- ItemGroup
The First ItemGroup Variable Type
Current Version- v1.2


(N/A)



Max of 8190 items, but also a max of 1 itemgroup.
Default at 682 items with a max of 12 itemgroups.


News Count- 3





There isn't an itemgroup variable type. So, I made one.



ItemGroup is very simple to use. The layout is as close to unit groups as I could get them.

To configure itemgroup, go into the ItemGroup library and look for:

JASS:
private constant integer ARRAY_SIZE = 682

682 items is the default maximum. I don't see a point in setting it very high, as it quickly diminishes your maximum amount of itemgroups, and as I see it, 682 is plenty items at a time. Add more if you need to. In fact, 819/682.5 = 12, thus giving you one itemgroup per player with a maximum of 682.5 items. Since it's an integer, we round down to 682. That's plenty.

To create an itemgroup, simply call CreateItemGroup()

JASS:
local itemgroup g = CreateItemGroup()

Now, add some items to it:

JASS:
call ItemGroupEnumItemsInRect(g, GetWorldBounds(), null)

That will add all items in the map to the itemgroup.

Next, do stuff with it:

JASS:
function do takes nothing returns nothing
    call RemoveItem(GetEnumItemGroupItem())
endfunction

function start takes nothing returns nothing
    local itemgroup g = CreateItemGroup()
    call ItemGroupEnumItemsInRect(g, GetWorldBounds(), null)
    call ForItemGroup(g, function do)
    call DestroyItemGroup(g)
endfunction

Let's look at some of the fuctions used in there:

JASS:
.
GetEnumItemGroupItem()
1. Returns the enum; essentially the same as GetEnumItem for Igs.

ForItemGroup(g, function do)
2. Executes function do for all items in the itemgroup; essentially the same as ForGroup for Igs.

DestroyItemGroup(g)
3. Destroys the itemgroup; all members of the struct are nulled in the onDestroy method; essentially the same as DestroyGroup for Igs.

There are many other Enum functions but all are the same as their respective unit group counterparts.

They should be simple enough to figure out.

And that's all there is to Igs.




-News Section-

The first release of ItemGroup. Sadly, it doesn't use linked lists. Perhaps I will make a linked lists version some time later on.



Fixed some bugs in the code and removed O(n) searching on removal.



Added CountItemsInItemGroup and IsItemInItemGroup


-System Section-

JASS:
/*System Information
===================================================================
Name: ItemGroup
Version: 1.2
Author: Sevion
Helpers: Flare

Description: ItemGroup Variable Type

Requirements: None

Usage:
------------------------------------------------------------------
local itemgroup g = CreateItemGroup()
call ItemGroupEnumItemsInRect(g, gg_rct_Region_000, null)
call ForItemGroup(g, function DoStuff)
call DestroyItemGroup(g)

Function List:
-CreateItemGroup()
-DestroyItemGroup()
-ItemGroupAddItem(itemgroup, item)
-ItemGroupRemoveItem(itemgroup, item)
-ItemGroupAddItemGroup(itemgroup, itemgroup)
-ItemGroupClear(itemgroup)
-ForItemGroup(itemgroup, code)
-CountItemsInItemGroup(itemgroup)
-IsItemInItemGroup(itemgroup)
-ItemGroupEnumItemsInRect(itemgroup, rect, boolexpr)
-ItemGroupEnumItemsInRectCount(itemgroup, rect, boolexpr, integer)
-ItemGroupEnumItemsInRange(itemgroup, real, real, real, boolexpr)
-ItemGroupEnumItemsInRangeCounted(itemgroup, real, real, real, boolexpr, integer)
-ItemGroupEnumItemsOfPlayer(itemgroup, player, boolexpr)
-ItemGroupEnumItemsOfType(itemgroup, integer, boolexpr)
-ItemGroupEnumItemsOfTypeCount(itemgroup, integer, boolexpr, integer)
-ItemGroupEnumItemsInRect(itemgroup, rect, boolexpr)
-ItemGroupEnumItemsInRect(itemgroup, rect, boolexpr)
-ItemGroupPickRandomItem(itemgroup)

Configuration:
-------------------------------------------------------------------
-Set ARRAY_SIZE to whatever you wish. The smaller it is, the fewer
-items you can have in an itemgroup. The larger, the fewer itemgroups
-you can have at one time.
===================================================================*/
library ItemGroup initializer Ini
    globals
        private constant integer ARRAY_SIZE = 682
    endglobals
    
    struct itemgroup
        item array items[ARRAY_SIZE]
        integer total = 0
        
        method onDestroy takes nothing returns nothing
            local integer i = .total
            loop
                exitwhen i == 0
                set .items[i] = null
                set i = i - 1
            endloop
            set .total = 0
        endmethod
    endstruct
    
    globals
        private real temp_x
        private real temp_y
        private rect temp_rect
        private real temp_radius
        private integer temp_count
        private integer temp_typeid
        private player temp_playerid
        private boolexpr temp_filter
        private itemgroup temp_itemgroup
        private integer temp_current_count
        private item enumitem
        private trigger t = CreateTrigger()
        private hashtable hasht = null
        private rect worldbounds
        public real trig = 0.
    endglobals
    
    function ItemGroupAddItem takes itemgroup g, item i returns nothing
        set g.total = g.total + 1
        set g.items[g.total] = i
        call SaveInteger (hasht, GetHandleId(i), g, g.total)
    endfunction
    
    function ItemGroupRemoveItem takes itemgroup g, item itm returns nothing
      local integer id = GetHandleId (itm)
      local integer id2 = GetHandleId (g.items[g.total])
      local integer index = LoadInteger (hasht, id, g)
      if HaveSavedInteger (hasht, id, g) then
        set g.items[index] = g.items[g.total]
        call RemoveSavedInteger (hasht, id, g)
        call RemoveSavedInteger (hasht, id2, g)
        call SaveInteger (hasht, id2, g, index)
        set g.total = g.total - 1
      endif
    endfunction
    
    private function EnumOfType takes nothing returns nothing
        if GetItemTypeId(GetEnumItem()) == temp_typeid then
            call ItemGroupAddItem(temp_itemgroup, GetEnumItem())
        endif
    endfunction
    
    private function EnumOfTypeCount takes nothing returns nothing
        if GetItemTypeId(GetEnumItem()) == temp_typeid then
            if temp_current_count > temp_count then
                return
            endif
            call ItemGroupAddItem(temp_itemgroup, GetEnumItem())
        endif
    endfunction
    
    private function EnumOfPlayer takes nothing returns nothing
        if GetItemPlayer(GetEnumItem()) == temp_playerid then
            call ItemGroupAddItem(temp_itemgroup, GetEnumItem())
        endif
    endfunction
    
    private function EnumInRect takes nothing returns nothing
        local real x = GetItemX(GetEnumItem())
        local real y = GetItemY(GetEnumItem())
        if x >= GetRectMinX(temp_rect) and x <= GetRectMaxX(temp_rect) and y >= GetRectMinY(temp_rect) and y <= GetRectMaxY(temp_rect) then
            call ItemGroupAddItem(temp_itemgroup, GetEnumItem())
        endif
    endfunction
    
    private function EnumInRectCount takes nothing returns nothing
        local real x = GetItemX(GetEnumItem())
        local real y = GetItemY(GetEnumItem())
        if x >= GetRectMinX(temp_rect) and x <= GetRectMaxX(temp_rect) and y >= GetRectMinY(temp_rect) and y <= GetRectMaxY(temp_rect) then
            if temp_current_count > temp_count then
                return
            endif
            call ItemGroupAddItem(temp_itemgroup, GetEnumItem())
            set temp_current_count = temp_current_count + 1
        endif
    endfunction
    
    private function EnumInRange takes nothing returns nothing
        local real x = GetItemX(GetEnumItem()) - temp_x
        local real y = GetItemY(GetEnumItem()) - temp_y
        if SquareRoot(x*x+y*y) <= temp_radius then
            call ItemGroupAddItem(temp_itemgroup, GetEnumItem())
        endif
    endfunction
    
    private function EnumInRangeCount takes nothing returns nothing
        local real x = GetItemX(GetEnumItem()) - temp_x
        local real y = GetItemY(GetEnumItem()) - temp_y
        if SquareRoot(x*x+y*y) <= temp_radius then
            if temp_current_count > temp_count then
                return
            endif
            call ItemGroupAddItem(temp_itemgroup, GetEnumItem())
            set temp_current_count = temp_current_count + 1
        endif
    endfunction
    
    function ItemGroupEnumItemsInRange takes itemgroup g, real x, real y, real radius, boolexpr filter returns nothing
        set temp_x = x
        set temp_y = y
        set temp_radius = radius
        set temp_itemgroup = g
        call EnumItemsInRect(worldbounds, filter, function EnumInRange)
    endfunction
    
    function ItemGroupEnumItemsInRangeCounted takes itemgroup g, real x, real y, real radius, boolexpr filter, integer count returns nothing
        set temp_x = x
        set temp_y = y
        set temp_count = count
        set temp_radius = radius
        set temp_itemgroup = g
        set temp_current_count = 0
        call EnumItemsInRect(worldbounds, filter, function EnumInRangeCount)
    endfunction
    
    function ItemGroupEnumItemsInRect takes itemgroup g, rect r, boolexpr filter returns nothing
        set temp_rect = r
        set temp_itemgroup = g
        call EnumItemsInRect(worldbounds, filter, function EnumInRect)
    endfunction
    
    function ItemGroupEnumItemsInRectCounted takes itemgroup g, rect r, boolexpr filter, integer count returns nothing
        set temp_rect = r
        set temp_count = count
        set temp_itemgroup = g
        set temp_current_count = 0
        call EnumItemsInRect(worldbounds, filter, function EnumInRectCount)
    endfunction
    
    function ItemGroupEnumItemsOfPlayer takes itemgroup g, player playerid, boolexpr filter returns nothing
        set temp_playerid = playerid
        set temp_itemgroup = g
        call EnumItemsInRect(worldbounds, filter, function EnumOfPlayer)
    endfunction
    
    function ItemGroupEnumItemsOfType takes itemgroup g, integer typeid, boolexpr filter returns nothing
        set temp_typeid = typeid
        set temp_itemgroup = g
        call EnumItemsInRect(worldbounds, filter, function EnumOfType)
    endfunction
    
    function ItemGroupEnumItemsOfTypeCount takes itemgroup g, integer typeid, boolexpr filter, integer count returns nothing
        set temp_count = count
        set temp_typeid = typeid
        set temp_itemgroup = g
        set temp_current_count = 0
        call EnumItemsInRect(worldbounds, filter, function EnumOfType)
    endfunction
    
    function ItemGroupClear takes itemgroup g returns nothing
        local integer i = g.total
        loop
            exitwhen i == 0
            set g.items[i] = null
            set i = i - 1
        endloop
    endfunction
    
    function ItemGroupAddItemGroup takes itemgroup g1, itemgroup g2 returns nothing
        local integer i = g2.total
        loop
            exitwhen i ==0 or g1.total == 100
            call ItemGroupAddItem(g1, g2.items[i])
            set i = i - 1
        endloop
    endfunction
    
    function GetEnumItemGroupItem takes nothing returns item
        return enumitem
    endfunction
    
    function CountItemsInItemGroup takes itemgroup g returns integer
        return g.total
    endfunction
    
    function IsItemInItemGroup takes itemgroup g, item it returns boolean
        local integer i = g.total
        loop
            exitwhen i == 0
            if g.items[i] == it then
                return true
            endif
            set i = i + 1
        endloop
        return false
    endfunction
    
    function ForItemGroup takes itemgroup g, code callback returns nothing
        local integer i = g.total
        loop
            exitwhen i == 0
            set enumitem = g.items[i]
            call TriggerAddAction(t, callback)
            set trig = 1.
            set trig = 0.
            call TriggerClearActions(t)
            set i = i - 1
        endloop
        set enumitem = null
    endfunction
    
    function ItemGroupPickRandomItem takes itemgroup g returns item
        return g.items[GetRandomInt(1, g.total)]
    endfunction
    
    function DestroyItemGroup takes itemgroup g returns nothing
        call g.destroy()
    endfunction
    
    function CreateItemGroup takes nothing returns itemgroup
        if hasht == null then
            set hasht = InitHashtable()
        endif
        return itemgroup.create()
    endfunction
    
    private function Ini takes nothing returns nothing
        call TriggerRegisterVariableEvent(t, "ItemGroup_trig", GREATER_THAN, 0.)
        set worldbounds = GetWorldBounds()
    endfunction
endlibrary
 

Attachments

  • ItemGroup.w3x
    20.8 KB · Views: 65
Last edited:
Level 16
Joined
Oct 12, 2008
Messages
1,570
JASS:
function ItemGroupPickRandomItem takes itemgroup g returns item
    return g.items[GetRandomInt(1,100)]
endfunction

should be

JASS:
function ItemGroupPickRandomItem takes itemgroup g returns item
    return g.items[GetRandomInt(1,g.total)]
endfunction

What if there are only 50 items in the group? Or 200 maybe? You might return a null item, while there in fact ARE items in the group, or you pick only a random one from a part of all the items.
 
Level 21
Joined
Aug 21, 2005
Messages
3,699
Templates would be so helpful...

Wouldn't even be *that* hard to implement for vexorian :(

Anyway, IMO a "group" should not have any limits to the amount of objects you can store there. Granted, what's the chance you're going to enter more than 600-some items. But then the problem is that it is memory inefficient. Most itemgroups probably won't use more than - say - 10 items?
A more generic solution should provide an "optimal" solution for both small groups and large groups. I'm talking about linked lists or hashtables...
 
A template wouldn't really work properly in this case due to the enum functions. They could be seperate, however... Anyway, don't textmacros provide enough functionality to be a decent substitute for templates? Sure, you have to run them once and they don't have that ugly <Type>Group syntax, but that's a good thing in my opinion.

Anyway, ontopic:
You should seriously use hashtables for this... it'd be much, much more useful. You could have unlimited groups holding unlimited amounts of items.
 
Level 8
Joined
Aug 4, 2006
Messages
357
Ya he should use a hashtable instead of arrays... but List uses a hashtable internally anyway, so using List would be using a hashtable. List also has the methods Sevion would need to add/remove items from a group, so he wouldn't have to make his own. Well, I guess it's up to him whether he wants to use a hashtable or List. It would be nice if someone actually used a system I made, though :(
 
Top