diff --git a/Server/data/configs/item_configs.json b/Server/data/configs/item_configs.json index e16807e0a..c9c560d81 100644 --- a/Server/data/configs/item_configs.json +++ b/Server/data/configs/item_configs.json @@ -93923,7 +93923,7 @@ }, { "shop_price": "128", - "examine": "I can keep my grub in here.", + "examine": "I can keep my items in here, but I'll need a banker to get them out.", "durability": null, "name": "Plain satchel", "weight": "0.1", @@ -93932,7 +93932,7 @@ "equipment_slot": "5" }, { - "examine": "I can keep my grub in here.", + "examine": "I can keep my seeds and herbs in here.", "durability": null, "name": "Green satchel", "weight": "0.1", @@ -93942,7 +93942,7 @@ }, { "shop_price": "128", - "examine": "I can keep my grub in here.", + "examine": "I can keep my summoning charms in here.", "durability": null, "name": "Red satchel", "weight": "0.1", @@ -93960,7 +93960,7 @@ "equipment_slot": "5" }, { - "examine": "I can keep my grub in here.", + "examine": "I can keep my ores in here.", "durability": null, "name": "Gold satchel", "weight": "0.1", @@ -93969,7 +93969,7 @@ "equipment_slot": "5" }, { - "examine": "I can keep my grub in here.", + "examine": "I can keep my catalytic runes in here.", "durability": null, "name": "Rune satchel", "weight": "0.1", diff --git a/Server/src/main/content/global/handlers/item/EnchantJewelleryTabListener.kt b/Server/src/main/content/global/handlers/item/EnchantJewelleryTabListener.kt index 1a31d30b5..b37ed1b1e 100644 --- a/Server/src/main/content/global/handlers/item/EnchantJewelleryTabListener.kt +++ b/Server/src/main/content/global/handlers/item/EnchantJewelleryTabListener.kt @@ -10,12 +10,14 @@ import org.rs09.consts.Sounds class EnchantJewelleryTabListener : InteractionListener { private val LVL_1_ENCHANT = mapOf( + Items.BLUE_DRAGONHIDE_1751 to Items.PLAIN_SATCHEL_10877, Items.SAPPHIRE_RING_1637 to Items.RING_OF_RECOIL_2550, Items.SAPPHIRE_NECKLACE_1656 to Items.GAMES_NECKLACE8_3853, Items.SAPPHIRE_AMULET_1694 to Items.AMULET_OF_MAGIC_1727, Items.SAPPHIRE_BRACELET_11072 to Items.BRACELET_OF_CLAY_11074 ) private val LVL_2_ENCHANT = mapOf( + Items.GREEN_DRAGONHIDE_1753 to Items.GREEN_SATCHEL_10878, Items.EMERALD_RING_1639 to Items.RING_OF_DUELLING8_2552, Items.EMERALD_NECKLACE_1658 to Items.BINDING_NECKLACE_5521, Items.EMERALD_AMULET_1696 to Items.AMULET_OF_DEFENCE_1729, @@ -23,6 +25,7 @@ class EnchantJewelleryTabListener : InteractionListener { ) private val LVL_3_ENCHANT = mapOf( + Items.RED_DRAGONHIDE_1749 to Items.RED_SATCHEL_10879, Items.RUBY_RING_1641 to Items.RING_OF_FORGING_2568, Items.RUBY_NECKLACE_1660 to Items.DIGSITE_PENDANT_5_11194, Items.RUBY_AMULET_1698 to Items.AMULET_OF_STRENGTH_1725, @@ -30,6 +33,7 @@ class EnchantJewelleryTabListener : InteractionListener { ) private val LVL_4_ENCHANT = mapOf( + Items.DAGANNOTH_HIDE_6155 to Items.GOLD_SATCHEL_10881, Items.DIAMOND_RING_1643 to Items.RING_OF_LIFE_2570, Items.DIAMOND_NECKLACE_1662 to Items.PHOENIX_NECKLACE_11090, Items.DIAMOND_AMULET_1700 to Items.AMULET_OF_POWER_1731, @@ -37,6 +41,7 @@ class EnchantJewelleryTabListener : InteractionListener { ) private val LVL_5_ENCHANT = mapOf( + Items.SUQAH_HIDE_9080 to Items.RUNE_SATCHEL_10882, Items.DRAGONSTONE_RING_1645 to Items.RING_OF_WEALTH4_14646, Items.DRAGON_NECKLACE_1664 to Items.SKILLS_NECKLACE4_11105, Items.DRAGONSTONE_AMMY_1702 to Items.AMULET_OF_GLORY4_1712, @@ -44,6 +49,7 @@ class EnchantJewelleryTabListener : InteractionListener { ) private val LVL_6_ENCHANT = mapOf( + Items.BLACK_DRAGONHIDE_1747 to Items.BLACK_SATCHEL_10880, Items.ONYX_RING_6575 to Items.RING_OF_STONE_6583, Items.ONYX_NECKLACE_6577 to Items.BERSERKER_NECKLACE_11128, Items.ONYX_AMULET_6581 to Items.AMULET_OF_FURY_6585, diff --git a/Server/src/main/content/global/handlers/item/SnowscapeSatchelListener.kt b/Server/src/main/content/global/handlers/item/SnowscapeSatchelListener.kt new file mode 100755 index 000000000..5dde40e25 --- /dev/null +++ b/Server/src/main/content/global/handlers/item/SnowscapeSatchelListener.kt @@ -0,0 +1,179 @@ +package content.global.handlers.item + +import core.api.* +import core.game.container.Container +import content.global.skill.summoning.familiar.BurdenContainerListener +import core.game.node.Node +import core.game.node.entity.player.Player +//import core.game.node.entity.player.info.login.PlayerSaver +import core.game.node.item.Item +import core.game.interaction.InteractionListener +import core.game.interaction.IntType +import org.json.simple.JSONArray +import org.json.simple.JSONObject +import org.json.simple.parser.JSONParser +import org.rs09.consts.Items + +import core.game.component.Component +import core.game.component.CloseEvent +import core.game.container.access.InterfaceContainer +import content.global.handlers.scenery.BankBoothListener + +/** + * Listener for satchels from Creature Creation, repurposed for Snowscape + * They are repurposed as item pouches, using the summoning familiar inventory interface + * @author + */ +class SnowscapeSatchelListener : InteractionListener { + + companion object { + + val plainSatchelId = 10877 + val greenSatchelId = 10878 + val redSatchelId = 10879 + val blackSatchelId = 10880 + val goldSatchelId = 10881 + val runeSatchelId = 10882 + val satchelIds = intArrayOf(plainSatchelId,greenSatchelId,redSatchelId,blackSatchelId,goldSatchelId,runeSatchelId) + + //val runeSatchelAllowed = intArrayOf(558,559,564,562,9075,561,563,560,565,566) + //val runesForbidden = intArrayOf(556,555,557,554,4695,4696,4698,4697,4694,4699) + + + + + + private fun transferItem(player: Player, satchelId: Int, item: Item, amount: Int, withdraw: Boolean, asNote: Boolean = false) { + if (withdraw == false && !isAllowed(satchelId, unnote(item).getId())) { + player.sendMessage(item.getName() + " cannot be stored in the " + Item(satchelId).getName() + ".") + return + } + if (withdraw == true && asNote == false && satchelId == plainSatchelId) { + player.sendMessage("This satchel can only be emptied by a banker. Use it on a bank booth to get the items.") + return + } + val to = if (withdraw) player.getInventory() else getSatchel(player, satchelId) + val from = if (withdraw) getSatchel(player, satchelId) else player.getInventory() + val maximum = if (asNote) to.getMaximumAdd(note(item)) else to.getMaximumAdd(unnote(item)) + if (maximum < 1 && withdraw == false) { + player.sendMessage("There is not enough space for the " + item.getName() + " in the satchel.") + return + } + val finalAmount = kotlin.comparisons.minOf(amount, from.getAmount(item), maximum) + val finalItem = Item(item.getId(), finalAmount) + if (finalAmount > 0 && from.remove(finalItem)) { + if (asNote) to.add(note(finalItem)) else to.add(unnote(finalItem)) + } + } + + private fun emptySatchel(player: Player, satchelId: Int, asNote: Boolean = false) { + if (asNote == false && satchelId == plainSatchelId) { + player.sendMessage("This satchel can only be emptied by a banker. Use it on a Bank Booth to get the items.") + return + } + val satchel = getSatchel(player, satchelId) + repeat(satchel.capacity()) { index -> + var item = satchel.get(index) + if (item != null) { + transferItem(player, satchelId, item, satchel.getAmount(item), true, asNote) + } + } + } + + + //Function to handle constructing the correct interfaces when the satchel is opened + private fun openSatchel(player: Player, node: Node) { + val satchelId = node.asItem().getId() + val satchel = getSatchel(player, satchelId) + if (satchel.getListeners().count() < 1) satchel.register(BurdenContainerListener(player)) + + player.getInterfaceManager().open(Component(671)).setCloseEvent(CloseEvent { player, component -> + player.getInterfaceManager().closeSingleTab() + removeAttribute(player, "openSatchel") + return@CloseEvent true + } + ) + setAttribute(player, "openSatchel", satchelId) + satchel.shift() + player.getInterfaceManager().openSingleTab(Component(665)) + InterfaceContainer.generateItems(player, player.getInventory().toArray(), arrayOf("Store-X","Store-All","Store-10","Store-5","Store-1"),665,0,7,4,93) + InterfaceContainer.generateItems(player, satchel.toArray(), arrayOf("Withdraw-X","Withdraw-All","Withdraw-10","Withdraw-5","Withdraw-1"),671,27,5,6,30) + } + + // This is called by BurdenInterfacePlugin.java when the player interacts with the familiar interface and the "openSatchel" attribute exists + fun satchelInterfaceAction(player: Player, component: Component, opcode: Int, button: Int, slot: Int, itemId: Int) { + //player.sendMessage("Button:" + button.toString() + ". Opcode:" + opcode.toString()) + val satchelId = getAttribute(player, "openSatchel", 0) + val withdraw = component.getId() == 671 + val container = if (withdraw) getSatchel(player, satchelId) else player.getInventory() + val item = if (slot >= 0 && slot < container.capacity()) container.get(slot) else null + if (item == null && button != 29) return + when (opcode) { + 155 -> if (button == 29) emptySatchel(player, satchelId) else transferItem(player, satchelId, item!!, 1, withdraw) + 196 -> transferItem(player, satchelId, item!!, 5, withdraw) + 124 -> transferItem(player, satchelId, item!!, 10, withdraw) + 199 -> transferItem(player, satchelId, item!!, container.getAmount(item), withdraw) + 234 -> sendInputDialogue(player, true, "Enter the amount:") { value -> transferItem(player, satchelId, item!!, value as Int, withdraw) } + 9 -> player.sendMessage(item!!.getDefinition().getExamine()) + } + } + + + + fun getSatchel(player: Player, satchelId: Int): Container { + var satchel: Container? = null + when (satchelId) { + plainSatchelId -> satchel = player.plainSatchel + greenSatchelId -> satchel = player.greenSatchel + redSatchelId -> satchel = player.redSatchel + blackSatchelId -> satchel = player.blackSatchel + goldSatchelId -> satchel = player.goldSatchel + runeSatchelId -> satchel = player.runeSatchel + } + return satchel!! + } + + // Checks if the item is allowed in the satchel. The NPCDropTables.java function calls this on the Red Satchel if the player has one + fun isAllowed(satchelId: Int, itemId: Int): Boolean { + when (satchelId) { + plainSatchelId -> return itemId !in satchelIds + greenSatchelId -> return (Item(itemId).getName().contains(" seed") || Item(itemId).getName().contains("Grimy") || Item(itemId).getName().contains("Clean ")) + redSatchelId -> return itemId in intArrayOf(12158,12159,12160,12161,12162,12163,12164,12165,12166,12167,12168) + blackSatchelId -> return itemId in intArrayOf(995) + goldSatchelId -> return itemId in intArrayOf(436,438,440,442,444,446,447,449,451,453,668,2892) + runeSatchelId -> return itemId in intArrayOf(558,559,564,562,9075,561,563,560,565,566) + } + return false + } + } + + + + override fun defineListeners() { + + onUseAnyWith(IntType.ITEM, *satchelIds) { player, used, with -> + val satchelId = with.asItem().getId() + transferItem(player, satchelId, used.asItem(), player.getInventory().getAmount(used.asItem()),false) + return@onUseAnyWith true + } + + on(satchelIds, IntType.ITEM, "inspect","operate") { player, node -> + openSatchel(player, node) + return@on true + } + + on(satchelIds, IntType.ITEM, "empty") { player, node -> + emptySatchel(player, node.asItem().getId()) + return@on true + } + + // BankBoothListener values are public but BankChestListener values are not, so rather than edit the BankChestListener file I have copied the IDs here. 12309 is the Culinomancer's chest. + val bankChests = intArrayOf(3194,4483,10562,14382,16695,16696,21301,27662,27663) + val bankUseWiths = intArrayOf(*BankBoothListener.BANK_BOOTHS, 12309, *bankChests) + onUseWith(IntType.SCENERY, satchelIds, *bankUseWiths) { player, used, with -> + emptySatchel(player, used.asItem().getId(), true) + return@onUseWith true + } + + } +} diff --git a/Server/src/main/content/global/skill/farming/CropHarvester.kt b/Server/src/main/content/global/skill/farming/CropHarvester.kt index 79919bdca..b70347b67 100644 --- a/Server/src/main/content/global/skill/farming/CropHarvester.kt +++ b/Server/src/main/content/global/skill/farming/CropHarvester.kt @@ -83,14 +83,16 @@ class CropHarvester : OptionHandler() { return true } val necklace = getItemFromEquipment(player, EquipmentSlot.NECK) - var amulet = false + var noted = false if (necklace != null && (necklace.name.lowercase().contains("amulet of farming") || necklace.name.lowercase().contains("amulet of nature"))) { - amulet = true - } + noted = true + } else if (inEquipment(player,10878,1)) { + noted = true + } val sendHarvestMessages = if (fPatch.type == PatchType.FLOWER_PATCH) false else true if (sendHarvestMessages && firstHarvest) { sendMessage(player, "You begin to harvest the $patchName.") - if (amulet) { + if (noted) { sendMessage(player, "The leprechaun exchanges your produce for banknotes.") } firstHarvest = false @@ -100,7 +102,7 @@ class CropHarvester : OptionHandler() { // TODO: If a flower patch is being harvested, delay the clearing of the // patch until after the animation has played - https://youtu.be/lg4GktlVNUY?t=75 delay = 2 - if (amulet) { + if (noted) { addItem(player, note(reward).id) } else { addItem(player, reward.id) diff --git a/Server/src/main/content/global/skill/magic/SpellListener.kt b/Server/src/main/content/global/skill/magic/SpellListener.kt index 64383b0a7..c9ba1b177 100644 --- a/Server/src/main/content/global/skill/magic/SpellListener.kt +++ b/Server/src/main/content/global/skill/magic/SpellListener.kt @@ -62,7 +62,12 @@ abstract class SpellListener(val bookName: String) : Listener { } fun removeRunes(player: Player,removeAttr: Boolean = true){ + /* Snowscape modification: remove runes from the inventory or rune satchel player.inventory.remove(*player.getAttribute("spell:runes",ArrayList()).toTypedArray()) + */ + player.getAttribute("spell:runes",ArrayList()).toTypedArray().forEach { rune -> + if (!player.inventory.remove(rune)) player.runeSatchel.remove(rune) + } if(removeAttr) { player.removeAttribute("spell:runes") player.removeAttribute("tablet-spell") diff --git a/Server/src/main/content/global/skill/magic/SpellUtils.kt b/Server/src/main/content/global/skill/magic/SpellUtils.kt index a80d646a5..ce84d606f 100644 --- a/Server/src/main/content/global/skill/magic/SpellUtils.kt +++ b/Server/src/main/content/global/skill/magic/SpellUtils.kt @@ -6,6 +6,7 @@ import core.game.node.entity.combat.spell.CombinationRune import core.game.node.entity.combat.spell.MagicStaff import core.game.node.entity.combat.spell.Runes import core.game.node.item.Item +import core.api.* object SpellUtils { fun usingStaff(p: Player, rune: Int): Boolean { @@ -20,15 +21,16 @@ object SpellUtils { return false } + // Snowscape modifications: check the runeStachel container for the base runes if the player is carrying one fun hasRune(p:Player,rune:Item):Boolean{ val removeItems = p.getAttribute("spell:runes",ArrayList()) if(usingStaff(p,rune.id)) return true - if(p.inventory.containsItem(rune)){ + if(p.inventory.containsItem(rune) || (inEquipmentOrInventory(p, 10882) && p.runeSatchel.containsItem(rune))){ removeItems.add(rune) p.setAttribute("spell:runes",removeItems) } - val baseAmt = p.inventory.getAmount(rune.id) + val baseAmt = p.inventory.getAmount(rune.id) + (if (inEquipmentOrInventory(p, 10882)) p.runeSatchel.getAmount(rune.id) else 0) var amtRemaining = rune.amount - baseAmt val possibleComboRunes = CombinationRune.eligibleFor(Runes.forId(rune.id)) for (r in possibleComboRunes) { @@ -49,9 +51,9 @@ object SpellUtils { fun hasRune(p: Player, item: Item, toRemove: MutableList, message: Boolean): Boolean { if (!usingStaff(p, item.id)) { - val hasBaseRune = p.inventory.contains(item.id, item.amount) + val hasBaseRune = p.inventory.contains(item.id, item.amount) || (inEquipmentOrInventory(p, 10882) && p.runeSatchel.contains(item.id, item.amount)) if (!hasBaseRune) { - val baseAmt = p.inventory.getAmount(item.id) + val baseAmt = p.inventory.getAmount(item.id) + (if (inEquipmentOrInventory(p, 10882)) p.runeSatchel.getAmount(item.id) else 0) if (baseAmt > 0) { toRemove.add(Item(item.id, p.inventory.getAmount(item.id))) } diff --git a/Server/src/main/content/global/skill/smithing/smelting/SmeltingPulse.java b/Server/src/main/content/global/skill/smithing/smelting/SmeltingPulse.java index 5f7876db9..e3e06df64 100644 --- a/Server/src/main/content/global/skill/smithing/smelting/SmeltingPulse.java +++ b/Server/src/main/content/global/skill/smithing/smelting/SmeltingPulse.java @@ -99,7 +99,8 @@ public class SmeltingPulse extends SkillPulse { return false; } for (Item item : bar.getOres()) { - if (!player.getInventory().contains(item.getId(), item.getAmount())) { + //Snowscape modification: check gold satchel for ores as well, if carried + if (!player.getInventory().contains(item.getId(), item.getAmount()) && !(inEquipmentOrInventory(player, 10881, 1) && player.goldSatchel.contains(item.getId(), item.getAmount()))) { player.getPacketDispatch().sendMessage("You do not have the required ores to make this bar."); return false; } @@ -128,7 +129,7 @@ public class SmeltingPulse extends SkillPulse { player.getPacketDispatch().sendMessage("You place the required ores and attempt to create a bar of " + StringUtils.formatDisplayName(bar.toString().toLowerCase()) + "."); } for (Item i : bar.getOres()) { - if (!player.getInventory().remove(i)) { + if (!(player.getInventory().remove(i) || player.goldSatchel.remove(i))) { return true; } } @@ -147,7 +148,8 @@ public class SmeltingPulse extends SkillPulse { player.sendMessage("The magic of the Varrock armour enables you to smelt 2 bars at the same time."); } } - player.getInventory().add(new Item(bar.getProduct().getId(), amt)); + //player.getInventory().add(new Item(bar.getProduct().getId(), amt)); + addItemOrDrop(player, bar.getProduct().getId(), amt); player.dispatch(new ResourceProducedEvent(bar.getProduct().getId(), 1, player, -1)); double xp = bar.getExperience() * amt; // Goldsmith gauntlets diff --git a/Server/src/main/content/global/skill/summoning/familiar/BurdenInterfacePlugin.java b/Server/src/main/content/global/skill/summoning/familiar/BurdenInterfacePlugin.java index f9a8fd1a2..275b4abf5 100644 --- a/Server/src/main/content/global/skill/summoning/familiar/BurdenInterfacePlugin.java +++ b/Server/src/main/content/global/skill/summoning/familiar/BurdenInterfacePlugin.java @@ -11,6 +11,8 @@ import core.plugin.Initializable; import core.plugin.Plugin; import kotlin.Unit; +import content.global.handlers.item.SnowscapeSatchelListener; + /** * Handles the beast of burden interface. * @author Emperor @@ -27,6 +29,10 @@ public final class BurdenInterfacePlugin extends ComponentPlugin { @Override public boolean handle(Player player, Component component, int opcode, int button, int slot, int itemId) { + if (getAttribute(player, "openSatchel", null) != null) { + SnowscapeSatchelListener.Companion.satchelInterfaceAction(player, component, opcode, button, slot, itemId); + return true; + } if (!player.getFamiliarManager().hasFamiliar() || !player.getFamiliarManager().getFamiliar().isBurdenBeast()) { return false; } diff --git a/Server/src/main/content/minigame/mta/EnchantSpell.kt b/Server/src/main/content/minigame/mta/EnchantSpell.kt index d6df04fe8..fc8878a27 100644 --- a/Server/src/main/content/minigame/mta/EnchantSpell.kt +++ b/Server/src/main/content/minigame/mta/EnchantSpell.kt @@ -113,6 +113,7 @@ class EnchantSpell : MagicSpell { Items.SAPPHIRE_NECKLACE_1656 to Item(Items.GAMES_NECKLACE8_3853), Items.SAPPHIRE_AMULET_1694 to Item(Items.AMULET_OF_MAGIC_1727), Items.SAPPHIRE_BRACELET_11072 to Item(Items.BRACELET_OF_CLAY_11074), + Items.BLUE_DRAGONHIDE_1751 to Item(Items.PLAIN_SATCHEL_10877), //Begin MTA-specific enchantments Items.CUBE_6899 to Item(Items.ORB_6902), Items.CYLINDER_6898 to Item(Items.ORB_6902), @@ -132,6 +133,7 @@ class EnchantSpell : MagicSpell { Items.EMERALD_NECKLACE_1658 to Item(Items.BINDING_NECKLACE_5521), Items.EMERALD_AMULET_1696 to Item(Items.AMULET_OF_DEFENCE_1729), Items.EMERALD_BRACELET_11076 to Item(Items.CASTLEWAR_BRACE3_11079), + Items.GREEN_DRAGONHIDE_1753 to Item(Items.GREEN_SATCHEL_10878), //Begin MTA-Specific Enchantments Items.CUBE_6899 to Item(Items.ORB_6902), Items.CYLINDER_6898 to Item(Items.ORB_6902), @@ -151,6 +153,7 @@ class EnchantSpell : MagicSpell { Items.RUBY_NECKLACE_1660 to Item(Items.DIGSITE_PENDANT_5_11194), Items.RUBY_AMULET_1698 to Item(Items.AMULET_OF_STRENGTH_1725), Items.RUBY_BRACELET_11085 to Item(Items.INOCULATION_BRACE_11088), + Items.RED_DRAGONHIDE_1749 to Item(Items.RED_SATCHEL_10879), //Begin MTA-Specific Enchantments Items.CUBE_6899 to Item(Items.ORB_6902), Items.CYLINDER_6898 to Item(Items.ORB_6902), @@ -169,6 +172,7 @@ class EnchantSpell : MagicSpell { Items.DIAMOND_NECKLACE_1662 to Item(Items.PHOENIX_NECKLACE_11090), Items.DIAMOND_AMULET_1700 to Item(Items.AMULET_OF_POWER_1731), Items.DIAMOND_BRACELET_11092 to Item(Items.FORINTHRY_BRACE5_11095), + Items.DAGANNOTH_HIDE_6155 to Item(Items.GOLD_SATCHEL_10881), //Begin MTA-Specific Enchantments Items.CUBE_6899 to Item(Items.ORB_6902), Items.CYLINDER_6898 to Item(Items.ORB_6902), @@ -188,6 +192,7 @@ class EnchantSpell : MagicSpell { Items.DRAGON_NECKLACE_1664 to Item(Items.SKILLS_NECKLACE4_11105), Items.DRAGONSTONE_AMMY_1702 to Item(Items.AMULET_OF_GLORY4_1712), Items.DRAGON_BRACELET_11115 to Item(Items.COMBAT_BRACELET4_11118), + Items.SUQAH_HIDE_9080 to Item(Items.RUNE_SATCHEL_10882), //Begin MTA-Specific Enchantments Items.CUBE_6899 to Item(Items.ORB_6902), Items.CYLINDER_6898 to Item(Items.ORB_6902), @@ -207,6 +212,7 @@ class EnchantSpell : MagicSpell { Items.ONYX_NECKLACE_6577 to Item(Items.BERSERKER_NECKLACE_11128), Items.ONYX_AMULET_6581 to Item(Items.AMULET_OF_FURY_6585), Items.ONYX_BRACELET_11130 to Item(Items.REGEN_BRACELET_11133), + Items.BLACK_DRAGONHIDE_1747 to Item(Items.BLACK_SATCHEL_10880), //Begin MTA-Specific Enchantments Items.CUBE_6899 to Item(Items.ORB_6902), Items.CYLINDER_6898 to Item(Items.ORB_6902), diff --git a/Server/src/main/core/game/node/entity/combat/spell/MagicSpell.java b/Server/src/main/core/game/node/entity/combat/spell/MagicSpell.java index 601cc835f..250e9489d 100644 --- a/Server/src/main/core/game/node/entity/combat/spell/MagicSpell.java +++ b/Server/src/main/core/game/node/entity/combat/spell/MagicSpell.java @@ -21,6 +21,7 @@ import java.util.ArrayList; import java.util.List; import static core.api.ContentAPIKt.playGlobalAudio; +import static core.api.ContentAPIKt.inEquipmentOrInventory; /** * Represents a magic spell. @@ -243,7 +244,9 @@ public abstract class MagicSpell implements Plugin { } if (remove) { toRemove.forEach(i -> { - p.getInventory().remove(i); + if (!p.getInventory().remove(i)){ + p.runeSatchel.remove(i); + } }); } return true; @@ -277,7 +280,8 @@ public abstract class MagicSpell implements Plugin { */ public boolean hasRune(Player p, Item item, List toRemove, boolean message) { if (!usingStaff(p, item.getId())) { - boolean hasBaseRune = p.getInventory().contains(item.getId(),item.getAmount()); + // Snowscape modification: check the rune satchel for the base runes if the player is carrying one + boolean hasBaseRune = p.getInventory().contains(item.getId(),item.getAmount()) || (inEquipmentOrInventory(p, 10882,1) && p.runeSatchel.contains(item.getId(),item.getAmount())); if(!hasBaseRune){ int baseAmt = p.getInventory().getAmount(item.getId()); if(baseAmt > 0){ diff --git a/Server/src/main/core/game/node/entity/npc/drop/NPCDropTables.java b/Server/src/main/core/game/node/entity/npc/drop/NPCDropTables.java index 84f33d6ce..3a71d14ca 100644 --- a/Server/src/main/core/game/node/entity/npc/drop/NPCDropTables.java +++ b/Server/src/main/core/game/node/entity/npc/drop/NPCDropTables.java @@ -27,6 +27,7 @@ import content.global.skill.summoning.familiar.BurdenBeast; import content.global.skill.summoning.familiar.Forager; import content.global.skill.summoning.SummoningPouch; import content.global.skill.summoning.familiar.PackYakNPC; +import content.global.handlers.item.SnowscapeSatchelListener; import java.util.ArrayList; import java.util.List; @@ -104,6 +105,9 @@ public final class NPCDropTables { if (handleBoneCrusher(player, item)) { return; } + if (handleSatchel(player, item)) { + return; + } if (handleCurrency(player, item)) { return; } @@ -181,7 +185,7 @@ public final class NPCDropTables { return true; } if (((BurdenBeast) player.getFamiliarManager().getFamiliar()).getContainer().add(item)) { - player.sendMessage("Your familiar picked up " + item.getAmount() + " " + item.getName() + "."); + player.sendMessage("Your familiar picked up " + item.getAmount() + " " + item.getName() + "."); return true; } else { return false; @@ -266,6 +270,17 @@ public final class NPCDropTables { player.getSkills().addExperience(Skills.PRAYER, item.getAmount() * bone.getExperience()); return true; } + + //Snowscape modification: loot certain items into the red satchel if carried + private boolean handleSatchel(Player player, Item item) { + if (inEquipmentOrInventory(player,10879,1)){ + if (SnowscapeSatchelListener.Companion.isAllowed(10879,item.getId()) && player.redSatchel.add(item)) { + player.sendMessage("Your red satchel stashed " + item.getAmount() + " " + item.getName() + "."); + return true; + } + } + return false; + } /** * Snowscape custom: Automatically loot coins and tokkul if wearing a ring of wealth. @@ -278,7 +293,7 @@ public final class NPCDropTables { Item ring = player.getEquipment().get(12); if (ring != null && ring.getId() >= 14638 && ring.getId() <=14646) { if (player.getInventory().add(item)) { - player.sendMessage("Your Ring collected " + item.getAmount() + " " + item.getName() + "."); + player.sendMessage("Your ring collected " + item.getAmount() + " " + item.getName() + "."); return true; } } diff --git a/Server/src/main/core/game/node/entity/player/Player.java b/Server/src/main/core/game/node/entity/player/Player.java index afaa0c1f5..06436975c 100644 --- a/Server/src/main/core/game/node/entity/player/Player.java +++ b/Server/src/main/core/game/node/entity/player/Player.java @@ -311,6 +311,15 @@ public class Player extends Entity { public byte[] opCounts = new byte[255]; public int invalidPacketCount = 0; + // Snowscape additions + // The satchel containers. + public final Container plainSatchel = new Container(6, ContainerType.ALWAYS_STACK); + public final Container greenSatchel = new Container(30, ContainerType.ALWAYS_STACK); + public final Container redSatchel = new Container(30, ContainerType.ALWAYS_STACK); + public final Container blackSatchel = new Container(30, ContainerType.ALWAYS_STACK); + public final Container goldSatchel = new Container(30, ContainerType.ALWAYS_STACK); + public final Container runeSatchel = new Container(30, ContainerType.ALWAYS_STACK); + /** * Constructs a new {@code Player} {@code Object}. * @param details The player's details. diff --git a/Server/src/main/core/game/node/entity/player/info/login/PlayerSaveParser.kt b/Server/src/main/core/game/node/entity/player/info/login/PlayerSaveParser.kt index 03fc75d67..4f9d57e44 100644 --- a/Server/src/main/core/game/node/entity/player/info/login/PlayerSaveParser.kt +++ b/Server/src/main/core/game/node/entity/player/info/login/PlayerSaveParser.kt @@ -74,6 +74,7 @@ class PlayerSaveParser(val player: Player) { parseStatistics() parseAchievements() parsePouches() + parseSnowscapeData() } fun runContentHooks() @@ -358,4 +359,32 @@ class PlayerSaveParser(val player: Player) { player.version = saveFile!!["version"].toString().toInt() } } + + //Load the custom data added by snowscape + fun parseSnowscapeData() { + saveFile ?: return + if (!(saveFile!!.containsKey("snowscape_data"))) return + + val snowscapeData = saveFile!!["snowscape_data"] as JSONObject + + val plainSatchel = snowscapeData["plainSatchel"] + if (plainSatchel != null) player.plainSatchel.parse(plainSatchel as JSONArray) + + val greenSatchel = snowscapeData["greenSatchel"] + if (greenSatchel != null) player.greenSatchel.parse(greenSatchel as JSONArray) + + val redSatchel = snowscapeData["redSatchel"] + if (redSatchel != null) player.redSatchel.parse(redSatchel as JSONArray) + + val blackSatchel = snowscapeData["blackSatchel"] + if (blackSatchel != null) player.blackSatchel.parse(blackSatchel as JSONArray) + + val goldSatchel = snowscapeData["goldSatchel"] + if (goldSatchel != null) player.goldSatchel.parse(goldSatchel as JSONArray) + + val runeSatchel = snowscapeData["runeSatchel"] + if (runeSatchel != null) player.runeSatchel.parse(runeSatchel as JSONArray) + + + } } diff --git a/Server/src/main/core/game/node/entity/player/info/login/PlayerSaver.kt b/Server/src/main/core/game/node/entity/player/info/login/PlayerSaver.kt index 11c15b4d8..1f1e3d566 100644 --- a/Server/src/main/core/game/node/entity/player/info/login/PlayerSaver.kt +++ b/Server/src/main/core/game/node/entity/player/info/login/PlayerSaver.kt @@ -55,6 +55,7 @@ class PlayerSaver (val player: Player){ saveStatManager(saveFile) saveAttributes(saveFile) savePouches(saveFile) + saveSnowscapeData(saveFile) contentHooks.forEach { it.savePlayer(player, saveFile) } return saveFile } @@ -643,4 +644,18 @@ class PlayerSaver (val player: Player){ root.put("core_data",coreData) } + + // Function to save the custom data added by snowscape + fun saveSnowscapeData(root: JSONObject){ + val snowscapeData = JSONObject() + + snowscapeData.put("plainSatchel", saveContainer(player.plainSatchel)) + snowscapeData.put("greenSatchel", saveContainer(player.greenSatchel)) + snowscapeData.put("redSatchel", saveContainer(player.redSatchel)) + snowscapeData.put("blackSatchel", saveContainer(player.blackSatchel)) + snowscapeData.put("goldSatchel", saveContainer(player.goldSatchel)) + snowscapeData.put("runeSatchel", saveContainer(player.runeSatchel)) + + root.put("snowscape_data",snowscapeData) + } }