Heya Folks!
So I have gone through various different plugins that use the functionality below, but I wanted something that provided me a bit more freedom and the ability to easily integrate shops into my other scripts!
Below is the script as well as an example shop script. It is very cut and paste friendly. I have also included a video on how to actually use the script in game to make shop menus!
Feel free to send me any suggestions or ideas on how to improve this system!
Video (Please note it does not contain instructions for a Sell Items shop, see P.S.)
https://www.youtube.com/watch?v=CswUR9UZvcs&t=197s
Current Version: 1.1 (It has been overhauled before posting, see P.S.)
P.S.
The ability to make a shop where players can sell items has been added but was not part of the original video!
When using the /createshop command add the argument SellShop at the end of the command and the system will create a shop for selling items too! Everything works exactly the same way accept when you make the script for the Sell Items menu make sure that it is checking if the player has the items in question and change the take money commands accordingly.
With the right knowledge this script allows for VERY customizable shops. Hit me up if you need ideas on different ways to utilize this system!
So I have gone through various different plugins that use the functionality below, but I wanted something that provided me a bit more freedom and the ability to easily integrate shops into my other scripts!
Below is the script as well as an example shop script. It is very cut and paste friendly. I have also included a video on how to actually use the script in game to make shop menus!
Feel free to send me any suggestions or ideas on how to improve this system!
Video (Please note it does not contain instructions for a Sell Items shop, see P.S.)
https://www.youtube.com/watch?v=CswUR9UZvcs&t=197s
Current Version: 1.1 (It has been overhauled before posting, see P.S.)
Code:
##Core Script##
##Inventory for the shop creator menu##
ShopCreatorInv:
type: inventory
display name: Shop Editor
size: 54
slots:
- "[] [] [] [] [] [] [] [] []"
- "[] [] [] [] [] [] [] [] []"
- "[] [] [] [] [] [] [] [] []"
- "[] [] [] [] [] [] [] [] []"
- "[] [] [] [] [] [] [] [] [i@SaveShopIt]"
- "[i@ClearCostIt] [i@CostMinus1It] [i@CostMinus10It] [i@CostMinus100It] [i@CostMinus1000It] [i@CostPlus1It] [i@CostPlus10It] [i@CostPlus100It] [i@CostPlus1000It]"
Procedural Items:
- if <player.has_flag[EditShop]> && <player.has_flag[AdjustedCost].not>:
- determine <yaml[<player.flag[EditShop].get[1]>].read[<player.flag[EditShop].get[2]>]>
- queue clear
- if <player.has_flag[AdjustedCost]>:
- determine <player.flag[AdjustedCost]>
##World script to handle Shop Creator Inventory##
ShopCreatorHandler:
type: world
debug: true
events:
on player clicks in ShopCreatorInv:
##Prevent players from placing Shop Menu items in other slots of the menu##
- if <context.cursor_item.has_nbt[ShopMenuItem]>:
- determine passively cancelled
##Prevent players from placing Cost Adjustment items into their inventory##
- if <context.cursor_item.has_nbt[Cost]> && <context.raw_slot.is[==].to[-998]>:
- determine passively cancelled
- queue clear
- if <context.raw_slot> > 54:
- if <context.cursor_item.has_nbt[ShopMenuItem]>:
- determine passively cancelled
- narrate "You can't use that there!"
- queue clear
##Prevent a player from placing an adjusted item into their inventory##
- if <context.cursor_item.has_nbt[Cost]>:
- determine passively cancelled
- narrate "Click on ClearCost to reset an item!."
- queue clear
- else:
- queue clear
##Prevent replacing items with Shop Creator Items##
- if <context.cursor_item.has_nbt[ShopMenuItem].not> && <context.cursor_item.contains[i@air].not>:
- if <context.item.has_nbt[ShopMenuItem]>:
- determine passively cancelled
- queue clear
##Initial lore adjustment to add Cost: $0##
- if <context.cursor_item.has_nbt[Cost].not>:
- nbt <context.cursor_item> Cost:0 save:adjustedcost
- if <context.cursor_item.lore.size||0> == 0:
- if <player.has_flag[SellShop]>:
- adjust <entry[adjustedcost].new_item> "lore:Click Here to Sell! Offer: $<entry[adjustedcost].new_item.nbt[Cost]>" save:adjustedcost
- else:
- adjust <entry[adjustedcost].new_item> "lore:Click Here to Buy! Cost: $<entry[adjustedcost].new_item.nbt[Cost]>" save:adjustedcost
- else:
- adjust <entry[adjustedcost].new_item> "lore:<entry[adjustedcost].new_item.lore.include[Click Here to Buy! Cost: $<entry[adjustedcost].new_item.nbt[Cost]>]>" save:adjustedcost
- flag player AdjustedCost:<player.open_inventory.list_contents.set[<entry[adjustedcost].result>].at[<context.slot>]>
- adjust <player> item_on_cursor:i@air
- inventory open d:in@ShopCreatorInv
- flag player AdjustedCost:!
- queue clear
##Add Cost Item To Cursor##
- if <context.item.nbt[ShopMenuItem]||0> > 0 || <context.item.nbt[ShopMenuItem]||0> < 0:
- determine passively cancelled
- if <context.cursor_item.simple> == <context.item.simple>:
- if <player.item_on_cursor.quantity> == 64:
- queue clear
- else:
- adjust <context.cursor_item> quantity:<context.cursor_item.quantity.add[1]> save:AdjustCost
- adjust <player> item_on_cursor:<entry[AdjustCost].result>
- queue clear
- else:
- if <context.item.nbt[ShopMenuItem]> != Save && <context.item.nbt[ShopMenuItem]> != Clear:
- adjust <player> item_on_cursor:<context.item>
##Add/Subtract Cost##
- if <context.raw_slot> > 54 && <context.cursor_item.has_nbt[ShopMenuItem]>:
- determine passively cancelled
- adjust <player> item_on_cursor:i@air
- queue clear
- if <context.item.has_nbt[Cost]> && <context.cursor_item.has_nbt[ShopMenuItem]>:
- if <context.cursor_item.nbt[ShopMenuItem]> == Clear:
- queue clear
- if <context.item.nbt[Cost].add[<context.cursor_item.nbt[ShopMenuItem].mul[<context.cursor_item.quantity>]>]> < 0:
- determine passively cancelled
- narrate "You cannot have a cost go below 0!"
- queue clear
- adjust <context.item> nbt:Cost/<context.item.nbt[Cost].add[<context.cursor_item.nbt[ShopMenuItem].mul[<context.cursor_item.quantity>]>]> save:adjustedcost
- adjust <entry[adjustedcost].result> "lore:<entry[adjustedcost].result.lore.set[Click Here to Buy! Cost: $<entry[adjustedcost].result.nbt[Cost]>].at[<entry[adjustedcost].result.lore.size>]>" save:adjustedcost
- flag player AdjustedCost:<player.open_inventory.list_contents.set[<entry[adjustedcost].result>].at[<context.slot>]>
- define CursorStack <player.item_on_cursor>
- adjust <player> item_on_cursor:i@air
- inventory open d:in@ShopCreatorInv
- adjust <player> item_on_cursor:<def[CursorStack]>
- flag player AdjustedCost:!
##Clear Cost##
on player left clicks ClearCostIt in ShopCreatorInv:
- determine passively cancelled
- if <context.cursor_item.has_nbt[cost]>:
- adjust <context.cursor_item> "Lore:<context.cursor_item.lore.remove[<context.cursor_item.lore.size>]>" save:ClearCost
- nbt <entry[ClearCost].result> Cost:! save:ClearCost
- adjust <player> item_on_cursor:<entry[ClearCost].new_item>
- narrate "Cost removed from Item."
- flag AdjustedCost:<player.open_inventory.list_contents>
- queue clear
- adjust <player> item_on_cursor:i@air
on player right clicks ClearCostIt in ShopCreatorInv:
- determine passively cancelled
- adjust <player> item_on_cursor:i@ClearCostIt
on player clicks in ShopCreatorInv with ClearCostIt:
- if <context.raw_slot> > 54 {
- adjust <player> item_on_cursor:i@air
- determine cancelled
- queue clear
}
- if <context.item.has_nbt[ShopMenuItem]> || <context.item.contains[i@air]> {
- determine passively cancelled
- queue clear
}
- determine passively cancelled
- adjust <context.item> nbt:Cost/0 save:adjustedcost
- adjust <entry[adjustedcost].result> "lore:<entry[adjustedcost].result.lore.set[Click Here to Buy! Cost: $<entry[adjustedcost].result.nbt[Cost]>].at[<entry[adjustedcost].result.lore.size>]>" save:adjustedcost
- flag player AdjustedCost:<player.open_inventory.list_contents.set[<entry[adjustedcost].result>].at[<context.slot>]>
- define CursorStack <player.item_on_cursor>
- adjust <player> item_on_cursor:i@air
- inventory open d:in@ShopCreatorInv
- adjust <player> item_on_cursor:<def[CursorStack]>
- flag player AdjustedCost:!
##Save and Exit##
on player clicks SaveShopIt in ShopCreatorInv:
- determine passively cancelled
- narrate "Shop Inventory:<player.flag[ShopCreator].get[2]> has been saved to File:<player.flag[ShopCreator].get[1]>.yml!"
- if <player.has_flag[EditShop]>:
- yaml id:<player.flag[ShopCreator].get[1]> set <player.flag[ShopCreator].get[2]>:!
- foreach <player.open_inventory.list_contents.get[1].to[44]>:
- yaml id:<player.flag[ShopCreator].get[1]> set <player.flag[ShopCreator].get[2]>:->:<def[value]>
- yaml savefile:/Shops/<player.flag[ShopCreator].get[1]>.yml id:<player.flag[ShopCreator].get[1]>
- yaml unload id:<player.flag[ShopCreator].get[1]>
- flag player SellShop:!
- flag player AdjustedCost:!
- flag player EditShop:!
- flag player ShopCreator:!
- inventory close
ShopCreatorCmd:
type: command
name: createshop
usage: /createshop
description: "Use to create a list for a Denizen shop script. /createshop File:<&lc>FileName<&rc> Shop:<&lc>ShopName<&rc> | add Delete to delete a shop | add Edit to edit an existing shop."
permission: denizen.shopcreator
script:
- if <player.has_flag[EditShop]> || <player.has_flag[ShopCreator]>:
- flag player EditShop:!
- flag player ShopCreator:!
- flag player SellShop:!
##Delete Shop##
- if <context.args.contains[Delete]>:
- if <server.has_file[/Shops/<context.args.map_get[File].split_by[<&co>]>.yml].not>:
- narrate "The File: <context.args.map_get[File].split_by[<&co>]>.yml does not exist! Did you type it in correctly?"
- queue clear
- yaml load:/Shops/<context.args.map_get[File].split_by[<&co>]>.yml id:<context.args.map_get[File].split_by[<&co>]>
- if <yaml[<context.args.map_get[File].split_by[<&co>]>].contains[<context.args.map_get[Shop].split_by[<&co>]>].not>:
- narrate "The Shop: <context.args.map_get[Shop].split_by[<&co>]> does not exist in File: <context.args.map_get[File].split_by[<&co>]>! Did you type it in correctly?"
- queue clear
- yaml id:<context.args.map_get[File].split_by[<&co>]> set <context.args.map_get[Shop].split_by[<&co>]>:!
- yaml savefile:/Shops/<context.args.map_get[File].split_by[<&co>]>.yml id:<context.args.map_get[File].split_by[<&co>]>
- narrate "The Shop: <context.args.map_get[Shop].split_by[<&co>]> in File: <context.args.map_get[File].split_by[<&co>]> has been deleted!"
- queue clear
##Edit Shop##
- if <context.args.contains[Edit]>:
- if <player.has_flag[AdjustedCost]>:
- flag player AdjustedCost:!
- if <server.has_file[/Shops/<context.args.map_get[File].split_by[<&co>]>.yml].not>:
- narrate "The File: <context.args.map_get[File].split_by[<&co>]>.yml does not exist! Did you type it in correctly?"
- queue clear
- yaml load:/Shops/<context.args.map_get[File].split_by[<&co>]>.yml id:<context.args.map_get[File].split_by[<&co>]>
- if <yaml[<context.args.map_get[File].split_by[<&co>]>].contains[<context.args.map_get[Shop].split_by[<&co>]>].not>:
- narrate "The Shop: <context.args.map_get[Shop].split_by[<&co>]> does not exist in File: <context.args.map_get[File].split_by[<&co>]>! Did you type it in correctly?"
- queue clear
- flag player EditShop:|:<context.args.map_get[File].split_by[<&co>]>|<context.args.map_get[Shop].split_by[<&co>]>
- flag player ShopCreator:|:<context.args.map_get[File].split_by[<&co>]>|<context.args.map_get[Shop].split_by[<&co>]>
- inventory open d:in@ShopCreatorInv
- queue clear
##Create Shop##
- if <server.has_file[/Shops/<context.args.map_get[File].split_by[<&co>]>.yml].not>:
- yaml create id:<context.args.map_get[File].split_by[<&co>]>
- yaml savefile:/Shops/<context.args.map_get[File].split_by[<&co>]>.yml id:<context.args.map_get[File].split_by[<&co>]>
- yaml load:/Shops/<context.args.map_get[File].split_by[<&co>]>.yml id:<context.args.map_get[File].split_by[<&co>]>
- else:
- yaml load:/Shops/<context.args.map_get[File].split_by[<&co>]>.yml id:<context.args.map_get[File].split_by[<&co>]>
- if <yaml[<context.args.map_get[File].split_by[<&co>]>].contains[<context.args.map_get[Shop].split_by[<&co>]>]>:
- yaml unload id:<context.args.map_get[File].split_by[<&co>]>
- narrate "That shop already exists! If you wish to Edit or Delete a Shop, add those arguments when using the /createshop command."
- queue clear
- flag player ShopCreator:|:<context.args.map_get[File].split_by[<&co>]>|<context.args.map_get[Shop].split_by[<&co>]>
- inventory open d:in@ShopCreatorInv
- if <context.args.contains[SellShop]>:
- flag player SellShop
##Shop Creator Items##
SaveShopIt:
type: item
display name: Save Shop
material: i@writable_book[nbt=ShopMenuItem/Save]
lore:
- "Click here to save this shop inventory."
ClearCostIt:
type: item
display name: Clear Cursor
material: i@barrier[nbt=ShopMenuItem/Clear]
lore:
- "Clicking here with a Cost Editting item"
- "will clear it from your cursor."
- "Right click to pick up this item."
- "Click an item to adjust its cost to $0."
- "With a cost adjusted item on your cursor"
- "click here to reset the item entirely."
CostPlus1It:
type: item
display name: Add $1
material: i@stone[nbt=ShopMenuItem/1]
lore:
- "Click here to add $1 to the price"
- "of an item. With this item in hand"
- "click on an item. It will add $1"
- "for each item in the held stack."
CostPlus10It:
type: item
display name: Add $10
material: i@iron_block[nbt=ShopMenuItem/10]
lore:
- "Click here to add $10 to the price"
- "of an item. With this item in hand"
- "click on an item. It will add $10"
- "for each item in the held stack."
CostPlus100It:
type: item
display name: Add $100
material: i@gold_block[nbt=ShopMenuItem/100]
lore:
- "Click here to add $100 to the price"
- "of an item. With this item in hand"
- "click on an item. It will add $100"
- "for each item in the held stack."
CostPlus1000It:
type: item
display name: Add $1000
material: i@diamond_block[nbt=ShopMenuItem/1000]
lore:
- "Click here to add $1000 to the price"
- "of an item. With this item in hand"
- "click on an item. It will add $1000"
- "for each item in the held stack."
CostMinus1It:
type: item
display name: Subtract $1
material: i@coal_ore[nbt=ShopMenuItem/-1]
lore:
- "Click here to subtract $1 to the price"
- "of an item. With this item in hand"
- "click on an item. It will subtract $1"
- "for each item in the held stack."
CostMinus10It:
type: item
display name: Subtract $10
material: i@iron_ore[nbt=ShopMenuItem/-10]
lore:
- "Click here to subtract $10 to the price"
- "of an item. With this item in hand"
- "click on an item. It will subtract $10"
- "for each item in the held stack."
CostMinus100It:
type: item
display name: Subtract $100
material: i@gold_ore[nbt=ShopMenuItem/-100]
lore:
- "Click here to subtract $100 to the price"
- "of an item. With this item in hand"
- "click on an item. It will subtract $100"
- "for each item in the held stack."
CostMinus1000It:
type: item
display name: Subtract $1000
material: i@diamond_ore[nbt=ShopMenuItem/-1000]
lore:
- "Click here to subtract $1000 to the price"
- "of an item. With this item in hand"
- "click on an item. It will subtract $1000"
- "for each item in the held stack."
##Player Shop Creation System##
PlayerShopHandler:
type: world
events:
on player places PlayerShopIt:
- flag player ShopOwner:<context.location>
- flag player ShopCreator:|:PlayerShops|<player.uuid>|<context.location>
- inventory open d:in@ShopCreatorInv
on player closes ShopCreatorInv:
- foreach <player.inventory.list_contents>:
- if <def[value].contains[i@ClearCostIt]> || <def[value].contains[i@CostMinus1000It]> || <def[value].contains[i@CostMinus100It]> || <def[value].contains[i@CostMinus10It]> || <def[value].contains[i@CostMinus1It]> || <def[value].contains[i@CostPlus1000It]> || <def[value].contains[i@CostPlus100It]> || <def[value].contains[i@CostPlus10It]> || <def[value].contains[i@CostPlus1It]>:
- take <def[value]> quantity:<def[value].quantity>
##Player Shop Creation Item##
PlayerShopIt:
type: item
material: sign
display name: Shop Post
lore:
- "Congratulations! You're the proud owner"
- "of a Personal Shop Post. Simply place"
- "this sign anywhere you're allowed to"
- "setup your own Personal Shop! Others will"
- "be able to purchase items you place there!"
- "Should you need to restock, simply right"
- "click this sign!"
##Example Shop##
GenericShopInv:
type: inventory
display name: Shop Name Here
size: 45
slots:
- "[] [] [] [] [] [] [] [] []"
- "[] [] [] [] [] [] [] [] []"
- "[] [] [] [] [] [] [] [] []"
- "[] [] [] [] [] [] [] [] []"
- "[] [] [] [] [] [] [] [] []"
Procedural Items:
- determine <yaml[FileName].read[ShopName]>
NPCAssignment:
type: assignment
actions:
on assignment:
- trigger name:click state:true
on click:
- narrate "Greeting Here"
- yaml load:/Shops/FileName.yml id:ShopName
- wait 2
- inventory open d:in@GenericShopInv
- yaml unload id:ShopName
ShopMenuHandler:
type: world
events:
on player drags in GenericShopInv:
- determine cancelled
on player clicks in GenericShopInv:
- determine passively cancelled
- if <context.item.has_nbt[Cost]>:
- if <player.money.is[MORE].to[<context.item.nbt[Cost]>]>:
- if <player.inventory.is_full>:
- narrate "Your inventory is full!"
- queue clear
- take money quantity:<context.item.nbt[Cost]>
- adjust <context.item> "Lore:<context.item.lore.remove[<context.item.lore.size>]>" save:Item
- nbt <entry[Item].result> Cost:! save:Item
- give <entry[Item].new_item>
- narrate "$<context.item.nbt[Cost]> has been removed from your wallet."
- flag player TotalSpent:+:<context.item.nbt[Cost]>
- queue clear
- else:
- narrate "You don't have enough money! Cost: $<context.item.nbt[Cost]> Your Money: $<player.money>"
- queue clear
P.S.
The ability to make a shop where players can sell items has been added but was not part of the original video!
When using the /createshop command add the argument SellShop at the end of the command and the system will create a shop for selling items too! Everything works exactly the same way accept when you make the script for the Sell Items menu make sure that it is checking if the player has the items in question and change the take money commands accordingly.
With the right knowledge this script allows for VERY customizable shops. Hit me up if you need ideas on different ways to utilize this system!