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
*/globalsprivate Table ShopTable
private Table WhichShop
private Table MainShop
privateunitarray DummyShop
privatebooleanarray CanShop
// The next constant is required in order to avoid conflict when more than one player// is buying from the same shopprivateconstantinteger DUMMY_SHOP_ID ='n000'privatehashtable ItemHash =InitHashtable()endglobalsprivatemodule init
staticmethod onInit takesnothingreturnsnothinglocalinteger i =0set ShopTable = Table.create()set WhichShop = Table.create()set MainShop = Table.create()setthistype.items= Table.create()call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SELECTED,function MainShops.selectShop)call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SELL_ITEM,functionthistype.changeItems)loopifGetPlayerSlotState(Player(i))==PLAYER_SLOT_STATE_PLAYINGthenset 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 emptyset CanShop[i]=trueendifset i = i +1exitwhen i >11endloopendmethodendmodulestruct Shops extendsarray//integer array items [11]static Table items
integer itemnum
privatestaticinteger instanceCount =0privatestaticthistype recycle =0privatethistype recycleNext
staticmethod clearShop takesinteger id returnsnothinglocalinteger i =0localthistypethis= WhichShop[id]loopcallRemoveItemFromStock(DummyShop[id],thistype.items[this*11+ i])set i = i +1exitwhen i >this.itemnumendloopendmethodstaticmethod changeItems takesnothingreturnsbooleanlocalplayer p =GetOwningPlayer(GetBuyingUnit())localinteger i =0localthistypethis= ShopTable[GetItemTypeId(GetSoldItem())]localinteger id =GetPlayerId(p)ifthis==0thenset p =nullreturnfalseendifcallthistype.clearShop(id)set WhichShop[id]=thisloopifnotLoadBoolean(ItemHash, id,thistype.items[this*11+ i])thencallAddItemToStock(DummyShop[id],thistype.items[this*11+ i],1,1)endifset i = i +1exitwhen i ==this.itemnumendloopset p =nullreturnfalseendmethodstaticmethod forceChangeItems takesinteger baseItem,integer id returnsbooleanlocalinteger i =0localthistypethis= ShopTable[baseItem]callthistype.clearShop(id)set WhichShop[id]=thisloopifnotLoadBoolean(ItemHash, id,thistype.items[this*11+ i])thencallAddItemToStock(DummyShop[id],thistype.items[this*11+ i],1,1)endifset i = i +1exitwhen i ==this.itemnumendloopreturnfalseendmethodstaticmethod addItemLink takesinteger itemBaseId,integer itemAddId returnsnothinglocalthistypethis= ShopTable[itemBaseId]ifthis.itemnum<11thensetthistype.items[this*11+this.itemnum]= itemAddId
setthis.itemnum=this.itemnum+1elsedebugBJDebugMsg("Item list already full")endifendmethodstaticmethod removeItem takesinteger baseItemId,integer itemId returnsnothinglocalthistypethis= ShopTable[baseItemId]localinteger i =0loopifthis.items[this*11+ i]== itemId thensetthis.itemnum=this.itemnum-1setthistype.items[this*11+ i]=thistype.items[this*11+this.itemnum]debugBJDebugMsg("REMOVED "+I2S(thistype.items[this*11+ i]))returnendifset i = i +1exitwhen i ==this.itemnumendloopendmethodstaticmethod duplicate takesinteger baseItemId,integer itemId returnsnothinglocalthistype base = ShopTable[baseItemId]localthistype that //= .allocate()localinteger i =0if(recycle ==0)thenset instanceCount = instanceCount +1set that = instanceCount
elseset that = recycle
set recycle = recycle.recycleNextendifset ShopTable[itemId]= that
set that.itemnum= base.itemnumloopsetthistype.items[that*11+ i]=thistype.items[base*11+ i]set i = i +1exitwhen i == base.itemnumendloopendmethodstaticmethod register takesinteger itemId returnsnothinglocalthistypethis//= .allocate()if(recycle ==0)thenset instanceCount = instanceCount +1setthis= instanceCount
elsesetthis= recycle
set recycle = recycle.recycleNextendifset ShopTable[itemId]=thisendmethodimplement init
endstructstruct MainShops extendsarrayprivatestaticinteger instanceCount =0privatestaticthistype recycle =0privatethistype recycleNext
integer baseItem
staticmethod selectShop takesnothingreturnsbooleanlocalunit u =GetTriggerUnit()localthistypethis= MainShop[GetHandleId(u)]localplayer p =GetTriggerPlayer()localinteger id =GetPlayerId(p)ifthis==0ornot CanShop[id]thenset p =nullreturnfalseendif// If you click the portait, it will still point your camera towards the main shopcallSetUnitX(DummyShop[id],GetUnitX(u))callSetUnitY(DummyShop[id],GetUnitY(u))call Shops.forceChangeItems(this.baseItem, id)ifGetLocalPlayer()== p thencallClearSelection()callSelectUnit(DummyShop[id],true)endifreturnfalseendmethodstaticmethod register takesunit shop,integer baseItem returnsnothinglocalthistypethis//= .allocate()if(recycle ==0)thenset instanceCount = instanceCount +1setthis= instanceCount
elsesetthis= recycle
set recycle = recycle.recycleNextendifset MainShop[GetHandleId(shop)]=thissetthis.baseItem= baseItem
endmethodendstructfunction shopAvailableForPlayer takesplayer p,boolean what returnsnothingset CanShop[GetPlayerId(p)]= what
endfunctionfunction shopAvailableForPlayerId takesinteger id,boolean what returnsnothingset CanShop[id]= what
endfunctionfunction itemAvailableForPlayer takesinteger itemid,player p,boolean what returnsnothingcallSaveBoolean(ItemHash,GetPlayerId(p), itemid,not what)endfunctionfunction itemAvailableForPlayerId takesinteger itemid,integer id,boolean what returnsnothingcallSaveBoolean(ItemHash, id, itemid,not what)endfunctionendlibrary
VersionWhichUsesCohadarsJassHelper
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
*/globalsprivate Table ShopTable
private Table WhichShop
private Table MainShop
privateunitarray DummyShop
privatebooleanarray CanShop
// The next constant is required in order to avoid conflict when more than one player// is buying from the same shopprivateconstantinteger DUMMY_SHOP_ID ='n000'privatehashtable ItemHash =InitHashtable()endglobalsprivatemodule init
staticmethod onInit takesnothingreturnsnothinglocalinteger i =0set ShopTable = Table.create()set WhichShop = Table.create()set MainShop = Table.create()setthistype.items= Table.create()call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SELECTED,function MainShops.selectShop)call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_SELL_ITEM,functionthistype.changeItems)for i =0 to 11ifGetPlayerSlotState(Player(i))==PLAYER_SLOT_STATE_PLAYINGthenset 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 emptyset CanShop[i]=trueendif
endfor
endmethodendmodulestruct Shops extendsarray//integer array items [11]static Table items
integer itemnum
privatestaticinteger instanceCount =0privatestaticthistype recycle =0privatethistype recycleNext
staticmethod clearShop takesinteger id returnsnothinglocalinteger i =0localthistypethis= WhichShop[id]for i =0 to this.itemnumcallRemoveItemFromStock(DummyShop[id],thistype.items[this*11+ i])
endfor
endmethodstaticmethod changeItems takesnothingreturnsbooleanlocalplayer p =GetOwningPlayer(GetBuyingUnit())localinteger i =0localthistypethis= ShopTable[GetItemTypeId(GetSoldItem())]localinteger id =GetPlayerId(p)ifthis==0thenset p =nullreturnfalseendifcallthistype.clearShop(id)set WhichShop[id]=thisfor i =0 to this.itemnumifnotLoadBoolean(ItemHash, id,thistype.items[this*11+ i])thencallAddItemToStock(DummyShop[id],thistype.items[this*11+ i],1,1)endif
endfor
set p =nullreturnfalseendmethodstaticmethod forceChangeItems takesinteger baseItem,integer id returnsbooleanlocalinteger i =0localthistypethis= ShopTable[baseItem]callthistype.clearShop(id)set WhichShop[id]=thisfor i =0 to (this.itemnum-1)ifnotLoadBoolean(ItemHash, id,thistype.items[this*11+ i])thencallAddItemToStock(DummyShop[id],thistype.items[this*11+ i],1,1)endif
endfor
debugBJDebugMsg(I2S(this.itemnum))returnfalseendmethodstaticmethod addItemLink takesinteger itemBaseId,integer itemAddId returnsnothinglocalthistypethis= ShopTable[itemBaseId]ifthis.itemnum<11thensetthistype.items[this*11+this.itemnum]= itemAddId
setthis.itemnum=this.itemnum+1elsedebugBJDebugMsg("Item list already full")endifendmethodstaticmethod removeItem takesinteger baseItemId,integer itemId returnsnothinglocalthistypethis= ShopTable[baseItemId]localinteger i =0for i =0 to (this.itemnum-1)ifthis.items[this*11+ i]== itemId thensetthis.itemnum=this.itemnum-1setthistype.items[this*11+ i]=thistype.items[this*11+this.itemnum]//debug BJDebugMsg("REMOVED " + I2S(thistype.items[this*11 + i]))returnendif
endfor
endmethodstaticmethod duplicate takesinteger baseItemId,integer itemId returnsnothinglocalthistype base = ShopTable[baseItemId]localthistype that //= .allocate()localinteger i =0if(recycle ==0)thenset instanceCount = instanceCount +1set that = instanceCount
elseset that = recycle
set recycle = recycle.recycleNextendifset ShopTable[itemId]= that
set that.itemnum= base.itemnumfor i =0 to (base.itemnum-1)setthistype.items[that*11+ i]=thistype.items[base*11+ i]
endfor
endmethodstaticmethod register takesinteger itemId returnsnothinglocalthistypethis//= .allocate()if(recycle ==0)thenset instanceCount = instanceCount +1setthis= instanceCount
elsesetthis= recycle
set recycle = recycle.recycleNextendifset ShopTable[itemId]=thisendmethodimplement init
endstructstruct MainShops extendsarrayprivatestaticinteger instanceCount =0privatestaticthistype recycle =0privatethistype recycleNext
integer baseItem
staticmethod selectShop takesnothingreturnsbooleanlocalunit u =GetTriggerUnit()localthistypethis= MainShop[GetHandleId(u)]localplayer p =GetTriggerPlayer()localinteger id =GetPlayerId(p)ifthis==0ornot CanShop[id]thenset p =nullreturnfalseendif// If you click the portait, it will still point your camera towards the main shopcallSetUnitX(DummyShop[id],GetUnitX(u))callSetUnitY(DummyShop[id],GetUnitY(u))call Shops.forceChangeItems(this.baseItem, id)ifGetLocalPlayer()== p thencallClearSelection()callSelectUnit(DummyShop[id],true)endifreturnfalseendmethodstaticmethod register takesunit shop,integer baseItem returnsnothinglocalthistypethis//= .allocate()if(recycle ==0)thenset instanceCount = instanceCount +1setthis= instanceCount
elsesetthis= recycle
set recycle = recycle.recycleNextendifset MainShop[GetHandleId(shop)]=thissetthis.baseItem= baseItem
endmethodendstructfunction shopAvailableForPlayer takesplayer p,boolean what returnsnothingset CanShop[GetPlayerId(p)]= what
endfunctionfunction shopAvailableForPlayerId takesinteger id,boolean what returnsnothingset CanShop[id]= what
endfunctionfunction itemAvailableForPlayer takesinteger itemid,player p,boolean what returnsnothingcallSaveBoolean(ItemHash,GetPlayerId(p), itemid,not what)endfunctionfunction itemAvailableForPlayerId takesinteger itemid,integer id,boolean what returnsnothingcallSaveBoolean(ItemHash, id, itemid,not what)endfunctionendlibrary
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.
*/privatefunction create takesnothingreturnsnothing// Create the shop on toplocalunit 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')// Equipmentscall Shops.addItemLink('I000','I002')// Potions// Now it's time to register those two items toocall Shops.register('I001')//Equipmentscall Shops.register('I002')//Potions// Now we will register items to I002 first since we will no longer have any category below potionscall Shops.addItemLink('I002','pgma')//Potion of Manacall Shops.addItemLink('I002','pghe')//Potion of Health// Now we setup another set of links with the equipments categorycall Shops.addItemLink('I001','I003')//Weaponscall Shops.addItemLink('I001','I004')//Armorcall Shops.register('I003')//Weaponscall Shops.register('I004')//Armor// Now we link items to the weapons categorycall Shops.addItemLink('I003','ratf')//Blades of attack + 15call Shops.addItemLink('I003','ofro')//Orb of Frostcall Shops.addItemLink('I003','ssil')//Staff of silencecall Shops.addItemLink('I003','stel')//Staff of teleportationcall Shops.addItemLink('I003','rat6')//Blades of attack + 6call Shops.addItemLink('I003','rat9')//Blades of attack + 9call Shops.addItemLink('I003','desc')//Dagger of escapecall Shops.addItemLink('I003','frgd')//Frostgardcall Shops.addItemLink('I003','klmm')//Kilmaimcall Shops.addItemLink('I003','ofir')//Orb of Firecall itemAvailableForPlayerId('ofir',0,false)//we disable selling og Orb of fire for Player Red// Now we link items to the armor categorycall Shops.addItemLink('I004','ckng')//Crown of kingscall Shops.addItemLink('I004','modt')//Mask of Deathcall Shops.addItemLink('I004','rde3')//Ring of protection// Now we will create a return to upper category button for the weapons categorycall 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 dummycall 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 categorycall Shops.removeItem('I006','I005')// but remove the return to upper category item from the duplicated instance.endfunctionprivatefunction init takesnothingreturnsnothingcallTimerStart(CreateTimer(),2.00,false,function create)endfunctionendlibrary
Changelog
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
Rating - 0.00 (0 votes)
(Hover and click)
Moderator Comments
Highly Recommended
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.
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...
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...
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...