Add messages.yml and functionality to purchase GUI

The plugin now has a functioning messages.yml that has the options to
set messages (improving customisability), as well as the shop now has a
working buy menu where u can see the price changes and what not.
Supports prices and rounding to 2 decimal places.
master
ALI Hamza 2020-03-11 18:11:27 +07:00
parent 34008d5d6b
commit 1e4f3dab01
No known key found for this signature in database
GPG Key ID: BCA8A46C87798C4C
6 changed files with 252 additions and 28 deletions

@ -1,24 +1,52 @@
package pw.hamzantal.shopreborn
import hazae41.minecraft.kutils.bukkit.msg
import org.bukkit.Bukkit
import org.bukkit.Material
import org.bukkit.entity.Player
import org.bukkit.event.inventory.ClickType.*
import org.bukkit.event.inventory.InventoryClickEvent
import org.bukkit.event.inventory.InventoryCloseEvent
import org.bukkit.inventory.Inventory
import org.bukkit.inventory.ItemStack
import kotlin.math.max
import kotlin.math.min
enum class PurchaseType { BUY, SELL }
class PurchaseEvent(
val inv: Inventory,
val item: ItemStack,
val shop: ShopConfig,
val p: Player,
val block: ShopConfig.Item,
val type: PurchaseType
)
val purchases = mutableListOf<PurchaseEvent>()
fun closeListener(e: InventoryCloseEvent) {
val purchase = purchases.firstOrNull { it.inv == e.inventory } ?: return
purchases -= purchase
}
fun baseListener(e: InventoryClickEvent) {
if (e.inventory == Configurations.main.inventory) {
if (e.inventory == GlobalConfig.main.inventory) {
mainClick(e)
return
}
val shop = Configurations.shops.firstOrNull { it.inventories.contains(e.inventory)} ?: return
shopClick(e, shop)
val purchase = purchases.firstOrNull { it.inv == e.inventory }
if (purchase != null) clickInventory(e, purchase)
val shop = GlobalConfig.shops.firstOrNull { it.inventories.contains(e.inventory) } ?: return
shopClick(e, shop)
}
fun mainClick(e: InventoryClickEvent) {
e.isCancelled = true
if (e.rawSlot > e.inventory.size) return
val main = Configurations.main
val main = GlobalConfig.main
val p = e.whoClicked as Player
val block = main.blocks.firstOrNull { it.slot == e.slot } ?: return
@ -31,7 +59,7 @@ fun shopClick(e: InventoryClickEvent, shop: ShopConfig) {
e.isCancelled = true
if (e.rawSlot > e.inventory.size) return
val main = Configurations.main
val main = GlobalConfig.main
val p = e.whoClicked as Player
//Check Menu Buttons
@ -47,7 +75,7 @@ fun shopClick(e: InventoryClickEvent, shop: ShopConfig) {
return
}
if(e.currentItem == main.buttons.previous) {
if (e.currentItem == main.buttons.previous) {
val current = shop.inventories.indexOf(e.inventory)
if (current == 0) return
p.openInventory(shop.inventories[current - 1])
@ -55,13 +83,91 @@ fun shopClick(e: InventoryClickEvent, shop: ShopConfig) {
//Buy / Sell Item
val block = shop.blocks.firstOrNull { it.item == e.currentItem } ?: return
if (block is ShopConfig.Command) {
TODO()
}
when(block) {
is ShopConfig.Item -> {
p.msg("Buying ${block.item.type.name} for ${block.buy}")
when (e.click) {
LEFT -> buy(e, p, shop, block as ShopConfig.Item)
RIGHT -> TODO()
MIDDLE -> TODO()
else -> return
}
}
fun clickInventory(e: InventoryClickEvent, pe: PurchaseEvent) {
e.isCancelled = true
val block = pe.block
val origin = block.item
val singleCost =
if (pe.type == PurchaseType.BUY) pe.block.buy / origin.amount
else pe.block.sell / origin.amount
val lore =
if (pe.type == PurchaseType.BUY) GlobalConfig.messages.buyLore
else GlobalConfig.messages.sellLore
when (e.currentItem) {
PurchaseItems.set1 -> {
pe.item.amount = 1
pe.item.setLore(lore.mixPlaceholder(price = singleCost))
}
PurchaseItems.sub10 -> {
val now = max(1, pe.item.amount - 10)
pe.item.amount = now
pe.item.setLore(lore.mixPlaceholder(price = singleCost * now))
}
is ShopConfig.Command -> {
p.msg("Buying ${block.item.type.name} producing ${block.commands.joinToString(",")}")
PurchaseItems.sub1 -> {
val now = max(1, pe.item.amount - 1)
pe.item.amount = now
pe.item.setLore(lore.mixPlaceholder(price = singleCost * now))
}
PurchaseItems.add1 -> {
val now = min(64, pe.item.amount + 1)
pe.item.amount = now
pe.item.setLore(lore.mixPlaceholder(price = singleCost * now))
}
PurchaseItems.add10 -> {
val now = min(64, pe.item.amount + 10)
pe.item.amount = now
pe.item.setLore(lore.mixPlaceholder(price = singleCost * now))
}
PurchaseItems.set64 -> {
pe.item.amount = 64
pe.item.setLore(lore.mixPlaceholder(price = singleCost * 64))
}
}
pe.inv.setItem(22, pe.item)
}
val base = Array<ItemStack?>(54) { null }.apply {
set(18, PurchaseItems.set1)
set(19, PurchaseItems.sub10)
set(20, PurchaseItems.sub1)
set(24, PurchaseItems.add1)
set(25, PurchaseItems.add10)
set(26, PurchaseItems.set64)
}
fun Material.prettyName() = name.split("_").joinToString(" ") { it.toLowerCase().capitalize() }
fun buy(e: InventoryClickEvent, p: Player, shop: ShopConfig, block: ShopConfig.Item) {
val item = e.currentItem.clone()
if (block.buy == -1.0) return
val name = if (item.itemMeta.hasDisplayName()) item.itemMeta.displayName else item.type.prettyName()
val inv = Bukkit.createInventory(null, 54, "&2Buying $name".c).apply {
contents = base.clone()
val buyLore = GlobalConfig.messages.buyLore.mixPlaceholder(price = block.buy)
setItem(22, e.currentItem.setLore(buyLore))
setItem(39, PurchaseItems.buyConfirm)
setItem(41, PurchaseItems.cancel)
}
p.openInventory(inv)
purchases.add(PurchaseEvent(inv, item, shop, p, block, PurchaseType.BUY))
}

@ -12,9 +12,10 @@ import java.io.File
import kotlin.math.ceil
import kotlin.math.max
object Configurations {
object GlobalConfig {
var dataFolder = File("")
lateinit var main: MainConfig
lateinit var messages: Messages
val shops = mutableListOf<ShopConfig>()
}
@ -59,10 +60,10 @@ class MainConfig(file: File) : ConfigFile(file) {
}
fun addShops() {
Configurations.shops.addAll(shops!!.keys.map {
GlobalConfig.shops.addAll(shops!!.keys.map {
ShopConfig(
it,
Configurations.dataFolder[shops!!.getString(it)]
GlobalConfig.dataFolder[shops!!.getString(it)]
)
})
}
@ -70,7 +71,7 @@ class MainConfig(file: File) : ConfigFile(file) {
class ShopConfig(val name: String, file: File) : ConfigFile(file) {
open class Block(val item: ItemStack)
class Item(item: ItemStack, val buy: Int, val sell: Int) : Block(item)
class Item(item: ItemStack, val buy: Double, val sell: Double) : Block(item)
class Command(item: ItemStack, val asPlayer: Boolean, val commands: List<String>) : Block(item)
init {
@ -104,8 +105,8 @@ class ShopConfig(val name: String, file: File) : ConfigFile(file) {
?.map<ConfigurationSection, Block> {
val type = it.getString("type")
val buy = it.getInt("buyPrice", -1)
val sell = it.getInt("sellPrice", -1)
val buy = it.getDouble("buyPrice", -1.0)
val sell = it.getDouble("sellPrice", -.01)
val item = it.getConfigurationSection("item").asItem(buy, sell)
when (type) {
@ -128,6 +129,7 @@ class ShopConfig(val name: String, file: File) : ConfigFile(file) {
val inventories = mutableListOf<Inventory>()
val inventory: Inventory
init {
inventory = makeInventory(size, title, menuRow, blocks, 1)
inventories += inventory
@ -140,7 +142,7 @@ class ShopConfig(val name: String, file: File) : ConfigFile(file) {
fun makeInventory(size: Int, title: String, menuRow: Int = -1, items: List<ShopConfig.Block>, page: Int): Inventory {
return Bukkit.createInventory(null, size, title.c).apply {
if (menuRow > 0) {
val buttons = Configurations.main.buttons
val buttons = GlobalConfig.main.buttons
for (i in menuRow until menuRow + 9) {
setItem(i, buttons.pane)
}
@ -157,15 +159,17 @@ fun makeInventory(size: Int, title: String, menuRow: Int = -1, items: List<ShopC
}
}
fun ConfigurationSection.asItem(buy: Int = -1, sell: Int = -1): ItemStack {
fun ConfigurationSection.asItem(buy: Double = -1.0, sell: Double = -1.0): ItemStack {
val material = Material.valueOf(getString("material").toUpperCase())
val item = ItemStack(material, getInt("quantity", 1), getInt("damage", 0).toShort())
item.itemMeta = item.itemMeta.apply {
displayName = getString("name", "").c
val configLore = getStringList("lore").map { it.c }.toMutableList()
if (buy > 0) configLore += "&fPurchase for $$buy".c
if (sell > 0) configLore += "&fSell for $$sell".c
val messages = GlobalConfig.messages
if (buy > 0) configLore += messages.buyLore.mixPlaceholder(price = buy)
if (sell > 0) configLore += messages.sellLore.mixPlaceholder(price = sell)
lore = configLore
}

@ -0,0 +1,44 @@
package pw.hamzantal.shopreborn
import hazae41.minecraft.kutils.bukkit.ConfigFile
import java.io.File
class Messages(file: File, pl: ShopReborn) : ConfigFile(file) {
val currency by string("currency", "$")
val buyLore by string("buyLore")
val sellLore by string("stringLore")
val itemLore by string("itemLore")
val set1 by string("set1")
val sub10 by string("sub10")
val sub1 by string("sub1")
val add1 by string("add1")
val add10 by string("add10")
val set64 by string("set64")
val sellConfirm by string("sell.confirm")
val sellAll by string("sell.sellAll")
val sellAllLore by string("sell.sellAllLore")
val buyConfirm by string("buy.confirm")
val cancel by string("cancel")
init {
if (!file.exists()) {
val messages = pl.getResource("messages.yml").bufferedReader().readLines().joinToString("\n")
file.createNewFile()
file.writeText(messages)
}
}
}
fun String.mixPlaceholder(amount: Int = 0, price: Double = 0.0): String =
replace("%AMOUNT%", amount.toString())
.replace(
"%PRICE%",
String.format("%s%.2f", GlobalConfig.messages.currency, price)
)
.c

@ -0,0 +1,47 @@
package pw.hamzantal.shopreborn
import org.bukkit.Material
import org.bukkit.inventory.ItemStack
object PurchaseItems {
fun paneStack(damage: Int, name: String): ItemStack {
return ItemStack(Material.STAINED_GLASS_PANE, 1, damage.toShort()).apply {
itemMeta = itemMeta.apply {
displayName = name.c
}
}
}
fun blockStack(damage: Int, name: String): ItemStack {
return ItemStack(Material.STAINED_GLASS, 1, damage.toShort()).apply {
itemMeta = itemMeta.apply {
displayName = name.c
}
}
}
val msgs = GlobalConfig.messages
val set1 = paneStack(14, msgs.set1)
val sub10 = paneStack(14, msgs.sub10)
val sub1 = paneStack(14, msgs.sub1)
val add1 = paneStack(5, msgs.add1)
val add10 = paneStack(5, msgs.add10)
val set64 = paneStack(5, msgs.set64)
val sellConfirm = blockStack(5, msgs.sellConfirm)
val sellAll = blockStack(5, msgs.sellAll)
val buyConfirm = blockStack(5, msgs.buyConfirm)
val cancel = blockStack(14, msgs.cancel)
}
fun ItemStack.setLore(s: String): ItemStack {
return apply {
itemMeta = itemMeta.apply {
lore = listOf(s.c)
}
}
}

@ -1,7 +1,6 @@
package pw.hamzantal.shopreborn
import hazae41.minecraft.kutils.bukkit.command
import hazae41.minecraft.kutils.bukkit.info
import hazae41.minecraft.kutils.bukkit.listen
import hazae41.minecraft.kutils.get
import org.bukkit.entity.Player
@ -12,21 +11,23 @@ class ShopReborn : JavaPlugin() {
override fun onEnable() {
saveDefaultConfig()
Configurations.dataFolder = dataFolder
Configurations.main =
GlobalConfig.dataFolder = dataFolder
GlobalConfig.messages = Messages(dataFolder["messages.yml"], this)
GlobalConfig.main =
MainConfig(dataFolder["config.yml"])
Configurations.main.addShops()
GlobalConfig.main.addShops()
listen(callback = ::baseListener)
listen(callback = ::closeListener)
command("shop") { sender, args ->
if (sender !is Player) return@command
if (args.isEmpty()) {
sender.openInventory(Configurations.main.inventory)
sender.openInventory(GlobalConfig.main.inventory)
return@command
}
val shop = Configurations.shops.firstOrNull { it.name == args.component1() } ?: return@command
val shop = GlobalConfig.shops.firstOrNull { it.name == args.component1() } ?: return@command
sender.openInventory(shop.inventory)
}
}

@ -0,0 +1,22 @@
currency: "$"
buyLore: "&6Buy price: &c%PRICE%"
sellLore: "&6Sell price: &c%PRICE%"
itemLore: "&6Left click to buy, Right click to sell"
set1: "&c&lSet to 1"
sub10: "&c&lRemove 10"
sub1: "&c&lRemove 1"
add1: "&a&lAdd 1"
add10: "&a&lAdd 10"
set64: "&a&lSet 64"
# Confirm for selling/buying (after selecting the item)
sell:
confirm: "&a&lConfirm"
sellAll: "&a&lSell all"
sellAllLore: "&7Sell all for &a%PRICE%"
buy:
confirm: "&a&lConfirm"
cancel: "&c&lCancel"