diff --git a/Server/src/main/content/global/skill/summoning/SummoningTabListener.kt b/Server/src/main/content/global/skill/summoning/SummoningTabListener.kt index c47862b62..ee39b8470 100644 --- a/Server/src/main/content/global/skill/summoning/SummoningTabListener.kt +++ b/Server/src/main/content/global/skill/summoning/SummoningTabListener.kt @@ -4,6 +4,8 @@ import content.global.skill.summoning.pet.Pet import core.api.sendMessage import core.game.interaction.InterfaceListener +import content.global.skill.summoning.familiar.SnowscapeFamiliarInterface + class SummoningTabListener : InterfaceListener { override fun defineInterfaceListeners() { on(662) { player, _, opcode, buttonID, _, _ -> @@ -12,7 +14,8 @@ class SummoningTabListener : InterfaceListener { if (player.familiarManager.hasFamiliar()) { player.familiarManager.familiar.call() } else { - player.getPacketDispatch().sendMessage("You don't have a follower.") + SnowscapeFamiliarInterface.Companion.openInterface(player) + //player.getPacketDispatch().sendMessage("You don't have a follower.") } } 67 -> { 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 275b4abf5..84de00f93 100644 --- a/Server/src/main/content/global/skill/summoning/familiar/BurdenInterfacePlugin.java +++ b/Server/src/main/content/global/skill/summoning/familiar/BurdenInterfacePlugin.java @@ -32,6 +32,10 @@ public final class BurdenInterfacePlugin extends ComponentPlugin { if (getAttribute(player, "openSatchel", null) != null) { SnowscapeSatchelListener.Companion.satchelInterfaceAction(player, component, opcode, button, slot, itemId); return true; + } + if (getAttribute(player, "openSummonStorage", false)) { + SnowscapeFamiliarInterface.Companion.interfaceAction(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/global/skill/summoning/familiar/Familiar.java b/Server/src/main/content/global/skill/summoning/familiar/Familiar.java index 064de882c..636787050 100644 --- a/Server/src/main/content/global/skill/summoning/familiar/Familiar.java +++ b/Server/src/main/content/global/skill/summoning/familiar/Familiar.java @@ -36,6 +36,8 @@ import java.util.List; import static core.api.ContentAPIKt.*; +import core.game.component.Component; + /** * Represents a familiar. * @author Emperor @@ -80,7 +82,7 @@ public abstract class Familiar extends NPC implements Plugin { /** * The amount of special points left. */ - protected int specialPoints = 60; + protected int specialPoints = 0; /** * The pouch id. @@ -178,7 +180,7 @@ public abstract class Familiar extends NPC implements Plugin { this.pointsPerTick = 0.0; } else { //int drain = pouch.getLevelRequired() - pouch.getSummonCost() + 1; - // Snowscape: removing the initial drain and making it drain over the life of the familiar. Removing the +1 makes the final drain happen on the last tick of the familiar's life. That works for our new system, as the familiar timer won't start until that final tick happens. + // Snowscape: removing the initial drain and making it drain over the life of the familiar. Removing the +1 makes the final drain happen on the last tick of the familiar's life. That works for our new system. int drain = pouch.getLevelRequired(); this.pointsPerTick = (double) drain / maximumTicks; } @@ -225,21 +227,20 @@ public abstract class Familiar extends NPC implements Plugin { @Override public void handleTickActions() { - //Snowscape: only count down the familiar timer if summoning points are zero, and give some summoning exp every minute a familiar is summoned. - if (owner.getSkills().getLevel(Skills.SUMMONING) == 0) { - ticks--; - } + //Snowscape: ticks are calculated from the summoning points (including fractional drain), so the familiar will despawn when points reach zero, but the timer goes up if points are restored + //ticks--; + ticks = Double.valueOf(maximumTicks*(owner.getSkills().getLevel(Skills.SUMMONING)-fracDrain)/pouch.getLevelRequired()).intValue(); if (getWorldTicks() % 100 == 0) { owner.getSkills().addExperience(Skills.SUMMONING, pouch.getLevelRequired()+10, true); } fracDrain += pointsPerTick; - if (fracDrain > 1.0 && ticks > 0) { + if (fracDrain > 1.0) { fracDrain -= 1.0; owner.getSkills().updateLevel(Skills.SUMMONING, -1, 0); } - if (ticks % 50 == 0) { - updateSpecialPoints(-15); + if (getWorldTicks() % 3 == 0) { + updateSpecialPoints(-1); if (!getText().isEmpty()) { super.sendChat(getText()); } @@ -258,6 +259,7 @@ public abstract class Familiar extends NPC implements Plugin { } else { owner.getPacketDispatch().sendMessage("Your familiar has vanished."); } + playAudio(owner, Sounds.PRAYER_DRAIN_2672); dismiss(); return; } @@ -665,7 +667,8 @@ public abstract class Familiar extends NPC implements Plugin { setVarp(owner, 1175, 182986); setVarp(owner, 1174, -1); owner.getAppearance().sync(); - owner.getInterfaceManager().setViewedTab(3); + owner.getInterfaceManager().openTab(new Component(662)); + owner.getInterfaceManager().setViewedTab(7); } /** diff --git a/Server/src/main/content/global/skill/summoning/familiar/FamiliarManager.java b/Server/src/main/content/global/skill/summoning/familiar/FamiliarManager.java index 94802a146..c9a9cb9fa 100644 --- a/Server/src/main/content/global/skill/summoning/familiar/FamiliarManager.java +++ b/Server/src/main/content/global/skill/summoning/familiar/FamiliarManager.java @@ -142,7 +142,13 @@ public final class FamiliarManager { ((BurdenBeast) familiar).container.parse(famInv); } familiar.setAttribute("hp",Integer.parseInt( currentFamiliar.get("lifepoints").toString())); - } + } else { + //Snowscape: Copied from Familiar.dismiss(), this clears the fields on the summoning tab if no familiar is loaded + setVarp(player, 448, -1); + setVarp(player, 1176, 0); + setVarp(player, 1175, 182986); + setVarp(player, 1174, -1); + } } /** @@ -164,12 +170,12 @@ public final class FamiliarManager { public void summon(Item item, boolean pet, boolean deleteItem) { boolean renew = false; if (hasFamiliar()) { - if (familiar.getPouchId() == item.getId()) { - renew = true; - } else { + //if (familiar.getPouchId() == item.getId()) { + // renew = true; + //} else { player.getPacketDispatch().sendMessage("You already have a follower."); return; - } + //} } if (player.getZoneMonitor().isRestricted(ZoneRestriction.FOLLOWERS) && !player.getLocks().isLocked("enable_summoning")) { player.getPacketDispatch().sendMessage("This is a Summoning-free area."); @@ -193,6 +199,10 @@ public final class FamiliarManager { return; } */ + if (player.getSkills().getLevel(Skills.SUMMONING) < 1) { + player.getPacketDispatch().sendMessage("You need at least one Summoning point to summon this familiar."); + return; + } final int npcId = pouch.getNpcId(); Familiar fam = !renew ? FAMILIARS.get(npcId) : familiar; if (fam == null) { @@ -207,11 +217,11 @@ public final class FamiliarManager { return; } } - if (!player.getInventory().remove(item)) { - return; - } + //if (!player.getInventory().remove(item)) { + // return; + //} //player.getSkills().updateLevel(Skills.SUMMONING, -pouch.getSummonCost(), 0); - player.getSkills().addExperience(Skills.SUMMONING, pouch.getSummonExperience()); + //player.getSkills().addExperience(Skills.SUMMONING, pouch.getSummonExperience()); if (!renew) { familiar = fam; spawnFamiliar(); diff --git a/Server/src/main/content/global/skill/summoning/familiar/SnowscapeFamiliarInterface.kt b/Server/src/main/content/global/skill/summoning/familiar/SnowscapeFamiliarInterface.kt new file mode 100644 index 000000000..388b746a0 --- /dev/null +++ b/Server/src/main/content/global/skill/summoning/familiar/SnowscapeFamiliarInterface.kt @@ -0,0 +1,96 @@ +package content.global.skill.summoning.familiar + +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.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 + +/* Custom Snowscape class. Allows storing summoning pouches in a special storage that can be accessed by using the "call familiar" button when no familiars are summoned. +* Familiars can be summoned from this storage. +* Designed around the snowscape summoning rework, where pouches are not consumed when summoning +*/ + +class SnowscapeFamiliarInterface { + companion object { + + + //Function to handle constructing the interface + public fun openInterface(player: Player) { + val storage = player.summoningPouches + if (storage.getListeners().count() < 1) storage.register(BurdenContainerListener(player)) + + player.getInterfaceManager().open(Component(671)).setCloseEvent(CloseEvent { player, component -> + player.getInterfaceManager().closeSingleTab() + removeAttribute(player, "openSummonStorage") + //Summoning tab cannot be interacted with until it's closed and re-opened for some reason + player.getInterfaceManager().removeTabs(7) + player.getInterfaceManager().openTab(Component(662)) + player.getInterfaceManager().setViewedTab(7) + return@CloseEvent true + } + ) + setAttribute(player, "openSummonStorage", true) + storage.shift() + player.getInterfaceManager().openSingleTab(Component(665)) + InterfaceContainer.generateItems(player, player.getInventory().toArray(), arrayOf("Add"),665,0,7,4,93) + InterfaceContainer.generateItems(player, storage.toArray(), arrayOf("Remove","Summon"),671,27,5,6,30) + } + + + fun interfaceAction(player: Player, component: Component, opcode: Int, button: Int, slot: Int, itemId: Int) { + val inventory = component.getId() == 665 + val container = if (inventory) player.getInventory() else player.summoningPouches + val item = if (slot >= 0 && slot < container.capacity()) container.get(slot) else null + if (item == null && button != 29) return + + if (opcode == 9) player.sendMessage(item!!.getDefinition().getExamine()) + + if (inventory) { + when (opcode) { + 155 -> addPouch(player, item!!) + } + } else { + when (opcode) { + 155 -> if (button != 29) summonPouch(player, item!!) + 196 -> removePouch(player, item!!) + } + } + } + + private fun addPouch(player: Player, item: Item) { + if (!hasOption(item, "Summon")){ + sendMessage(player, "You can only add summoning pouches.") + return + } else if (player.summoningPouches.containsItem(item)) { + sendMessage(player, "You have already added this familiar's pouch.") + return + } else if (player.summoningPouches.add(item)) { + player.getInventory().remove(item) + } + } + + private fun removePouch(player: Player, item: Item) { + if (player.getInventory().add(item)) { + player.summoningPouches.remove(item) + } + } + + private fun summonPouch(player: Player, item: Item) { + player.getInterfaceManager().close() + SummonFamiliarPlugin().handle(player, item, "summon") + } + + } +} \ No newline at end of file diff --git a/Server/src/main/core/api/utils/Permadeath.kt b/Server/src/main/core/api/utils/Permadeath.kt index 1e7f13e9f..cbd442bc7 100644 --- a/Server/src/main/core/api/utils/Permadeath.kt +++ b/Server/src/main/core/api/utils/Permadeath.kt @@ -49,6 +49,7 @@ fun permadeath(target: Player) { target.goldSatchel.clear() target.runeSatchel.clear() target.blackSatchel.clear() + target.summoningPouches.clear() // Skills target.skills = Skills(target) 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 06436975c..6416acb37 100644 --- a/Server/src/main/core/game/node/entity/player/Player.java +++ b/Server/src/main/core/game/node/entity/player/Player.java @@ -319,6 +319,8 @@ public class Player extends Entity { 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); + // The summoning pouch storage + public final Container summoningPouches = new Container(30); /** * Constructs a new {@code Player} {@code Object}. 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 cb0e151f4..2e661c782 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 @@ -387,6 +387,8 @@ class PlayerSaveParser(val player: Player) { val runeSatchel = snowscapeData["runeSatchel"] if (runeSatchel != null) player.runeSatchel.parse(runeSatchel as JSONArray) + val summoningPouches = snowscapeData["summoningPouches"] + if (summoningPouches != null) player.summoningPouches.parse(summoningPouches 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 1f1e3d566..15ab459af 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 @@ -656,6 +656,8 @@ class PlayerSaver (val player: Player){ snowscapeData.put("goldSatchel", saveContainer(player.goldSatchel)) snowscapeData.put("runeSatchel", saveContainer(player.runeSatchel)) + snowscapeData.put("summoningPouches", saveContainer(player.summoningPouches)) + root.put("snowscape_data",snowscapeData) } } diff --git a/Server/src/main/core/game/node/entity/player/link/InterfaceManager.java b/Server/src/main/core/game/node/entity/player/link/InterfaceManager.java index 4a0fb00ae..eaa9ca5da 100644 --- a/Server/src/main/core/game/node/entity/player/link/InterfaceManager.java +++ b/Server/src/main/core/game/node/entity/player/link/InterfaceManager.java @@ -358,9 +358,9 @@ public final class InterfaceManager { openTab(6, new Component(player.getSpellBookManager().getSpellBook())); // Magic break; case 7: - if (player.getFamiliarManager().hasFamiliar()) { + //if (player.getFamiliarManager().hasFamiliar()) { openTab(7, new Component(662)); - } + //} break; default: openTab(i, new Component(DEFAULT_TABS[i])); @@ -393,9 +393,9 @@ public final class InterfaceManager { openTab(4, new Component(Components.WORNITEMS_387)); // Equipment openTab(5, new Component(Components.PRAYER_271)); // Prayer openTab(6, new Component(player.getSpellBookManager().getSpellBook())); // Magic - if (player.getFamiliarManager().hasFamiliar()) { + //if (player.getFamiliarManager().hasFamiliar()) { openTab(7, new Component(Components.LORE_STATS_SIDE_662)); // summoning. - } + //} openTab(8, new Component(Components.FRIENDS2_550)); // Friends openTab(9, new Component(Components.IGNORE2_551)); // Ignores openTab(10, new Component(Components.CLANJOIN_589)); // Clan chat