• 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.

Shop System 1.2

Basically an upgraded version of the system on my sub-shop tutorial

JASS:
library ShopSystem requires Table, RegisterPlayerUnitEvent
/*
    Version 1.2 by Adiktuz
    
    Credits to Bribe and Magtheridon96 for Table and RegisterPlayerUnitEvent
    
    A simple shop system which allows you to have multiple shops/shopping category inside a single shop.
    
        If you've read my tutorial about sub-shops maybe you'll be asking what is the difference of this 
    to the system in the tutorial. Well, this one uses only one shop per player. Also with this one, all 
    items sold should be set via the trigger editor. 
    
        You can create an infinite-level shop with this one.
        
        You can only register 11 items per catergory
    
    Requirements:
        JNGP with the latest jass helper
        knowledge on how to call functions
        knowledge on how to obtain rawcodes
        knowledge on copying object data and adjusting them
     
    Make sure that the shops you will register with this system doesn't have any items sold
    on its object data 
     
    How to use:

    
    1) Copy the dummy shop, the dummy select unit ability and the dummy click ability from the object editor into your map.
    2) Make sure that you adjust the settings of the dummy shop in case it cannot recognize the dummy
        select unit ability.
    3) Copy this system and Bribe's Table library into your map.
    4) Adjust some of the globals to fit your new map.
    4) Start registering your main shops and items. See attached example trigger for better understanding.
    
    Creating category items
    
    1) Make a new item based on power ups
    2) Add the Dummy Click ability
    3) Make sure you set gold cost to 0 and set model used to none
    
    Functions to toggle shop/item availability
    
    shopAvailableForPlayer(player p, boolean what)
    shopAvailableForPlayerId(integer id, boolean what)
    
    --> Enables or disables the shop system for the player p, or the player with
        PlayerId of id, depending on the setting of boolean what
    
    itemAvailableForPlayer(integer itemid, player p, boolean what)
    itemAvailableForPlayerId(integer itemid, player p, boolean what)
    
    --> Enables or disables the item with the rawcode itemid for player p or the player with
        PlayerId of id, depending on the setting of boolean what
        
*/
    
    globals
        private Table ShopTable
        private Table WhichShop
        private Table MainShop
        private unit array DummyShop
        private boolean array CanShop
        // The next constant is required in order to avoid conflict when more than one player 
        // is buying from the same shop
        private constant integer DUMMY_SHOP_ID = 'n000' 
        private hashtable ItemHash = InitHashtable()
    endglobals
    
    private module init
        static method onInit takes nothing returns nothing
            local integer i = 0
            set ShopTable = Table.create()
            set WhichShop = Table.create()
            set MainShop = Table.create()
            set thistype.items = Table.create()
            call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SELECTED, function MainShops.selectShop)
            call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SELL_ITEM, function thistype.changeItems)
            loop
                if GetPlayerSlotState(Player(i)) == PLAYER_SLOT_STATE_PLAYING then
                    set DummyShop[i] = CreateUnit(Player(i),DUMMY_SHOP_ID, 0.0, 0.0, 0.0)
                    // I make the player own it because if not and they are not visible to the player
                    // the selection action actually runs before the dummy gets moved so the selection becomes empty
                    set CanShop[i] = true
                endif
                set i = i + 1
                exitwhen i > 11
            endloop
        endmethod
    endmodule
    

    struct Shops extends array
        
        //integer array items [11]
        static Table items
        integer itemnum
        private static integer instanceCount = 0
        private static thistype recycle = 0
        private thistype recycleNext
        
        
        static method clearShop takes integer id returns nothing
            local integer i = 0
            local thistype this = WhichShop[id]
            loop
                call RemoveItemFromStock(DummyShop[id], thistype.items[this*11 + i])
                set i = i + 1
                exitwhen i > this.itemnum
            endloop
        endmethod
        
        static method changeItems takes nothing returns boolean
            local player p = GetOwningPlayer(GetBuyingUnit())
            local integer i = 0
            local thistype this = ShopTable[GetItemTypeId(GetSoldItem())]
            local integer id = GetPlayerId(p)
            if this == 0 then
                set p = null
                return false
            endif
            call thistype.clearShop(id)
            set WhichShop[id] = this
            loop
                if not LoadBoolean(ItemHash, id, thistype.items[this*11 + i]) then
                    call AddItemToStock(DummyShop[id], thistype.items[this*11 + i], 1,1)
                endif
                set i = i + 1
                exitwhen i == this.itemnum
            endloop
            set p = null
            return false
        endmethod
        
        static method forceChangeItems takes integer baseItem, integer id returns boolean
            local integer i = 0
            local thistype this = ShopTable[baseItem]
            call thistype.clearShop(id)
            set WhichShop[id] = this
            loop
                if not LoadBoolean(ItemHash, id, thistype.items[this*11 + i]) then
                    call AddItemToStock(DummyShop[id], thistype.items[this*11 + i], 1,1)
                endif
                set i = i + 1
                exitwhen i == this.itemnum
            endloop
            return false
        endmethod
        
        static method addItemLink takes integer itemBaseId, integer itemAddId returns nothing
            local thistype this = ShopTable[itemBaseId]
            if this.itemnum < 11 then
                set thistype.items[this*11 + this.itemnum] = itemAddId
                set this.itemnum = this.itemnum + 1
            else
                debug BJDebugMsg("Item list already full")
            endif
        endmethod
        
        static method removeItem takes integer baseItemId, integer itemId returns nothing
            local thistype this = ShopTable[baseItemId]
            local integer i = 0
            loop
                if this.items[this*11 + i] == itemId then
                    set this.itemnum = this.itemnum - 1
                    set thistype.items[this*11 + i] = thistype.items[this*11 + this.itemnum]
                    debug BJDebugMsg("REMOVED " + I2S(thistype.items[this*11 + i]))
                    return
                endif
                set i = i + 1
                exitwhen i == this.itemnum
            endloop
        endmethod
        
        static method duplicate takes integer baseItemId, integer itemId returns nothing
            local thistype base = ShopTable[baseItemId]
            local thistype that //= .allocate()
            local integer i = 0
            if (recycle == 0) then
                set instanceCount = instanceCount + 1
                set that = instanceCount
            else
                set that = recycle
                set recycle = recycle.recycleNext
            endif
            set ShopTable[itemId] = that
            set that.itemnum = base.itemnum
            loop
                set thistype.items[that*11 + i] = thistype.items[base*11 + i]
                set i = i + 1
                exitwhen i == base.itemnum
            endloop
        endmethod
        
        static method register takes integer itemId returns nothing
            local thistype this //= .allocate()
            if (recycle == 0) then
                set instanceCount = instanceCount + 1
                set this = instanceCount
            else
                set this = recycle
                set recycle = recycle.recycleNext
            endif
            set ShopTable[itemId] = this
        endmethod
        
        implement init
    endstruct
    
    struct MainShops extends array
        
        private static integer instanceCount = 0
        private static thistype recycle = 0
        private thistype recycleNext
        
        integer baseItem
        
        static method selectShop takes nothing returns boolean
            local unit u = GetTriggerUnit()
            local thistype this = MainShop[GetHandleId(u)]
            local player p = GetTriggerPlayer()
            local integer id = GetPlayerId(p)
            if this == 0 or not CanShop[id] then
                set p = null
                return false
            endif
            // If you click the portait, it will still point your camera towards the main shop
            call SetUnitX(DummyShop[id], GetUnitX(u))
            call SetUnitY(DummyShop[id], GetUnitY(u))
            call Shops.forceChangeItems(this.baseItem, id)
            if GetLocalPlayer() == p then
                call ClearSelection()
                call SelectUnit(DummyShop[id], true)
            endif
            return false
        endmethod
        
        static method register takes unit shop, integer baseItem returns nothing
            local thistype this //= .allocate()
            
            if (recycle == 0) then
                set instanceCount = instanceCount + 1
                set this = instanceCount
            else
                set this = recycle
                set recycle = recycle.recycleNext
            endif
            
            set MainShop[GetHandleId(shop)] = this
            set this.baseItem = baseItem
        endmethod
        
    endstruct
    
    function shopAvailableForPlayer takes player p, boolean what returns nothing
        set CanShop[GetPlayerId(p)] = what
    endfunction
    
    function shopAvailableForPlayerId takes integer id, boolean what returns nothing
        set CanShop[id] = what
    endfunction
    
    function itemAvailableForPlayer takes integer itemid, player p, boolean what returns nothing
        call SaveBoolean(ItemHash, GetPlayerId(p), itemid, not what)
    endfunction
    
    function itemAvailableForPlayerId takes integer itemid, integer id, boolean what returns nothing
        call SaveBoolean(ItemHash, id, itemid, not what)
    endfunction
    
endlibrary


JASS:
library ShopSystem requires Table, RegisterPlayerUnitEvent
/*
    Version 1.2 by Adiktuz
    
    Credits:
    Bribe for Table 
    Magtheridon96 for RegisterPlayerUnitEvent
    Cohadar for his JassHelper update
    
    
    A simple shop system which allows you to have multiple shops/shopping category inside a single shop.
    
        If you've read my tutorial about sub-shops maybe you'll be asking what is the difference of this 
    to the system in the tutorial. Well, this one uses only one shop per player. Also with this one, all 
    items sold should be set via the trigger editor. 
    
        You can create an infinite-level shop with this one.
        
        You can only register 11 items per catergory
    
    Requirements:
        JNGP with the Cohadar's latest jass helper
        knowledge on how to call functions
        knowledge on how to obtain rawcodes
        knowledge on copying object data and adjusting them
     
    Make sure that the shops you will register with this system doesn't have any items sold
    on its object data 
     
    How to use:

    
    1) Copy the dummy shop, the dummy select unit ability and the dummy click ability from the object editor into your map.
    2) Make sure that you adjust the settings of the dummy shop in case it cannot recognize the dummy
        select unit ability.
    3) Copy this system and Bribe's Table library into your map.
    4) Adjust some of the globals to fit your new map.
    4) Start registering your main shops and items. See attached example trigger for better understanding.
    
    Creating category items
    
    1) Make a new item based on power ups
    2) Add the Dummy Click ability
    3) Make sure you set gold cost to 0 and set model used to none
    
    Functions to toggle shop/item availability
    
    shopAvailableForPlayer(player p, boolean what)
    shopAvailableForPlayerId(integer id, boolean what)
    
    --> Enables or disables the shop system for the player p, or the player with
        PlayerId of id, depending on the setting of boolean what
    
    itemAvailableForPlayer(integer itemid, player p, boolean what)
    itemAvailableForPlayerId(integer itemid, integer id, boolean what)
    
    --> Enables or disables the item with the rawcode itemid for player p or the player with
        PlayerId of id, depending on the setting of boolean what
        
*/
    
    globals
        private Table ShopTable
        private Table WhichShop
        private Table MainShop
        private unit array DummyShop
        private boolean array CanShop
        // The next constant is required in order to avoid conflict when more than one player 
        // is buying from the same shop
        private constant integer DUMMY_SHOP_ID = 'n000' 
        private hashtable ItemHash = InitHashtable()
    endglobals
    
    private module init
        static method onInit takes nothing returns nothing
            local integer i = 0
            set ShopTable = Table.create()
            set WhichShop = Table.create()
            set MainShop = Table.create()
            set thistype.items = Table.create()
            call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SELECTED, function MainShops.selectShop)
            call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SELL_ITEM, function thistype.changeItems)
            for i = 0 to 11
                if GetPlayerSlotState(Player(i)) == PLAYER_SLOT_STATE_PLAYING then
                    set DummyShop[i] = CreateUnit(Player(i),DUMMY_SHOP_ID, 0.0, 0.0, 0.0)
                    // I make the player own it because if not and they are not visible to the player
                    // the selection action actually runs before the dummy gets moved so the selection becomes empty
                    set CanShop[i] = true
                endif
            endfor
        endmethod
    endmodule
    

    struct Shops extends array
        
        //integer array items [11]
        static Table items
        integer itemnum
        private static integer instanceCount = 0
        private static thistype recycle = 0
        private thistype recycleNext
        
        
        static method clearShop takes integer id returns nothing
            local integer i = 0
            local thistype this = WhichShop[id]
            for i = 0 to this.itemnum
                call RemoveItemFromStock(DummyShop[id], thistype.items[this*11 + i])
            endfor
        endmethod
        
        static method changeItems takes nothing returns boolean
            local player p = GetOwningPlayer(GetBuyingUnit())
            local integer i = 0
            local thistype this = ShopTable[GetItemTypeId(GetSoldItem())]
            local integer id = GetPlayerId(p)
            if this == 0 then
                set p = null
                return false
            endif
            call thistype.clearShop(id)
            set WhichShop[id] = this
            for i = 0 to this.itemnum
                if not LoadBoolean(ItemHash, id, thistype.items[this*11 + i]) then
                    call AddItemToStock(DummyShop[id], thistype.items[this*11 + i], 1,1)
                endif
            endfor
            set p = null
            return false
        endmethod
        
        static method forceChangeItems takes integer baseItem, integer id returns boolean
            local integer i = 0
            local thistype this = ShopTable[baseItem]
            call thistype.clearShop(id)
            set WhichShop[id] = this
            for i = 0 to (this.itemnum - 1)
                if not LoadBoolean(ItemHash, id, thistype.items[this*11 + i]) then
                    call AddItemToStock(DummyShop[id], thistype.items[this*11 + i], 1,1)
                endif
            endfor
            debug BJDebugMsg(I2S(this.itemnum))
            return false
        endmethod
        
        static method addItemLink takes integer itemBaseId, integer itemAddId returns nothing
            local thistype this = ShopTable[itemBaseId]
            if this.itemnum < 11 then
                set thistype.items[this*11 + this.itemnum] = itemAddId
                set this.itemnum = this.itemnum + 1
            else
                debug BJDebugMsg("Item list already full")
            endif
        endmethod
        
        static method removeItem takes integer baseItemId, integer itemId returns nothing
            local thistype this = ShopTable[baseItemId]
            local integer i = 0
            for i = 0 to (this.itemnum - 1)
                if this.items[this*11 + i] == itemId then
                    set this.itemnum = this.itemnum - 1
                    set thistype.items[this*11 + i] = thistype.items[this*11 + this.itemnum]
                    //debug BJDebugMsg("REMOVED " + I2S(thistype.items[this*11 + i]))
                    return
                endif
            endfor
        endmethod
        
        static method duplicate takes integer baseItemId, integer itemId returns nothing
            local thistype base = ShopTable[baseItemId]
            local thistype that //= .allocate()
            local integer i = 0
            if (recycle == 0) then
                set instanceCount = instanceCount + 1
                set that = instanceCount
            else
                set that = recycle
                set recycle = recycle.recycleNext
            endif
            set ShopTable[itemId] = that
            set that.itemnum = base.itemnum
            for i = 0 to (base.itemnum - 1)
                set thistype.items[that*11 + i] = thistype.items[base*11 + i]
            endfor
        endmethod
        
        static method register takes integer itemId returns nothing
            local thistype this //= .allocate()
            if (recycle == 0) then
                set instanceCount = instanceCount + 1
                set this = instanceCount
            else
                set this = recycle
                set recycle = recycle.recycleNext
            endif
            set ShopTable[itemId] = this
        endmethod
        
        implement init
    endstruct
    
    struct MainShops extends array
        
        private static integer instanceCount = 0
        private static thistype recycle = 0
        private thistype recycleNext
        
        integer baseItem
        
        static method selectShop takes nothing returns boolean
            local unit u = GetTriggerUnit()
            local thistype this = MainShop[GetHandleId(u)]
            local player p = GetTriggerPlayer()
            local integer id = GetPlayerId(p)
            if this == 0 or not CanShop[id] then
                set p = null
                return false
            endif
            // If you click the portait, it will still point your camera towards the main shop
            call SetUnitX(DummyShop[id], GetUnitX(u))
            call SetUnitY(DummyShop[id], GetUnitY(u))
            call Shops.forceChangeItems(this.baseItem, id)
            if GetLocalPlayer() == p then
                call ClearSelection()
                call SelectUnit(DummyShop[id], true)
            endif
            return false
        endmethod
        
        static method register takes unit shop, integer baseItem returns nothing
            local thistype this //= .allocate()
            
            if (recycle == 0) then
                set instanceCount = instanceCount + 1
                set this = instanceCount
            else
                set this = recycle
                set recycle = recycle.recycleNext
            endif
            
            set MainShop[GetHandleId(shop)] = this
            set this.baseItem = baseItem
        endmethod
        
    endstruct
    
    function shopAvailableForPlayer takes player p, boolean what returns nothing
        set CanShop[GetPlayerId(p)] = what
    endfunction
    
    function shopAvailableForPlayerId takes integer id, boolean what returns nothing
        set CanShop[id] = what
    endfunction
    
    function itemAvailableForPlayer takes integer itemid, player p, boolean what returns nothing
        call SaveBoolean(ItemHash, GetPlayerId(p), itemid, not what)
    endfunction
    
    function itemAvailableForPlayerId takes integer itemid, integer id, boolean what returns nothing
        call SaveBoolean(ItemHash, id, itemid, not what)
    endfunction
    
endlibrary


JASS:
library Sample initializer init requires ShopSystem
    
    /*
            In this example, we will be making shop which is both a two-level and a three-level shop.
        Here you will be familiarized to the method of registering main shops and linking items to the
        system. We will also make another shop which sells directly what the second level of the other
        shop sells. We will also make a return to upper category dummy item. This was made so that you'll have a better grasp on how to use the system. 
        
            Theoretically, you can create an infinite-level shop using the ShopSystem.
    */
    
    private function create takes nothing returns nothing
        // Create the shop on top
        local unit shop = CreateUnit(Player(15), 'n001', 983.0, -892.0, 270.0)
        /* Register the created shop as a main shop
         I000 is the rawcode of the dummy item which we will use in order to determine
         which items should the shop initialy have
        */
        call MainShops.register(shop, 'I000')
        /* We register I000 to the shop system so that we can now link items to be sold when I000 is sold.
            and since our shop is linked with I000, whenever we click the shop, it will show the items linked
            to I000
        */
        call Shops.register('I000')
        /* Now we will link items to I000, take note that this items will also be used as categories
            so  we will register them to the system too
        */
        call Shops.addItemLink('I000', 'I001') // Equipments
        call Shops.addItemLink('I000', 'I002') // Potions
        // Now it's time to register those two items too
        call Shops.register('I001') //Equipments
        call Shops.register('I002') //Potions
        // Now we will register items to I002 first since we will no longer have any category below potions
        call Shops.addItemLink('I002', 'pgma') //Potion of Mana
        call Shops.addItemLink('I002', 'pghe') //Potion of Health
        // Now we setup another set of links with the equipments category
        call Shops.addItemLink('I001', 'I003') //Weapons
        call Shops.addItemLink('I001', 'I004') //Armor
        call Shops.register('I003') //Weapons
        call Shops.register('I004') //Armor
        // Now we link items to the weapons category
        call Shops.addItemLink('I003', 'ratf') //Blades of attack + 15
        call Shops.addItemLink('I003', 'ofro') //Orb of Frost
        call Shops.addItemLink('I003', 'ssil') //Staff of silence
        call Shops.addItemLink('I003', 'stel') //Staff of teleportation
        call Shops.addItemLink('I003', 'rat6') //Blades of attack + 6
        call Shops.addItemLink('I003', 'rat9') //Blades of attack + 9
        call Shops.addItemLink('I003', 'desc') //Dagger of escape
        call Shops.addItemLink('I003', 'frgd') //Frostgard
        call Shops.addItemLink('I003', 'klmm') //Kilmaim
        call Shops.addItemLink('I003', 'ofir') //Orb of Fire
        call itemAvailableForPlayerId('ofir', 0, false) //we disable selling og Orb of fire for Player Red
        // Now we link items to the armor category
        call Shops.addItemLink('I004', 'ckng') //Crown of kings
        call Shops.addItemLink('I004', 'modt') //Mask of Death
        call Shops.addItemLink('I004', 'rde3') //Ring of protection
        // Now we will create a return to upper category button for the weapons category
        call Shops.duplicate('I001', 'I005') 
        // the .duplicate method automatically registers the new item so no need to call .register
        // Upper category of weapons is equipments so we duplicate its instance into the upper category dummy
        call Shops.addItemLink('I003', 'I005') // Don't forget to link it to the weapons dummy
        // Now we will create another shop at the left which sells the items in the weapons category of our
        // previous shop.
        set shop = CreateUnit(Player(15), 'n001', 93.4, -1430.0, 270.0)
        call MainShops.register(shop, 'I006') 
        // We actually created a new dummy item since this shop cannot have the return to upper
        // category option since it sells the items from the weapons category directly
        // to easily do this:
        call Shops.duplicate('I003', 'I006')  // we duplicate the weapons category
        call Shops.removeItem('I006', 'I005') // but remove the return to upper category item from the duplicated instance. 
    endfunction
    
    private function init takes nothing returns nothing
        call TimerStart(CreateTimer(), 2.00, false, function create)
    endfunction
    
endlibrary


Version 1.1 - turned the structs into array structs
Version 1.1b - replaced the static integer array with Table
Version 1.1c - fixed the possible cause of the desync when selecting shops
Version 1.1d - ensured that the system won't let more than 11 items per category due to some weird wc3 function...
Version 1.2 - Added functionality to disable the whole shop system or specific items for a player
- Added a version which requires Cohadar's Jass helper update [I changed the loops to use the for i = x to y keyword]


Credits to Bribe and Magtheridon96 for Table and RegisterPlayerUnitEvent

Keywords:
adiktuz, scrolls, rpg, systems, shops, items, subshops, categories, vending, sell, buy
Contents

Shop System 1.2 (Map)

Reviews
4th Jun 2012 Bribe: This is well-coded and useful. I would like to use this for when I get back to working on my WarChasers II update as it looks like it's going to save me a lot of time (I hate doing this stuff in object editor and my time is very...

Moderator

M

Moderator

4th Jun 2012
Bribe: This is well-coded and useful. I would like to use this for when I get back to working on my WarChasers II update as it looks like it's going to save me a lot of time (I hate doing this stuff in object editor and my time is very limited lately). I'll give it 5/5 for now as I can't find any faults myself.
 
Level 3
Joined
Apr 4, 2012
Messages
64
added to my map and when i compile............ tried compiling the your map alone it had no problem.... any ideia?
w9e1bm.png
 
Level 3
Joined
Apr 4, 2012
Messages
64
0.A.2.B.jasshelper.7z

i downloaded that and still gave the same error

Only gives error "ON MY MAP" i can compile your example with no problem

pp say its a jass helper fail..... i have the lastest FOR SURE!

can anyone pass me their jass helper so i can test? or the hole editor
 
Don't post here if you're gonna send me a PM too... or don't PM me if you're gonna post here too... it makes it harder to communicate...

so just choose one...

well, make sure you placed it at the right location... and make sure that JNGP is closed when you update it...

and oh, is that the JH from moyack's site? because there are two .B versions actually... one is from the cJASS project and is older and the other one was the latest JH which is currently being developed by Cohadar which is downloadable from moyack's site...
 
rawcodes should be written within ''

sample

'I000'

and put them in hidden tags plese...

and oh, the rawcode that should be placed on the MainShop.register is the rawcode of an item which you will be registering with the system... you will link what you want the acedemy to sell via that item...

and oh, the trigger I sent you will register any Academy that finishes building no matter who made it...

about the second pic, what's the prob?

and oh, I might not be able to answer within one hour...
 
Level 3
Joined
Apr 4, 2012
Messages
64
rawcodes should be written within ''

sample

'I000'

and put them in hidden tags plese...

and oh, the rawcode that should be placed on the MainShop.register is the rawcode of an item which you will be registering with the system... you will link what you want the acedemy to sell via that item...

and oh, the trigger I sent you will register any Academy that finishes building no matter who made it...

about the second pic, what's the prob?

and oh, I might not be able to answer within one hour...

well what about now?
pic1
http://i42.tinypic.com/359cln6.png
pic2
http://i41.tinypic.com/dolyxy.png
 
Last edited:
First, I already told you, put those image in HIDDEN TAGS...

for the second one, it should be debug BJDebug something... you seem to have lost it...

look at this, this was the original code...

JASS:
static method addItemLink takes integer itemBaseId, integer itemAddId returns nothing
            local thistype this = ShopTable[itemBaseId]
            if this.itemnum < 11 then
                set this.items[this.itemnum] = itemAddId
                set this.itemnum = this.itemnum + 1
            else
                debug BJDebugMsg("Item list already full")
            endif
        endmethod

for the first one, it has a typo... it should be GetConstructedStructure()

seriously, if you looked at the Trig_Academy_Conditions a few lines above, you would have noticed that there is a typo...

Lastly, I already told you, put those image in HIDDEN TAGS...
 
I know... but JH won't let me use array structs because they cannot have array members yet...

JASS:
struct A extends array
      integer array b [10]
endstruct

/*
    JASS helper throws an error saying array structs cannot have array members
*/

I also tried using the custom allocation for non-array structs but it didn't work fine... the system got messed up...

oh, forgot to remove those... thanks

edit: updated...
 
Level 3
Joined
Apr 4, 2012
Messages
64
First, I already told you, put those image in HIDDEN TAGS...

for the second one, it should be debug BJDebug something... you seem to have lost it...

look at this, this was the original code...

JASS:
static method addItemLink takes integer itemBaseId, integer itemAddId returns nothing
            local thistype this = ShopTable[itemBaseId]
            if this.itemnum < 11 then
                set this.items[this.itemnum] = itemAddId
                set this.itemnum = this.itemnum + 1
            else
                debug BJDebugMsg("Item list already full")
            endif
        endmethod

for the first one, it has a typo... it should be GetConstructedStructure()

seriously, if you looked at the Trig_Academy_Conditions a few lines above, you would have noticed that there is a typo...

Lastly, I already told you, put those image in HIDDEN TAGS...

srry i dk how to put in hidden tags second i didn't lost it cuz its a copy paste of ur code i still get the second error.... its a 100% copy paste

and i copyed thisone it gives the same error (pic2-syntax error)

about the first error srry i had it spelled wrong
 
Level 10
Joined
Sep 19, 2011
Messages
527
I know... but JH won't let me use array structs because they cannot have array members yet...

JASS:
struct A extends array
      integer array b [10]
endstruct

/*
    JASS helper throws an error saying array structs cannot have array members
*/

I also tried using the custom allocation for non-array structs but it didn't work fine... the system got messed up...

oh, forgot to remove those... thanks

edit: updated...

Ah... you right, I forgot the item array that you have inside the struct e__e
 
Last edited:
Level 16
Joined
Aug 7, 2009
Messages
1,406
@Luorax
What do yo mean about using array struct with 2D array member?...

JASS:
struct Shops  
        
    integer array items [11]

->

JASS:
struct Shops extends array
        
    static integer array items


JASS:
call RemoveItemFromStock(DummyShop[id], this.items[i])

->
JASS:
call RemoveItemFromStock(DummyShop[id], thistype.items[this*11+i])
 
Level 16
Joined
Aug 7, 2009
Messages
1,406
As far as I know struct arrays work exactly like I wrote it down two posts above, mine is just an inlined version of it, as non-static arrays are not compatible with array structs. I personally prefer using array structs as they don't generate so much garbage as their non-array brothers do.
 
I mean the array index for the static array... Since limit of index is 8190 for arrays, so the amount of items I can register in the "static integer array items" is 8191 (including 0 index)... 8191/11 [11 is the max index of items that can be linked with a category including 0] = approximately 744, so only 744 category items... so if the struct value becomes like 750, it will not be able to register items into the "static integer array items" since 750*11 is already > 8190...

but as I said, maybe no one will ever use more than 744 category items... unless maybe you're making shops which has about 20 levels or more but I believe there is no sense in going that far...

anyway, I will be uploading the new version updated with the array struct...

EDIT: oh wait, I realized the max should be 12 not 11... as there as 12 item slots in a shop...
 
Level 3
Joined
Apr 4, 2012
Messages
64
I dk why but when the map starts i get a text msg "Item list already full" i make the shop and everything works fine besides i kick everyone out if i click anywhere in the shop. -.-!


tested on original map, it disconnects everyone but the host when u open anything inside the shop
 
Last edited:
Question 1: That means that you registered more than 12 items on a single category... I placed that limiter because shops can only show 12 items

I'll take a look at that...

But maybe, about 12 hours from now as I'm busy at the moment...

oh wait, I think I know why it desyncs... I think three of the functions inside the getlocalplayer should be outside...

EDIT: Updated! I think that should fix the desync issue...
 
Last edited:
Level 3
Joined
Apr 4, 2012
Messages
64
Question 1: That means that you registered more than 12 items on a single category... I placed that limiter because shops can only show 12 items

I'll take a look at that...

But maybe, about 12 hours from now as I'm busy at the moment...

oh wait, I think I know why it desyncs... I think three of the functions inside the getlocalplayer should be outside...

EDIT: Updated! I think that should fix the desync issue...

ty ill test it again and the skills not that i know of i dont have more than 12

Edit: It's working properly, 1 thing how do i set the bounds of the house? cuz right now the player will only see with no fog over the house cuz its ex: red player owns the shop but its like the house is neutral if u go off area it goes on shadows, but u own it..... strange and it can be built anywhere how to set bounds?
 
Last edited:
Level 3
Joined
Apr 4, 2012
Messages
64
script

can you send me the script ur using to register the items?

can u tell me why the 11 slot doest work? x2y3 even if i code it stays blank? is it because its the cancel slot?
c
here

This is the script that regists;
  • ResgisterShop
    • Events
      • Unit - A unit Finishes construction
    • Conditions
      • (Unit-type of (Constructed structure)) Equal to Hero Shop
    • Actions
      • Custom script: call MainShops.register(GetConstructedStructure(), 'I03Y')
And this is my shop:

JASS:
library Sample initializer init requires ShopSystem
    
    /*
            In this example, we will be making shop which is both a two-level and a three-level shop.
        Here you will be familiarized to the method of registering main shops and linking items to the
        system. We will also make another shop which sells directly what the second level of the other
        shop sells. We will also make a return to upper category dummy item. This was made so that you'll have a better grasp on how to use the system. 
        
            Theoretically, you can create an infinite-level shop using the ShopSystem.
    */
        private function create takes nothing returns nothing
        
        call Shops.register('I03Y')
        call Shops.addItemLink('I03Y', 'I040') // Hero Abilities Shop
        call Shops.addItemLink('I03Y', 'I03X') // Scrolls Shop
        // Now it's time to register those two items too
        call Shops.register('I040') //Hero Abilities Shop
        call Shops.register('I03X') //Scrolls Shop
/*----------------------------------------------------------------------------------------------------------------*/
        // Now we will register items to I03X first since we will no longer have any category below Scrolls Shop
        call Shops.addItemLink('I03X', 'pgma') //Potion of Mana
        call Shops.addItemLink('I03X', 'pghe') //Potion of Health
        call Shops.addItemLink('I03X', 'tint') //Tome of Intelligence +5
        call Shops.addItemLink('I03X', 'tdex') //Tome of Agility +5
        call Shops.addItemLink('I03X', 'tstr') //Tome of Strength +5
        call Shops.addItemLink('I03X', 'manh') //Manual of Health
        call Shops.addItemLink('I03X', 'ankh') //Ankh of Reincarnation
        call Shops.addItemLink('I03X', 'rwiz') //Sobi Mask
        call Shops.addItemLink('I03X', 'gcel') //Gloves of Haste
        call Shops.addItemLink('I03X', 'bspd') //Boots of Speed
        call Shops.addItemLink('I03X', 'ward') //Warsong Battle Drums
        
/*----------------------------------------------------------------------------------------------------------------*/
        // Now we setup another set of links with the Hero Abilities Shop category
        call Shops.addItemLink('I040', 'I03W') //Attack Abilities Pack 1
        call Shops.addItemLink('I040', 'I03R') //Attack Abilities Pack 2
        call Shops.addItemLink('I040', 'I034') //Aura Abilities
        call Shops.addItemLink('I040', 'I03M') //Auto Cast Abilities
        call Shops.addItemLink('I040', 'I03N') //Defensive Abilities
        call Shops.addItemLink('I040', 'I03O') //Summon Abilities
        call Shops.addItemLink('I040', 'I03P') //Passive Abilities
        call Shops.addItemLink('I040', 'I03Q') //Support Abilities
        call Shops.register('I03W') //Attack Abilities Pack 1
        call Shops.register('I03R') //Attack Abilities Pack 2
        call Shops.register('I034') //Aura Abilities
        call Shops.register('I03M') //Auto Cast Abilities
        call Shops.register('I03N') //Defensive Abilities
        call Shops.register('I03O') //Summon Abilities
        call Shops.register('I03P') //Passive Abilities
        call Shops.register('I03Q') //Support Abilities
/*----------------------------------------------------------------------------------------------------------------*/
        // Now we link items to the Attack Abilities Pack 1 Category
        call Shops.addItemLink('I03W', 'I011') //Blizzard
        call Shops.addItemLink('I03W', 'I014') //Breath of Fire
        call Shops.addItemLink('I03W', 'I027') //Carrion Swarm
        call Shops.addItemLink('I03W', 'I028') //Chain Lightning
        call Shops.addItemLink('I03W', 'I01L') //Death Coil
        call Shops.addItemLink('I03W', 'I00I') //Entangling Roots
        call Shops.addItemLink('I03W', 'I023') //Fan of Knives
        call Shops.addItemLink('I03W', 'I02U') //Fire Ball
        call Shops.addItemLink('I03W', 'I005') //Flame Strike
        call Shops.addItemLink('I03W', 'I00H') //Impale >Full<
        
        // Now we link items to the Attack Abilities Pack 2 Category
        call Shops.addItemLink('I03R', 'I01D') //Rain of Fire
        call Shops.addItemLink('I03R', 'I00X') //Shadow Strike
        call Shops.addItemLink('I03R', 'I02H') //ShockWave
        call Shops.addItemLink('I03R', 'I01X') //Storm Bolt
        call Shops.addItemLink('I03R', 'I00V') //Thunder Clap
        call Shops.addItemLink('I03R', 'I02F') //War Stomp
        call Shops.addItemLink('I03R', 'I00Y') //Mind Burn
        call Shops.addItemLink('I03R', 'I00C') //Cluster Rockets
        call Shops.addItemLink('I03R', 'I006') //Frost Nova
        call Shops.addItemLink('I03R', 'I021') //Forked Lightning >Full<
        
        // Now we link items to the Aura Abilities Category
        call Shops.addItemLink('I034', 'I013') //Brilliance
        call Shops.addItemLink('I034', 'I01E') //Devotion
        call Shops.addItemLink('I034', 'I00K') //Endurance
        call Shops.addItemLink('I034', 'I039') //Melee
        call Shops.addItemLink('I034', 'I037') //True Shot
        call Shops.addItemLink('I034', 'I00P') //Unholy
        call Shops.addItemLink('I034', 'I018') //Vampiric >3 slots left<
        
        // Now we link items to the Auto Cast Abilities Category
        call Shops.addItemLink('I03M', 'I012') //Black Arrow
        call Shops.addItemLink('I03M', 'I00G') //Carrion Beetles
        call Shops.addItemLink('I03M', 'I006') //Frost Armor
        call Shops.addItemLink('I03M', 'I00D') //Frost Arrows
        call Shops.addItemLink('I03M', 'I02G') //Searing Arrows >5 slots left<
        
        // Now we link items to the Defensive Abilities Category
        call Shops.addItemLink('I03N', 'I01M') //Death Pact
        call Shops.addItemLink('I03N', 'I014') //Divine Shield
        call Shops.addItemLink('I03N', 'I01G') //Drunken haze
        call Shops.addItemLink('I03N', 'I01Z') //Hex
        call Shops.addItemLink('I03N', 'I000') //Howl of Terror
        call Shops.addItemLink('I03N', 'I01Q') //Life Drain
        call Shops.addItemLink('I03N', 'I01C') //Mana Sield
        call Shops.addItemLink('I03N', 'I01A') //Mirror Image
        call Shops.addItemLink('I03N', 'I01Y') //Mana Drain
        call Shops.addItemLink('I03W', 'I01V') //Mana Burn >Full<
        
        // Now we link items to the Summon Abilities Category
        call Shops.addItemLink('I03O', 'I003') //Feral Spirit
        call Shops.addItemLink('I03O', 'I007') //Force of Nature
        call Shops.addItemLink('I03O', 'I01P') //Lava Spawn
        call Shops.addItemLink('I03O', 'I02C') //Serpent Wards
        call Shops.addItemLink('I03O', 'I016') //Summon Bear
        call Shops.addItemLink('I03O', 'I02D') //Summon Hawk
        call Shops.addItemLink('I03O', 'I00E') //Summon KillBeast
        call Shops.addItemLink('I03O', 'I00N') //Summon Water Elemental >2 slots left<
        
        // Now we link items to the Passive Abilities Category
        call Shops.addItemLink('I03P', 'I035') //Barrage
        call Shops.addItemLink('I03P', 'I01W') //Bash
        call Shops.addItemLink('I03P', 'I025') //Cleave
        call Shops.addItemLink('I03P', 'I026') //Critical Strike
        call Shops.addItemLink('I03P', 'I00S') //Detect Invisible
        call Shops.addItemLink('I03P', 'I01N') //Drunken Brawler
        call Shops.addItemLink('I03P', 'I02E') //Evasion
        call Shops.addItemLink('I03P', 'I00J') //Incinerate
        call Shops.addItemLink('I03P', 'I01J') //Spiked Carapace >1 slots left<
        
        // Now we link items to the Support Abilities Category
        call Shops.addItemLink('I03Q', 'I019') //Banish
        call Shops.addItemLink('I03Q', 'I038') //Get Smart
        call Shops.addItemLink('I03Q', 'I002') //Healing Spray
        call Shops.addItemLink('I03Q', 'I02J') //Healing Wave
        call Shops.addItemLink('I03Q', 'I001') //Holy Light
        call Shops.addItemLink('I03Q', 'I03V') //Wind Walk
        call Shops.addItemLink('I03Q', 'I03T') //Agility Bonus
        call Shops.addItemLink('I03Q', 'I00M') //Intelligence Bonus
        call Shops.addItemLink('I03Q', 'I03S') //Strength Bonus >1 slot left<
        
/*----------------------------------------------------------------------------------------------------------------*/
        // Now we will create a return to upper category button for the Attack Abilities Pack 1 Category
        call Shops.duplicate('I040', 'I03U') 
        // the .duplicate method automatically registers the new item so no need to call .register
        // Upper Category Dummy
        call Shops.addItemLink('I03W', 'I03U')
        call Shops.addItemLink('I03R', 'I03U')
        call Shops.addItemLink('I034', 'I03U')
        call Shops.addItemLink('I03M', 'I03U')
        call Shops.addItemLink('I03N', 'I03U')
        call Shops.addItemLink('I03O', 'I03U')
        call Shops.addItemLink('I03P', 'I03U')
        call Shops.addItemLink('I03Q', 'I03U')
        
    endfunction
    
    private function init takes nothing returns nothing
        call TimerStart(CreateTimer(), 2.00, false, function create)
    endfunction
    
endlibrary
 
Hmm... I'll run tests on it, it might have something to do with the variables...

There's no cancel slot in this system unless its added by the user...

EDIT: It seems that the game actually leaves that space blank, I think it has something to do with the fact that the items were added via triggers, because I believe that for items added thru the OE, disabling the icon for the select unit actually allows 12 items inside the shop... I'm trying to find some workaround...

On my tests, I can register 11 items successfully, the 12th one show... and it seems that if there is an item with position [3,2], it will displace the blank space...

so for now, make sure you only register 11 items... and you can actually enable the Select Unit button so it won't look bad, and I think having it enabled is preferable...

Anyway, updated the map so that it won't let users register more than 11 items per category, also added that note at the header
 
Last edited:
Level 3
Joined
Apr 4, 2012
Messages
64
Hmm... I'll run tests on it, it might have something to do with the variables...

There's no cancel slot in this system unless its added by the user...

EDIT: It seems that the game actually leaves that space blank, I think it has something to do with the fact that the items were added via triggers, because I believe that for items added thru the OE, disabling the icon for the select unit actually allows 12 items inside the shop... I'm trying to find some workaround...

On my tests, I can register 11 items successfully, the 12th one show... and it seems that if there is an item with position [3,2], it will displace the blank space...

so for now, make sure you only register 11 items... and you can actually enable the Select Unit button so it won't look bad, and I think having it enabled is preferable...

Anyway, updated the map so that it won't let users register more than 11 items per category, also added that note at the header

11 counting with the dummy so its 10 items plus the dummy to go back if used ye 11 :D onother thing when i call duplicate i have to use different items to return on level ex: i got

call Shops.duplicate('I040', 'I03U')

so anywhere i put the I03U it will go back to the container I040 Correct?
so to call the other with diff dummy

ill do like this:

call Shops.duplicate('I03Y', 'I03M') Correct?

and about the bounds? how to set them i dont want the building being able to be constructed anywhere? ty
 
Level 3
Joined
Apr 4, 2012
Messages
64
Q1) I think so, I cannot understand the query much... ^_^

Q2) Well, if its a building, then it will by default not be buildable on unbuildable terrain...
Q1 the dummy to go back on category needs to be different or it can have 2 reference? probably need 2 dummys to have 2 diferent categorys to go like the dummy I03N goes up to X and I03M goes up to Y. but nvm

Q2 LOL OFC but wait a sec i think i might have the scale low and the shops seams so big still its funny i can build the shop on trees on clifs....
 
Level 14
Joined
Aug 8, 2010
Messages
1,022
I am having a problem. I don't know if someone mentioned it before, but the "Return to upper category" button doesn't appear for me. Instead, the normal War3 button "Switch User" appears... The upper category button only appears in Equipment -> Weapons (the Switch User button also appears), which means that i can only go back and forth between the Equipment category and Weapons category. Otherwise, the system is great. :)
 
That is not a bug... If you looked at the fully commented example trigger, I only added a return button for the weapons category...

The return button is not a universal button, it is just like the other categorical items... You will create one per every "back" capability that you need...

I'm still thinking about making it universal, but until I'm sure that I made the script to avoid every possible bug that would arise from it, I won't be adding it...
 
Level 6
Joined
Oct 23, 2011
Messages
182
Do shops have infinite range? o.o
Would changing range value on Select Unit Dummy cause no problem?
Items are also restocked immediately upon reselection regardless if item has restock period

also debug lines don't compile

Shop 'unregister' would be nice as well
 
Last edited:
Level 19
Joined
Mar 18, 2012
Messages
1,716
A very good system and easy to setup. I can recommend it to anyone who wants to add a complex shop system to his map.

While editing/optimizing it a little bit to my personal needs (single unit event instead of RegisterPlayerUnitEvent, UnitUserData instead of UnitHandle, Alloc,..)
I noticed you have a unit leak in MainShops method selectShop.
 
Top