Summoning rework

Pouches are not consumed. Points are not lost when summoning. However, lifespan is directly tied to summoning points, and the familiar despawns at zero points.
Created a new pouch storage that can be accessed from the summoning tab by pressing "call pet" when no familiar is active. This allows freely switching familiars as long as points are maintained.
Special move points start at empty instead of full, and replenish 1 point every 3 ticks instead of 15 points every 50 ticks.
This commit is contained in:
randy 2025-03-22 21:23:28 -06:00
parent 4991b07ff8
commit 4799069ebd
10 changed files with 147 additions and 24 deletions

View file

@ -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 -> {

View file

@ -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;

View file

@ -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<Object> {
/**
* 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<Object> {
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<Object> {
@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<Object> {
} else {
owner.getPacketDispatch().sendMessage("<col=ff0000>Your familiar has vanished.");
}
playAudio(owner, Sounds.PRAYER_DRAIN_2672);
dismiss();
return;
}
@ -665,7 +667,8 @@ public abstract class Familiar extends NPC implements Plugin<Object> {
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);
}
/**

View file

@ -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();

View file

@ -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")
}
}
}

View file

@ -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)

View file

@ -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}.

View file

@ -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)
}
}

View file

@ -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)
}
}

View file

@ -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