Emberveil sourcetests/GertrudesCatCheck.java
import com.rs2.Constants;
import com.rs2.game.content.quests.QuestRewards;
import com.rs2.game.content.quests.impl.GertrudesCat;
import com.rs2.game.items.ItemDefinitions;
import com.rs2.game.npcs.*;
import com.rs2.game.players.*;
import com.rs2.net.Packet;
import com.rs2.net.packets.impl.ItemOnNpc;
import io.netty.buffer.*;
import org.apollo.cache.IndexedFileSystem;
import org.apollo.cache.decoder.*;
import java.nio.file.*;
import java.util.Arrays;
/** Real inventory, NPC/object dispatch, packet parsing, reward and save paths. */
public final class GertrudesCatCheck {
static int checks;
static void check(boolean ok,String label){checks++;if(!ok)throw new AssertionError(label);}
static class Fixture extends Client {
Fixture(){super(null,1);playerName=playerName2="gertruderegression";playerPass="local-test-only";
tutorialProgress=36;isActive=true;respawnTimer=-6;randomEventsEnabled=false;
Arrays.fill(playerLevel,99);Arrays.fill(playerXP,13034431);
getOutStream().packetEncryption=new org.apollo.util.security.IsaacRandom(new int[]{1,2,3,4});}
public void flushOutStream(){getOutStream().currentOffset=0;}
void clear(){Arrays.fill(playerItems,0);Arrays.fill(playerItemsN,0);}
void item(int slot,int id){playerItems[slot]=id+1;playerItemsN[slot]=1;}
void full(){clear();for(int i=0;i<28;i++)item(i,995);}
}
static void use(Fixture p,int npc,int item,int slot) {
NpcHandler.npcs[17]=new Npc(17,npc);NpcHandler.npcs[17].absX=p.absX;NpcHandler.npcs[17].absY=p.absY;
ByteBuf b=Unpooled.buffer(6);b.writeByte(item>>8).writeByte((item+128)&255);
b.writeByte(0).writeByte(17+128);b.writeByte(slot).writeByte(0);
try{new ItemOnNpc().processPacket(p,new Packet(57,Packet.Type.FIXED,b));}finally{b.release();NpcHandler.npcs[17]=null;}
}
static void quest()throws Exception {
Fixture p=new Fixture();p.gertCat=5;p.full();
check(!GertrudesCat.collectKitten(p)&&p.gertCat==5,"full backpack cannot create a false reunion stage");
p.getObjects().firstClickObject(2620,3300,3500);
check(p.gertCat==5&&!p.getItemAssistant().playerHasItem(1554),"crate refuses full backpack without losing quest progress");
p.clear();check(GertrudesCat.collectKitten(p),"kitten collected with room");
check(p.gertCat==5&&p.getItemAssistant().playerHasItem(1554),"finding kitten leaves reunion unfinished");
check(!GertrudesCat.collectKitten(p),"cannot collect a second kitten");
p.nextChat=0;p.getNpcs().firstClickNpc(780);check(p.nextChat!=329,"cannot claim completion immediately after crate");
int qp=p.questPoints,xp=p.playerXP[Constants.COOKING];QuestRewards.gertFinish(p);
check(p.gertCat==5&&p.questPoints==qp&&p.playerXP[Constants.COOKING]==xp,"direct reward cannot skip reunion");
check(!GertrudesCat.returnKitten(p,780),"only Fluffs can receive kitten");
p.getNpcs().firstClickNpc(759);check(p.gertCat==6&&!p.getItemAssistant().playerHasItem(1554),"spawned Fluffs receives kitten by clicking");
check(!GertrudesCat.returnKitten(p,759),"reunion cannot repeat without kitten");
String original=System.getProperty("user.dir");Path root=Paths.get(original,"../../runtime/gertrude-save-check").normalize().toAbsolutePath();
Path save=root.resolve("data/characters/gertruderegression.txt");check(!Files.exists(save),"test cannot overwrite an existing save");
try{
System.setProperty("user.dir",root.toString());p.saveFile=p.saveCharacter=true;p.newPlayer=false;PlayerHandler.players[1]=p;
check(PlayerSave.saveGame(p),"reunion progress saves");Fixture q=new Fixture();check(PlayerSave.loadPlayerInfo(q,q.playerName,"",false)==1,"reunion reloads");
check(q.gertCat==6&&!q.getItemAssistant().playerHasItem(1554),"saved reunion and consumed kitten survive reload");p=q;
}finally{System.setProperty("user.dir",original);PlayerHandler.players[1]=null;Files.deleteIfExists(save);Files.deleteIfExists(Paths.get(save+".bak"));}
p.getNpcs().firstClickNpc(780);check(p.nextChat==329,"Gertrude starts reward dialogue only after reunion");
qp=p.questPoints;xp=p.playerXP[Constants.COOKING];p.getDialogueHandler().sendDialogues(337,780);
check(p.gertCat==7&&p.questPoints==qp+1&&p.playerXP[Constants.COOKING]==xp+1525*4,"real completion grants one QP and configured cooking XP");
check(p.getItemAssistant().playerHasItem(1560)&&p.getItemAssistant().playerHasItem(1897)&&p.getItemAssistant().playerHasItem(2003),"kitten cake and stew granted");
p.getDialogueHandler().sendDialogues(337,780);QuestRewards.gertFinish(p);
check(p.questPoints==qp+1&&p.playerXP[Constants.COOKING]==xp+1525*4,"replayed completion cannot grant more rewards");
p=new Fixture();p.gertCat=6;p.item(0,1554);qp=p.questPoints;QuestRewards.gertFinish(p);
check(p.gertCat==6&&p.questPoints==qp,"legacy collected-but-unreturned kitten cannot claim reward");
p.getNpcs().firstClickNpc(759);check(!p.getItemAssistant().playerHasItem(1554)&&GertrudesCat.readyForReward(p),"legacy state recovers by returning kitten");
}
static void itemUse(){
for(int npc:new int[]{759,2997}){
Fixture p=new Fixture();p.full();p.item(0,1927);p.gertCat=2;use(p,npc,1927,0);
check(p.gertCat==3&&p.getItemAssistant().playerHasItem(1925)&&!p.getItemAssistant().playerHasItem(1927),"milk works with full backpack on Fluffs "+npc);
p.full();p.item(0,1552);p.gertCat=3;use(p,npc,1552,0);check(p.gertCat==4&&!p.getItemAssistant().playerHasItem(1552),"seasoned sardine works on Fluffs "+npc);
p.full();p.item(0,1554);p.gertCat=5;use(p,npc,1554,0);check(p.gertCat==6&&!p.getItemAssistant().playerHasItem(1554),"kitten item use completes reunion with full backpack "+npc);
p.clear();p.item(0,1927);p.item(1,995);p.gertCat=2;use(p,npc,995,1);check(p.gertCat==2&&p.getItemAssistant().playerHasItem(1927),"wrong item cannot feed milk merely present in backpack "+npc);
}
}
public static void main(String[] args)throws Exception {
Constants.XP_RATE=4;Constants.VARIABLE_XP_RATE=false;
IndexedFileSystem cache=new IndexedFileSystem(Paths.get("data/cache"),true);new ItemDefinitionDecoder(cache).run();ItemDefinitions.load();new ObjectDefinitionDecoder(cache).run();
quest();itemUse();System.out.println("PASS: "+checks+" Gertrude's Cat regression checks");
}
}