Emberveil sourcetests/TribalTotemCheck.java
import com.rs2.Constants;import com.rs2.game.content.quests.*;import com.rs2.game.content.quests.impl.TribalTotem;import com.rs2.game.dialogues.DialogueOptions;import com.rs2.game.items.ItemDefinitions;import com.rs2.game.players.*;import com.rs2.world.clip.*;import org.apollo.cache.*;import org.apollo.cache.decoder.*;import java.nio.file.*;import java.util.*;
public class TribalTotemCheck {
static int checks;static Path root;static String original;
static class F extends MemberQuestsCheck.Fixture {F(){playerName=playerName2="tribaltotemqa";}}
static void check(boolean ok,String m){checks++;if(!ok)throw new AssertionError(m);}
static void kangai(F p){p.pos(TribalTotem.KANGAI_X,TribalTotem.KANGAI_Y,0);p.getNpcs().firstClickNpc(846);}
static void accept(F p){kangai(p);p.getDialogueHandler().sendDialogues(p.nextChat,846);DialogueOptions.handleDialogueOptions(p,9157);}
static F reload(F p)throws Exception{
p.saveFile=p.saveCharacter=true;p.newPlayer=false;PlayerHandler.players[1]=p;System.setProperty("user.dir",root.toString());
try{check(PlayerSave.saveGame(p),"save");F q=new F();check(PlayerSave.loadPlayerInfo(q,q.playerName,"",false)==1,"reload");check(q.tribalTotem==p.tribalTotem&&q.tribalFlags==p.tribalFlags,"all quest flags persist");check(q.questPoints==p.questPoints&&q.playerXP[Constants.THIEVING]==p.playerXP[Constants.THIEVING]&&Arrays.equals(q.playerItems,p.playerItems)&&Arrays.equals(q.playerItemsN,p.playerItemsN),"XP QP and items persist");return q;}finally{System.setProperty("user.dir",original);PlayerHandler.players[1]=null;}
}
static void wizard(F p){p.pos(2681,3325,0);p.getNpcs().firstClickNpc(844);DialogueOptions.handleDialogueOptions(p,9157);}
static void story()throws Exception{
F p=new F();p.playerXP[Constants.THIEVING]=0;p.playerLevel[Constants.THIEVING]=99;kangai(p);check(p.nextChat==0,"base21Thieving required, boosted level not sufficient");p.playerXP[Constants.THIEVING]=5018;
kangai(p);p.getDialogueHandler().sendDialogues(p.nextChat,846);DialogueOptions.handleDialogueOptions(p,9158);check(p.tribalTotem==0,"decline");
kangai(p);p.getDialogueHandler().sendDialogues(p.nextChat,846);p.pos(0,0,0);DialogueOptions.handleDialogueOptions(p,9157);check(p.tribalTotem==0,"walk-away acceptance rejected");accept(p);check(p.tribalTotem==1,"accept at21");p=reload(p);
p.pos(2628,3311,1);p.getNpcs().firstClickNpc(845);check(p.tribalFlags==0,"wrong-floor gardener");p.pos(2628,3311,0);p.getNpcs().firstClickNpc(845);check((p.tribalFlags&1)!=0,"gardener clue");
wizard(p);check(p.teleX==2651&&p.teleY==3272&&p.isTeleporting,"first block at RPDT without Rune Mysteries");p.isTeleporting=false;p.teleTimer=0;p.teleX=p.teleY=0;
p.teleBlockDelay=System.currentTimeMillis();p.teleBlockLength=60000;wizard(p);check(!p.isTeleporting&&p.teleX==0,"quest teleport respects teleblock");p.teleBlockLength=0;
p.pos(2649,3274,0);p.getNpcs().firstClickNpc(843);DialogueOptions.handleDialogueOptions(p,9157);check((p.tribalFlags&4)==0,"unlabelled crate cannot deliver");
p.pos(2651,3273,0);p.inTrade=true;p.getObjects().secondClickObject(2707,2650,3273);check(!p.getItemAssistant().playerHasItem(1858),"trade blocks label");p.inTrade=false;
p.clear();for(int i=0;i<28;i++)p.item(i,1511);p.getObjects().secondClickObject(2707,2650,3273);check(!p.getItemAssistant().playerHasItem(1858),"full inventory cannot lose label");p.clear();p.getObjects().secondClickObject(2707,2650,3273);check(p.getItemAssistant().getItemAmount(1858)==1,"label obtainable through actual second option");p.getObjects().secondClickObject(2707,2650,3273);check(p.getItemAssistant().getItemAmount(1858)==1,"no duplicate carried label");p=reload(p);
p.pos(2651,3272,0);TribalTotem.useItem(p,2708,2638,3320,1858);check((p.tribalFlags&2)==0,"wrong crate cannot relabel");TribalTotem.useItem(p,2708,2650,3271,995);check((p.tribalFlags&2)==0,"wrong item");TribalTotem.useItem(p,2708,2650,3271,1858);check((p.tribalFlags&2)!=0&&!p.getItemAssistant().playerHasItem(1858),"label consumed exactly once");p=reload(p);
p.pos(2649,3274,0);p.getNpcs().firstClickNpc(843);DialogueOptions.handleDialogueOptions(p,9157);check((p.tribalFlags&4)!=0,"crate delivered");p=reload(p);
p.item(0,1856);check(TribalTotem.readBook(p,1856),"guide book offers quest and existing journal");DialogueOptions.handleDialogueOptions(p,9158);check((p.tribalFlags&8)==0,"existing Emberveil journal preserved");TribalTotem.readBook(p,1856);DialogueOptions.handleDialogueOptions(p,9157);check((p.tribalFlags&8)!=0,"guide reveals middle name");
wizard(p);check(p.teleX==2638&&p.teleY==3321,"delivered block teleports to mansion");p.isTeleporting=false;p.teleTimer=0;
p.pos(2635,3323,0);p.getObjects().firstClickObject(2705,2634,3323);DialogueOptions.handleDialogueOptions(p,9178);check((p.tribalFlags&16)==0,"wrong combination rejected");p.getObjects().firstClickObject(2705,2634,3323);DialogueOptions.handleDialogueOptions(p,9180);check((p.tribalFlags&16)!=0&&p.teleportToX==2633,"KURT opens correct inner doorway");p=reload(p);
p.pos(2633,3322,0);p.getObjects().firstClickObject(2711,2631,3322);check(p.teleportToY==9720,"unchecked stairs trap");
p.pos(2633,9694,0);p.getObjects().firstClickObject(1755,2632,9694);check(p.teleportToX==2633&&p.teleportToY==3294,"sewer ladder escapes");
p.pos(2633,3322,0);p.getObjects().secondClickObject(2711,2631,3322);check((p.tribalFlags&32)!=0,"investigate discovers stair trap");p.getObjects().firstClickObject(2711,2631,3322);check(p.teleHeight==1&&p.teleportToX==2633&&p.teleportToY==3321,"investigated stairs safe");p=reload(p);
p.pos(2638,3323,0);p.getObjects().firstClickObject(2709,2638,3324);check(!p.getItemAssistant().playerHasItem(1857),"wrong-floor chest rejected");p.pos(2638,3323,1);p.getObjects().firstClickObject(2709,2638,3324);check(p.getItemAssistant().getItemAmount(1857)==1&&(p.tribalFlags&64)!=0,"totem recovered");p.getObjects().firstClickObject(2709,2638,3324);check(p.getItemAssistant().getItemAmount(1857)==1,"no duplicate carried totem");p=reload(p);
p.getItemAssistant().deleteItem(1857,1);p.pos(2638,3323,1);p.getObjects().firstClickObject(2709,2638,3324);check(p.getItemAssistant().playerHasItem(1857),"lost totem recovery");
for(int i=0;i<28;i++)if(p.playerItems[i]==0)p.item(i,1511);kangai(p);check(p.tribalTotem==1&&p.questPoints==0&&p.getItemAssistant().playerHasItem(1857),"full backpack defers all rewards without consuming totem");
for(int i=24;i<28;i++){p.playerItems[i]=0;p.playerItemsN[i]=0;}int xp=p.playerXP[Constants.THIEVING];kangai(p);check(p.tribalTotem==2&&p.questPoints==1&&p.getItemAssistant().getItemAmount(373)==5&&!p.getItemAssistant().playerHasItem(1857),"five swordfish replace totem plus four free slots");check(p.playerXP[Constants.THIEVING]-xp==7100,"1775baseXP atx4");p=reload(p);xp=p.playerXP[Constants.THIEVING];for(int i=0;i<6;i++)kangai(p);check(p.questPoints==1&&p.playerXP[Constants.THIEVING]==xp&&p.getItemAssistant().getItemAmount(373)==5,"no repeat rewards after relog");
check(!TribalTotem.readBook(p,1856),"normal journal restored after quest");QuestAssistant.questButtons(p,28213);check(QuestAssistant.Quests.TRIBAL_TOTEM.questStatus()&&QuestAssistant.MAXIMUM_QUESTPOINTS==45,"quest listed and journal enabled");
}
static void world(){
F gate=new F();gate.pos(2635,3306,0);check(TribalTotem.object(gate,1557,2635,3307,1)&&gate.teleportToY==3308,"garden gate enters");
gate.pos(2636,3308,0);TribalTotem.object(gate,1558,2636,3307,1);check(gate.teleportToY==3306,"garden gate leaves");
gate.pos(2635,3306,1);TribalTotem.object(gate,1557,2635,3307,1);check(gate.teleportToX==0,"garden gate rejects wrong floor");
int[][] objects={{2707,2650,3273,0},{2708,2650,3271,0},{2708,2638,3320,0},{2705,2634,3323,0},{2706,2635,3321,0},{2711,2631,3322,0},{2709,2638,3324,1},{1723,2631,3322,1},{1755,2632,9694,0}};
for(int[]a:objects)check(Region.objectExists(a[0],a[1],a[2],a[3]),"original object "+Arrays.toString(a));
for(int[]a:new int[][]{{2790,3182,0},{2628,3311,0},{2649,3274,0},{2681,3325,0},{2651,3272,0},{2638,3321,0},{2633,3323,0},{2635,3323,0},{2633,3322,0},{2633,3321,1},{2635,9720,0},{2633,3294,0}})check((Region.getClipping(a[0],a[1],a[2])&0x1280100)==0,"clear NPC or landing "+Arrays.toString(a));
}
public static void main(String[] args)throws Exception{
Constants.XP_RATE=4;Constants.VARIABLE_XP_RATE=false;original=System.getProperty("user.dir");root=Paths.get(original,"../../runtime/totem-quest-save-check").normalize().toAbsolutePath();check(!Files.exists(root.resolve("data/characters/tribaltotemqa.txt")),"preserve existing fixture");
IndexedFileSystem c=new IndexedFileSystem(Paths.get("data/cache"),true);new ItemDefinitionDecoder(c).run();ItemDefinitions.load();new NpcDefinitionDecoder(c).run();new ObjectDefinitionDecoder(c).run();RegionFactory.load(c);
try{world();story();System.out.println("PASS "+checks+" Tribal Totem integration and route checks");}finally{System.setProperty("user.dir",original);PlayerHandler.players[1]=null;Files.deleteIfExists(root.resolve("data/characters/tribaltotemqa.txt"));Files.deleteIfExists(root.resolve("data/characters/tribaltotemqa.txt.bak"));}
}
}