Rewrote pet management

Fixed being unable to remove pets
Removed redundant pet messaging
This commit is contained in:
Player Name
2023-10-04 23:19:57 +00:00
committed by Ryan
parent e5afeed6db
commit 7c38339e16
6 changed files with 175 additions and 114 deletions
@@ -4,6 +4,7 @@ import content.global.skill.summoning.pet.Pet;
import content.global.skill.summoning.pet.Pets;
import core.cache.def.impl.ItemDefinition;
import core.game.component.Component;
import core.game.container.Container;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import core.game.node.entity.skill.Skills;
@@ -27,6 +28,7 @@ import static core.api.ContentAPIKt.*;
/**
* Handles a player's familiar.
* @author Emperor
* @author Player Name
*/
public final class FamiliarManager {
@@ -73,34 +75,58 @@ public final class FamiliarManager {
this.player = player;
}
public final void parse(JSONObject familiarData){
public final void parse(JSONObject familiarData) {
int currentPet = -1;
if (familiarData.containsKey("currentPet")) {
currentPet = Integer.parseInt(familiarData.get("currentPet").toString());
}
JSONArray petDetails = (JSONArray) familiarData.get("petDetails");
for(int i = 0 ; i < petDetails.size(); i++){
for (int i = 0 ; i < petDetails.size(); i++) {
JSONObject detail = (JSONObject) petDetails.get(i);
PetDetails details = new PetDetails(0);
details.updateHunger(Double.parseDouble(detail.get("hunger").toString()));
details.updateGrowth(Double.parseDouble(detail.get("growth").toString()));
details.setStage(Integer.parseInt(detail.get("stage").toString()));
this.petDetails.put(Integer.parseInt(detail.get("petId").toString()),details);
int itemIdHash = Integer.parseInt(detail.get("petId").toString());
// The below is for migrating legacy saves, which stored baby item IDs + growth stages
if (detail.containsKey("stage")) {
// The "itemIdHash" is actually the baby item ID. The "stage" gives the actual pet stage we want.
int babyItemId = itemIdHash;
int itemId = babyItemId;
int stage = Integer.parseInt(detail.get("stage").toString());
if (stage > 0) {
Pets pets = Pets.forId(babyItemId);
itemId = pets.getNextStageItemId(itemId);
if (stage > 1) {
itemId = pets.getNextStageItemId(itemId);
}
}
Item item = new Item(itemId);
item.setCharge(1000); //this is the default value that will correspond to the player's item
itemIdHash = item.getIdHash();
if (currentPet != -1 && currentPet == babyItemId) {
currentPet = itemIdHash;
}
}
this.petDetails.put(itemIdHash, details);
}
if(familiarData.containsKey("currentPet")){
int currentPet = Integer.parseInt( familiarData.get("currentPet").toString());
if (currentPet != -1) {
PetDetails details = this.petDetails.get(currentPet);
Pets pets = Pets.forId(currentPet);
int itemId = currentPet >> 16 & 0xFFFF;
Pets pets = Pets.forId(itemId);
if (details == null) {
details = new PetDetails(pets.getGrowthRate() == 0.0 ? 100.0 : 0.0);
this.petDetails.put(currentPet, details);
}
familiar = new Pet(player, details, currentPet, pets.getNpcId(details.getStage()));
} else if(familiarData.containsKey("familiar")){
familiar = new Pet(player, details, itemId, pets.getNpcId(itemId));
} else if (familiarData.containsKey("familiar")) {
JSONObject currentFamiliar = (JSONObject) familiarData.get("familiar");
int familiarId = Integer.parseInt( currentFamiliar.get("originalId").toString());
familiar = FAMILIARS.get(familiarId).construct(player,familiarId);
familiar.ticks = Integer.parseInt( currentFamiliar.get("ticks").toString());
familiar.specialPoints = Integer.parseInt( currentFamiliar.get("specialPoints").toString());
JSONArray famInv = (JSONArray) currentFamiliar.get("inventory");
if(famInv != null){
if (famInv != null) {
((BurdenBeast) familiar).container.parse(famInv);
}
familiar.setAttribute("hp",Integer.parseInt( currentFamiliar.get("lifepoints").toString()));
@@ -124,14 +150,14 @@ public final class FamiliarManager {
* @param deleteItem we should delete the item.
*/
public void summon(Item item, boolean pet, boolean deleteItem) {
boolean renew = false;
boolean renew = false;
if (hasFamiliar()) {
if(familiar.getPouchId() == item.getId()) {
renew = true;
} else {
player.getPacketDispatch().sendMessage("You already have a follower.");
return;
}
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.");
@@ -156,28 +182,28 @@ public final class FamiliarManager {
final int npcId = pouch.getNpcId();
Familiar fam = !renew ? FAMILIARS.get(npcId) : familiar;
if (fam == null) {
player.getPacketDispatch().sendMessage("Invalid familiar " + npcId + " - report on 2009scape github");
player.getPacketDispatch().sendMessage("Invalid familiar " + npcId + " - report on 2009scape GitLab");
return;
}
if(!renew) {
fam = fam.construct(player, npcId);
if (fam.getSpawnLocation() == null) {
player.getPacketDispatch().sendMessage("The spirit in this pouch is too big to summon here. You will need to move to a larger");
player.getPacketDispatch().sendMessage("area.");
return;
}
}
if(!renew) {
fam = fam.construct(player, npcId);
if (fam.getSpawnLocation() == null) {
player.getPacketDispatch().sendMessage("The spirit in this pouch is too big to summon here. You will need to move to a larger");
player.getPacketDispatch().sendMessage("area.");
return;
}
}
if (!player.getInventory().remove(item)) {
return;
}
player.getSkills().updateLevel(Skills.SUMMONING, -pouch.getSummonCost(), 0);
player.getSkills().addExperience(Skills.SUMMONING, pouch.getSummonExperience());
if(!renew) {
familiar = fam;
spawnFamiliar();
} else {
familiar.refreshTimer();
}
if(!renew) {
familiar = fam;
spawnFamiliar();
} else {
familiar.refreshTimer();
}
player.getAppearance().sync();
}
@@ -219,6 +245,7 @@ public final class FamiliarManager {
*/
private boolean summonPet(final Item item, boolean deleteItem, boolean morph, Location location) {
final int itemId = item.getId();
int itemIdHash = item.getIdHash();
if (itemId > 8850 && itemId < 8900) {
return false;
}
@@ -230,18 +257,26 @@ public final class FamiliarManager {
player.getDialogueInterpreter().sendDialogue("You need a summoning level of " + pets.getSummoningLevel() + " to summon this.");
return false;
}
int baseItemId = pets.getBabyItemId();
PetDetails details = petDetails.get(baseItemId);
if (details == null) {
PetDetails details = petDetails.get(itemIdHash);
if (details == null) { //init new pet
details = new PetDetails(pets.getGrowthRate() == 0.0 ? 100.0 : 0.0);
petDetails.put(baseItemId, details);
// Find an available individual slot
ArrayList<Integer> taken = new ArrayList<Integer>();
Container[] searchSpace = {player.getInventory(), player.getBankPrimary(), player.getBankSecondary()};
for (Container container : searchSpace) {
for (Item i : container.getAll(item)) {
taken.add(i.getCharge());
}
}
int individual;
for (individual = 0; taken.contains(individual) && individual < 0xFFFF; individual++) {}
details.setIndividual(individual);
item.setCharge(individual);
itemIdHash = item.getIdHash(); //updates the hashed item to include the new "charge" value
petDetails.put(itemIdHash, details);
}
int id = pets.getItemId(details.getStage());
if (itemId != id) {
player.getPacketDispatch().sendMessage("This is not the right pet, grow the pet correctly.");
return true;
}
int npcId = pets.getNpcId(details.getStage());
int npcId = pets.getNpcId(itemId);
if (npcId > 0) {
familiar = new Pet(player, details, itemId, npcId);
if (deleteItem) {
@@ -314,7 +349,9 @@ public final class FamiliarManager {
}
Pet pet = ((Pet) familiar);
PetDetails details = pet.getDetails();
if (player.getInventory().add(new Item(pet.getPet().getItemId(details.getStage())))) {
Item petItem = new Item(pet.getItemId());
petItem.setCharge(details.getIndividual());
if (player.getInventory().add(petItem)) {
player.animate(Animation.create(827));
player.getFamiliarManager().dismiss();
}
@@ -365,7 +402,7 @@ public final class FamiliarManager {
*/
public void dismiss(boolean saveDetails) {
if (hasPet() && !saveDetails) {
removeDetails(((Pet) familiar).getItemId());
removeDetails(((Pet) familiar).getItemIdHash());
}
if (hasFamiliar()) {
familiar.dismiss();
@@ -412,9 +449,9 @@ public final class FamiliarManager {
* @param value the value.
*/
public void setConfig(int value) {
int current = getVarp(player, 1160);
int current = getVarp(player, 1160);
int newVal = current + value;
setVarp(player, 1160, newVal);
setVarp(player, 1160, newVal);
}
/**
@@ -4,6 +4,8 @@ import content.global.skill.skillcapeperks.SkillcapePerks;
import content.global.skill.summoning.familiar.Familiar;
import content.global.skill.summoning.familiar.FamiliarSpecial;
import core.game.node.entity.player.Player;
import core.game.node.item.Item;
import core.game.world.GameWorld;
import static core.api.ContentAPIKt.*;
@@ -66,10 +68,12 @@ public final class Pet extends Familiar {
public void handleTickActions() {
final PetDetails petDetails = details;
if (getPet().getFood().length > 0) {
if(SkillcapePerks.isActive(SkillcapePerks.PET_MASTERY, owner)) {
petDetails.updateHunger(0);
} else {
petDetails.updateHunger(petDetails.getStage() == 0 ? 0.025 : 0.018);
if(!SkillcapePerks.isActive(SkillcapePerks.PET_MASTERY, owner)) {
double amount = itemId == pet.getBabyItemId() ? 0.025 : 0.018;
if (GameWorld.getSettings().isDevMode()) {
amount *= 100;
}
petDetails.updateHunger(amount);
}
}
double hunger = petDetails.getHunger();
@@ -84,13 +88,17 @@ public final class Pet extends Familiar {
if (hunger >= 100.0 && growthRate != 0 && pet.getFood().length != 0) {
owner.getFamiliarManager().dismiss(false);
owner.getFamiliarManager().setFamiliar(null);
setVarp(owner, 1175, 0);
setVarp(owner, 1175, 0);
owner.sendMessage("<col=ff0000>Your pet has run away.</col>");
return;
}
double growth = petDetails.getGrowth();
if (pet.getGrowthRate() > 0.000) {
petDetails.updateGrowth(pet.getGrowthRate());
double growthrate = pet.getGrowthRate();
if (growthrate > 0.000) {
if (GameWorld.getSettings().isDevMode()) {
growthrate *= 100;
}
petDetails.updateGrowth(growthrate);
if (growth == 100.0) {
growNextStage();
}
@@ -102,31 +110,27 @@ public final class Pet extends Familiar {
} else if (!getPulseManager().hasPulseRunning()) {
startFollowing();
}
setVarp(owner, 1175, ((int) details.getGrowth() << 1) | ((int) details.getHunger() << 9));
setVarp(owner, 1175, ((int) details.getGrowth() << 1) | ((int) details.getHunger() << 9));
}
/**
* Method used to grow the npc's next stage.
*/
public final void growNextStage() {
if (details.getStage() == 3) {
return;
}
public void growNextStage() {
if (pet == null) {
return;
}
int npcId = pet.getNpcId(details.getStage() + 1);
if (npcId < 1) {
int newItemId = pet.getNextStageItemId(itemId);
if (newItemId == -1) {
// then this pet is already overgrown
return;
}
details.setStage(details.getStage() + 1);
int itemId = pet.getItemId(details.getStage());
if (pet.getNpcId(details.getStage() + 1) > 0) {
details.updateGrowth(-100.0);
}
clear();
Pet newPet = new Pet(owner, details, itemId, npcId);
int npcId = pet.getNpcId(newItemId);
details.updateGrowth(-100.0);
Pet newPet = new Pet(owner, details, newItemId, npcId);
newPet.growthRate = growthRate;
newPet.hasWarned = hasWarned;
owner.getFamiliarManager().dismiss(false);
owner.getFamiliarManager().setFamiliar(newPet);
owner.getPacketDispatch().sendMessage("<col=ff0000>Your pet has grown larger.</col>");
owner.getFamiliarManager().spawnFamiliar();
@@ -171,6 +175,16 @@ public final class Pet extends Familiar {
return itemId;
}
/**
* Gets the itemId with the individual hashed in.
* @return The itemIdHash.
*/
public int getItemIdHash() {
Item item = new Item(itemId);
item.setCharge(details.getIndividual());
return item.getIdHash();
}
/**
* Gets the details.
* @return The details.
@@ -2,11 +2,10 @@ package content.global.skill.summoning.pet;
import core.game.world.GameWorld;
/**
* A class containing pet details for a certain pet.
* @author Emperor
* @author Player Name
*/
public final class PetDetails {
@@ -21,9 +20,9 @@ public final class PetDetails {
private double growth = 0.0;
/**
* The current stage of the pet (0 - baby, 1 - grown, 2 - overgrown).
* The individual, an in principle arbitrary integer read off of the item's charge slot.
*/
private int stage;
private int individual;
/**
* Constructs a new {@code PetDetails} {@code Object}.
@@ -38,15 +37,9 @@ public final class PetDetails {
* @param amount The amount.
*/
public void updateHunger(double amount) {
if(GameWorld.getSettings().isDevMode()){
hunger += amount * 100;
} else {
hunger += amount;
}
hunger += amount;
if (hunger < 0.0) {
hunger = 0.0;
} else if (hunger > 100.0) {
hunger = 100.0;
}
}
@@ -80,19 +73,18 @@ public final class PetDetails {
}
/**
* Gets the stage.
* @return The stage.
* Sets the individual.
* @param individual The individual to set.
*/
public int getStage() {
return stage;
public void setIndividual(int individual) {
this.individual = individual;
}
/**
* Sets the stage.
* @param stage The stage to set.
* Gets the individual.
* @return The individual.
*/
public void setStage(int stage) {
this.stage = stage;
public int getIndividual() {
return individual;
}
}
}
@@ -1,13 +1,17 @@
package content.global.skill.summoning.pet;
import core.game.node.entity.player.Player;
import core.tools.Log;
import java.util.HashMap;
import java.util.Map;
import static core.api.ContentAPIKt.log;
/**
* An enum containing all the pets and their info.
* @author Emperor
* @author Player Name
*/
public enum Pets {
@@ -446,35 +450,35 @@ public enum Pets {
/**
* Gets the NPC id for this pet.
* @param stage The stage of the pet.
* @return The NPc id.
* @param itemId An int giving the ID of the item for which we want to know the corresponding NPC id.
* @return The NPC id.
*/
public int getNpcId(int stage) {
switch (stage) {
case 0:
return babyNpcId;
case 1:
return grownNpcId;
case 2:
return overgrownNpcId;
public int getNpcId(int itemId) {
if (itemId == babyItemId) {
return babyNpcId;
}
return 0;
if (itemId == grownItemId) {
return grownNpcId;
}
if (itemId == overgrownItemId) {
return overgrownNpcId;
}
log(this.getClass(), Log.ERR, "Could not locate NPC ID for pet item " + itemId);
return -1;
}
/**
* Gets the item id for this pet.
* @param stage The stage of the pet.
* @return The item id.
* Gets the next growth stage's item ID for this pet.
* @param itemId An int giving the current pet's item ID.
* @return The item ID for the next growth stage, or -1 if there isn't any (i.e. pet is already overgrown).
*/
public int getItemId(int stage) {
switch (stage) {
case 0:
return babyItemId;
case 1:
return grownItemId;
case 2:
return overgrownItemId;
public int getNextStageItemId(int itemId) {
if (itemId == babyItemId) {
return grownItemId;
}
return 0;
if (itemId == grownItemId) {
return overgrownItemId;
}
return -1;
}
}
}
@@ -866,6 +866,21 @@ public class Container {
return null;
}
/**
* Gets all instances of an item, and returns them.
* @author Player Name
* @param item the item.
* @return a list of all items that were found (can be length 0).
*/
public ArrayList<Item> getAll(Item item){
ArrayList<Item> ret = new ArrayList<Item>();
for(Item i : items){
if(i == null) continue;
if(item.getId() == i.getId()) ret.add(i);
}
return ret;
}
/**
* Gets the next free slot.
*
@@ -279,12 +279,11 @@ class PlayerSaver (val player: Player){
detail.put("petId",it.key.toString())
detail.put("hunger",it.value.hunger.toString())
detail.put("growth",it.value.growth.toString())
detail.put("stage",it.value.stage.toString())
petDetails.add(detail)
}
familiarManager.put("petDetails",petDetails)
if(player.familiarManager.hasPet()){
familiarManager.put("currentPet",(player.familiarManager.familiar as Pet).pet.babyItemId.toString())
familiarManager.put("currentPet",(player.familiarManager.familiar as Pet).getItemIdHash().toString())
} else if (player.familiarManager.hasFamiliar()){
val familiar = JSONObject()
familiar.put("originalId",player.familiarManager.familiar.originalId.toString())