diff --git a/common/src/main/kotlin/com/artillexstudios/axminions/AxMinionsPlugin.kt b/common/src/main/kotlin/com/artillexstudios/axminions/AxMinionsPlugin.kt index b355577..2b68044 100644 --- a/common/src/main/kotlin/com/artillexstudios/axminions/AxMinionsPlugin.kt +++ b/common/src/main/kotlin/com/artillexstudios/axminions/AxMinionsPlugin.kt @@ -36,6 +36,7 @@ import com.artillexstudios.axminions.minions.miniontype.SlayerMinionType import java.io.File import com.artillexstudios.axapi.libs.libby.BukkitLibraryManager import com.artillexstudios.axapi.libs.libby.Library +import com.artillexstudios.axminions.minions.miniontype.CrafterMinionType import org.bstats.bukkit.Metrics import org.bukkit.Bukkit import revxrsal.commands.bukkit.BukkitCommandHandler @@ -83,6 +84,7 @@ class AxMinionsPlugin : AxPlugin() { MinionTypes.also { it.register(CollectorMinionType()) + it.register(CrafterMinionType()) it.register(FarmerMinionType()) it.register(MinerMinionType()) it.register(LumberMinionType()) diff --git a/common/src/main/kotlin/com/artillexstudios/axminions/listeners/MinionInventoryListener.kt b/common/src/main/kotlin/com/artillexstudios/axminions/listeners/MinionInventoryListener.kt index 59d4852..cca3191 100644 --- a/common/src/main/kotlin/com/artillexstudios/axminions/listeners/MinionInventoryListener.kt +++ b/common/src/main/kotlin/com/artillexstudios/axminions/listeners/MinionInventoryListener.kt @@ -49,8 +49,15 @@ class MinionInventoryListener : Listener { coolDown.add(player, 250) val allowedTools = arrayListOf() - minion.getType().getConfig().getStringList("tool.material").fastFor { - allowedTools.add(Material.matchMaterial(it) ?: return@fastFor) + run breaking@{ + minion.getType().getConfig().getStringList("tool.material").fastFor { + if (it.equals("*")) { + allowedTools.addAll(Material.entries) + return@breaking + } + + allowedTools.add(Material.matchMaterial(it) ?: return@fastFor) + } } if (event.clickedInventory == player.inventory && event.currentItem != null) { @@ -147,7 +154,12 @@ class MinionInventoryListener : Listener { } if (Config.UPGRADE_SOUND().isNotBlank()) { - player.playSound(player, Sound.valueOf(Config.UPGRADE_SOUND().uppercase(Locale.ENGLISH)), 1.0f, 1.0f) + player.playSound( + player, + Sound.valueOf(Config.UPGRADE_SOUND().uppercase(Locale.ENGLISH)), + 1.0f, + 1.0f + ) } minion.setLevel(minion.getLevel() + 1) diff --git a/common/src/main/kotlin/com/artillexstudios/axminions/listeners/SuperiorSkyBlock2Listener.kt b/common/src/main/kotlin/com/artillexstudios/axminions/listeners/SuperiorSkyBlock2Listener.kt index 9eda25a..66b5cc5 100644 --- a/common/src/main/kotlin/com/artillexstudios/axminions/listeners/SuperiorSkyBlock2Listener.kt +++ b/common/src/main/kotlin/com/artillexstudios/axminions/listeners/SuperiorSkyBlock2Listener.kt @@ -5,7 +5,6 @@ import com.bgsoftware.superiorskyblock.api.events.IslandDisbandEvent import org.bukkit.World.Environment import org.bukkit.event.EventHandler import org.bukkit.event.Listener -import org.bukkit.World class SuperiorSkyBlock2Listener : Listener { diff --git a/common/src/main/kotlin/com/artillexstudios/axminions/minions/miniontype/CrafterMinionType.kt b/common/src/main/kotlin/com/artillexstudios/axminions/minions/miniontype/CrafterMinionType.kt new file mode 100644 index 0000000..63f3115 --- /dev/null +++ b/common/src/main/kotlin/com/artillexstudios/axminions/minions/miniontype/CrafterMinionType.kt @@ -0,0 +1,259 @@ +package com.artillexstudios.axminions.minions.miniontype + +import com.artillexstudios.axminions.AxMinionsPlugin +import com.artillexstudios.axminions.api.minions.Minion +import com.artillexstudios.axminions.api.minions.miniontype.MinionType +import com.artillexstudios.axminions.api.warnings.Warnings +import com.artillexstudios.axminions.minions.MinionTicker +import org.bukkit.Bukkit +import org.bukkit.Material +import org.bukkit.inventory.Inventory +import org.bukkit.inventory.ItemStack +import org.bukkit.inventory.ShapedRecipe +import org.bukkit.inventory.ShapelessRecipe + +class CrafterMinionType : MinionType("collector", AxMinionsPlugin.INSTANCE.getResource("minions/crafter.yml")!!) { + + override fun shouldRun(minion: Minion): Boolean { + return MinionTicker.getTick() % minion.getNextAction() == 0L + } + + override fun onToolDirty(minion: Minion) { + val minionImpl = minion as com.artillexstudios.axminions.minions.Minion + minionImpl.setRange(1.0) + minionImpl.setNextAction(getLong("speed", minion.getLevel()).toInt()) + } + + override fun run(minion: Minion) { + if (minion.getLinkedChest() == null) { + Warnings.NO_CONTAINER.display(minion) + return + } + + val type = minion.getLinkedChest()!!.block.type + if (type != Material.CHEST && type != Material.TRAPPED_CHEST && type != Material.BARREL) { + Warnings.NO_CONTAINER.display(minion) + minion.setLinkedChest(null) + return + } + + if (minion.getLinkedInventory() == null) { + Warnings.NO_CONTAINER.display(minion) + minion.setLinkedChest(null) + return + } + + Warnings.remove(minion, Warnings.NO_CONTAINER) + + if (!minion.canUseTool()) { + Warnings.NO_TOOL.display(minion) + return + } + + Warnings.remove(minion, Warnings.NO_TOOL) + + val tool = minion.getTool() + + val recipes = Bukkit.getRecipesFor(tool ?: return) + + val shaped = arrayListOf() + val shapeless = arrayListOf() + + for (recipe in recipes) { + if (recipe is ShapedRecipe) { + shaped.add(recipe) + } else if (recipe is ShapelessRecipe) { + shapeless.add(recipe) + } + } + + val inv = minion.getLinkedInventory() ?: return + val items = inv.contents + + val contents = HashMap() + + a@ for (item in items) { + if (item == null || item.type.isAir) continue + + if (contents.isEmpty()) { + contents[item] = item.amount + continue + } + + val iterator: Iterator> = contents.entries.iterator() + while (iterator.hasNext()) { + val next = iterator.next() + + if (item.isSimilar(next.key)) { + next.setValue(next.value + item.amount) + continue@a + } + } + + contents[item] = item.amount + } + + // SHAPELESS + var recipeIterator = shapeless.iterator() + while (recipeIterator.hasNext()) { + val recipe = recipeIterator.next() + + if (!canCraftShapeless(recipe, contents)) { + recipeIterator.remove() + continue + } + + doCraftShapeless(inv, recipe, contents) + + recipeIterator = shapeless.iterator() + } + + + // SHAPED + var shapedIterator = shaped.iterator() + while (shapedIterator.hasNext()) { + val recipe = shapedIterator.next() + + if (!canCraftShaped(recipe, contents)) { + shapedIterator.remove() + continue + } + + doCraftShaped(inv, recipe, contents) + + shapedIterator = shaped.iterator() + } + } + + private fun canCraftShapeless(recipe: ShapelessRecipe, contents: HashMap): Boolean { + val clone = contents.clone() as HashMap + for (recipeChoice in recipe.choiceList) { + var hasEnough = false + + val iterator = clone.entries.iterator() + while (iterator.hasNext()) { + val next = iterator.next() + + if (next.key.isSimilar(recipeChoice.itemStack) && next.value >= recipeChoice.itemStack.amount) { + hasEnough = true + val amount = next.value - recipeChoice.itemStack.amount + if (amount == 0) { + iterator.remove() + } else { + next.setValue(amount) + } + break + } + } + + if (!hasEnough) { + return false + } + } + + return true + } + + private fun canCraftShaped(recipe: ShapedRecipe, contents: HashMap): Boolean { + val clone = contents.clone() as HashMap + for (recipeChoice in recipe.choiceMap.values) { + var hasEnough = false + + val iterator = clone.entries.iterator() + while (iterator.hasNext()) { + val next = iterator.next() + + if (next.key.isSimilar(recipeChoice.itemStack) && next.value >= recipeChoice.itemStack.amount) { + hasEnough = true + val amount = next.value - recipeChoice.itemStack.amount + if (amount == 0) { + iterator.remove() + } else { + next.setValue(amount) + } + break + } + } + + if (!hasEnough) { + return false + } + } + + return true + } + + private fun doCraftShapeless(inventory: Inventory, recipe: ShapelessRecipe, contents: HashMap) { + for (recipeChoice in recipe.choiceList) { + val item = recipeChoice.itemStack.clone() + + inventory.removeItem(item) + + val iterator = contents.entries.iterator() + while (iterator.hasNext()) { + val next = iterator.next() + + if (item.isSimilar(next.key)) { + val amount = next.value - item.amount + if (amount == 0) { + iterator.remove() + } else { + next.setValue(amount) + } + break + } + } + } + + val result = recipe.result.clone() + inventory.addItem(result) + val iterator: Iterator> = contents.entries.iterator() + while (iterator.hasNext()) { + val next = iterator.next() + + if (result.isSimilar(next.key)) { + next.setValue(next.value + result.amount) + return + } + } + + contents[result] = result.amount + } + + private fun doCraftShaped(inventory: Inventory, recipe: ShapedRecipe, contents: HashMap) { + for (recipeChoice in recipe.choiceMap.values) { + val item = recipeChoice.itemStack.clone() + + inventory.removeItem(item) + + val iterator = contents.entries.iterator() + while (iterator.hasNext()) { + val next = iterator.next() + + if (item.isSimilar(next.key)) { + val amount = next.value - item.amount + if (amount == 0) { + iterator.remove() + } else { + next.setValue(amount) + } + break + } + } + } + + val result = recipe.result.clone() + inventory.addItem(result) + val iterator: Iterator> = contents.entries.iterator() + while (iterator.hasNext()) { + val next = iterator.next() + + if (result.isSimilar(next.key)) { + next.setValue(next.value + result.amount) + return + } + } + + contents[result] = result.amount + } +} \ No newline at end of file diff --git a/common/src/main/resources/minions/crafter.yml b/common/src/main/resources/minions/crafter.yml new file mode 100644 index 0000000..fc2d1b1 --- /dev/null +++ b/common/src/main/resources/minions/crafter.yml @@ -0,0 +1,118 @@ +name: "<#FFEE00>Crafter Minion" + +entity: + name: "[] <#FFEE00>Crafter Minion []" + +tool: + material: + - "*" +item: + type: "player_head" + texture: "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvN2UzZDM2MzVjZTQxMWFiZjFlNGYzNzNkMTYxZDA3YjhjNDdlMzU5YjZjNTZmNzRiNDEzY2I0OTRhYzc0NmUyZCJ9fX0=" + name: "<#FFEE00>Crafter Minion" + lore: + - "" + - " - Crafts in it's container." + - "" + - "<#FFEE00>Statistics" + - " <#FFEE00>❙ Level: <#FFEEAA>" + - " <#FFEE00>❙ Collected items: <#FFEEAA>" + - "" + - "<#FFEE00>(!) Place the minion and give it an item to craft!" + +gui: + upgrade: + type: "gold_ingot" + name: "<#00CCFF>Upgrade minion" + lore: + - "" + - " - Level: » " + - " - Range: » " + - " - Speed: » " + - "" + - "<#00CCFF>Requirements:" + - " - Money: <#33FF33>$" + - " - Collected items: <#33FF33>" + - "" + - "<#00CCFF>(!) Click here to upgrade your minion!" + statistics: + type: "paper" + name: "<#FFEE00>Statistics" + lore: + - "" + - " - Crafted items: <#FFEE00>" + - "" + +upgrades: + 1: + speed: 160 + items: + helmet: + type: "player_head" + texture: "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvN2UzZDM2MzVjZTQxMWFiZjFlNGYzNzNkMTYxZDA3YjhjNDdlMzU5YjZjNTZmNzRiNDEzY2I0OTRhYzc0NmUyZCJ9fX0=" + chestplate: + type: "leather_chestplate" + color: "255, 230, 0" + glow: false + leggings: + type: "leather_leggings" + color: "255, 230, 0" + glow: false + boots: + type: "leather_boots" + color: "255, 230, 0" + glow: false + 2: + requirements: + money: 1000 + actions: 100 + 3: + speed: 140 + requirements: + money: 3000 + actions: 300 + 4: + requirements: + money: 10000 + actions: 1000 + 5: + speed: 120 + requirements: + money: 20000 + actions: 3000 + 6: + requirements: + money: 50000 + actions: 6000 + 7: + speed: 100 + requirements: + money: 150000 + actions: 10000 + 8: + requirements: + money: 500000 + actions: 17500 + 9: + speed: 90 + requirements: + money: 1000000 + actions: 25000 + 10: + speed: 80 + requirements: + money: 5000000 + actions: 50000 + items: + chestplate: + type: LEATHER_CHESTPLATE + color: "255, 200, 0" + glow: true + leggings: + type: LEATHER_LEGGINGS + color: "255, 200, 0" + glow: true + boots: + type: LEATHER_BOOTS + color: "255, 200, 0" + glow: true \ No newline at end of file