Emberveil source

tests/FishingContestCheck.java

import com.rs2.Constants;import com.rs2.event.*;import com.rs2.game.content.quests.*;import com.rs2.game.content.quests.impl.FishingContest;import com.rs2.game.dialogues.DialogueOptions;import com.rs2.game.items.ItemDefinitions;import com.rs2.game.players.*;import com.rs2.world.GlobalDropsHandler;import com.rs2.world.clip.*;import org.apollo.cache.*;import org.apollo.cache.decoder.*;import org.apollo.cache.def.*;import java.nio.file.*;import java.util.*;
public final class FishingContestCheck {
 static int checks;static Path root;static String original;
 static class F extends MemberQuestsCheck.Fixture {F(){playerName=playerName2="fishingquestqa";playerXP[Constants.FISHING]=1154;playerLevel[Constants.FISHING]=10;}}
 static void check(boolean ok,String message){checks++;if(!ok)throw new AssertionError(message);}
 static void dwarf(F p){p.pos(2822,3485,0);p.getNpcs().firstClickNpc(3679);}
 static void accept(F p){dwarf(p);check(p.nextChat==17500,"dwarf introduction");p.getDialogueHandler().sendDialogues(p.nextChat,232);DialogueOptions.handleDialogueOptions(p,9157);}
 static void bonzo(F p){p.pos(2637,3440,0);p.getNpcs().firstClickNpc(225);}
 static void ticks(){for(int i=0;i<3;i++)CycleEventHandler.getSingleton().process();}
 static void fish(F p){p.pos(2638,3443,0);p.getNpcs().firstClickNpc(233);ticks();}
 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.fishingContest==p.fishingContest&&q.fishingContestFlags==p.fishingContestFlags,"progress and garlic persist");check(q.questPoints==p.questPoints&&q.playerXP[Constants.FISHING]==p.playerXP[Constants.FISHING],"XP and QP persist");check(Arrays.equals(q.playerItems,p.playerItems)&&Arrays.equals(q.playerItemsN,p.playerItemsN),"inventory persists");return q;}
  finally{System.setProperty("user.dir",original);PlayerHandler.players[1]=null;}
 }
 static void world()throws Exception{
  check(NpcDefinition.lookup(3679)!=null,"Vestri server definition available");
  int[][] objects={{47,2642,3442},{48,2642,3441},{51,2662,3500},{58,2631,3498},{41,2638,3446},{55,2820,3484},{57,2876,3480},{54,2820,9883},{56,2876,9880}};
  for(int[] o:objects)check(Region.objectExists(o[0],o[1],o[2],0),"real quest object "+Arrays.toString(o));
  for(int[] p:new int[][]{{2822,3485},{2878,3481},{2639,3440},{2639,3445},{2643,3442},{2638,3441},{2638,3438},{2641,3430},{2638,3443},{2641,3442},{2643,3442},{2661,3500},{2663,3500},{2822,9883},{2878,9880},{2822,3484},{2878,3480}})check((Region.getClipping(p[0],p[1],0)&0x1280100)==0,"landing or NPC tile clear "+Arrays.toString(p));
  check(QuestRouteCheck.route(2643,3442,2661,3500,0,0),"Hemenster reaches railing outside");
  check(QuestRouteCheck.route(2662,3500,2631,3498,0,1),"railing reaches worm vine");
  check(QuestRouteCheck.route(2641,3442,2638,3444,0,1),"contest gate reaches fishing spot");
  check(QuestRouteCheck.route(2641,3442,2638,3446,0,1),"gate reaches garlic pipe");
  check(QuestRouteCheck.route(2643,3442,2643,3432,0,0),"contest area reaches Grandpa Jack door");
  check(QuestRouteCheck.route(2641,3432,2641,3430,0,1),"doorway reaches Grandpa Jack");
  check(QuestRouteCheck.route(2643,3442,2713,3484,0,0),"contest area reaches garlic house door");
  check(QuestRouteCheck.route(2713,3482,2714,3478,0,1),"inside garlic house reaches supply");
  check(QuestRouteCheck.route(2822,9883,2878,9880,0,0),"both passage landings connected");
  F p=new F();p.pos(2661,3500,0);p.getObjects().firstClickObject(51,2662,3500);check(p.teleportToX==2662&&p.teleportToY==3500,"railing enters wood");p.pos(2662,3500,0);p.getObjects().firstClickObject(51,2662,3500);check(p.teleportToX==2661,"railing exits wood");
  p.pos(2643,3442,0);p.getObjects().firstClickObject(47,2642,3442);check(p.teleportToX==0,"gate rejects missing pass");p.item(0,27);p.getObjects().firstClickObject(47,2642,3442);check(p.teleportToX==2641,"pass opens gate");p.pos(2641,3442,0);p.clear();p.getObjects().firstClickObject(47,2642,3442);check(p.teleportToX==2643,"lost pass never traps contestant inside");
  p.pos(2822,3484,0);p.getObjects().firstClickObject(55,2820,3484);check(p.teleportToX==0,"mountain passage locked before quest");p.fishingContest=5;p.getObjects().firstClickObject(55,2820,3484);check(p.teleportToX==2822&&p.teleportToY==9883,"west entrance unlocked");p.pos(2878,9880,0);p.getObjects().firstClickObject(56,2876,9880);check(p.teleportToX==2878&&p.teleportToY==3480,"east exit works");
  F garlic=new F();garlic.pos(2714,3478,0);GlobalDropsHandler.load(garlic);GlobalDropsHandler.pickup(garlic,1550,2714,3478);check(garlic.getItemAssistant().playerHasItem(1550),"garlic obtainable from existing world drop");
  com.rs2.game.globalworldobjects.Doors.getSingleton().load();
  F doors=new F();doors.pos(2643,3432,0);check(com.rs2.game.globalworldobjects.Doors.getSingleton().handleDoor(doors,1533,2642,3432,0),"Jack door renders open");doors.getObjects().firstClickObject(1533,2642,3432);check(doors.teleportToX==2641,"Jack doorway enters");doors.pos(2642,3432,0);doors.getObjects().firstClickObject(1534,2643,3432);check(doors.teleportToX==2643,"rotated Jack door exits x="+doors.teleportToX+" original="+Region.objectExists(1533,2642,3432,0)+" open="+Region.objectExists(1534,2643,3432,0)+" teleport="+doors.isTeleporting+" stop="+doors.stopPlayerPacket);
  doors.pos(2713,3484,0);check(com.rs2.game.globalworldobjects.Doors.getSingleton().handleDoor(doors,1530,2713,3483,0),"garlic door renders open");doors.getObjects().firstClickObject(1530,2713,3483);check(doors.teleportToY==3482,"garlic house enters");doors.pos(2713,3482,0);doors.getObjects().firstClickObject(1531,2713,3482);check(doors.teleportToY==3484,"rotated garlic door exits");
 }
 static void story()throws Exception{
  F p=new F();p.pos(0,0,0);p.getNpcs().firstClickNpc(232);check(p.nextChat==0&&p.fishingContest==0,"remote start rejected");
  p.playerXP[Constants.FISHING]=0;dwarf(p);check(p.nextChat==0,"level requirement uses real XP");p.playerXP[Constants.FISHING]=1154;
  dwarf(p);p.getDialogueHandler().sendDialogues(p.nextChat,232);DialogueOptions.handleDialogueOptions(p,9158);check(p.fishingContest==0,"decline");
  dwarf(p);p.getDialogueHandler().sendDialogues(p.nextChat,232);p.pos(0,0,0);DialogueOptions.handleDialogueOptions(p,9157);check(p.fishingContest==0,"remote accept rejected");
  for(int i=0;i<28;i++)p.item(i,995);accept(p);check(p.fishingContest==0,"full backpack defers pass and start");p.clear();accept(p);check(p.fishingContest==1&&p.getItemAssistant().playerHasItem(27),"accepted with pass");p=reload(p);
  p.clear();dwarf(p);check(p.getItemAssistant().getItemAmount(27)==1,"lost pass replacement");dwarf(p);check(p.getItemAssistant().getItemAmount(27)==1,"no duplicate pass");
  bonzo(p);check(p.fishingContest==1,"fee requires five coins");p.item(1,995);p.playerItemsN[1]=10;bonzo(p);check(p.fishingContest==2&&p.getItemAssistant().getItemAmount(995)==5,"entry fee once");p=reload(p);bonzo(p);check(p.getItemAssistant().getItemAmount(995)==5,"relog does not charge again");
  p.pos(2641,3430,0);p.getNpcs().firstClickNpc(230);p.getDialogueHandler().sendDialogues(p.nextChat,230);DialogueOptions.handleDialogueOptions(p,9157);check(p.getItemAssistant().playerHasItem(307)&&!p.getItemAssistant().playerHasItem(995),"Grandpa Jack sells normal rod for5");
  p.pos(2632,3498,0);p.getObjects().firstClickObject(58,2631,3498);check(!p.getItemAssistant().playerHasItem(25),"spade required");p.item(3,952);
  for(int i=0;i<4;i++)p.getObjects().firstClickObject(58,2631,3498);check(p.getItemAssistant().getItemAmount(25)==3,"three worms collected without unbounded duplicates");
  fish(p);check(!p.getItemAssistant().playerHasItem(338),"garlic required");
  p.item(6,1550);p.pos(2638,3445,1);FishingContest.useItem(p,41,2638,3446,1550);check(p.fishingContestFlags==0,"wrong-floor pipe rejected");p.pos(2638,3445,0);p.inTrade=true;FishingContest.useItem(p,41,2638,3446,1550);check(p.getItemAssistant().playerHasItem(1550),"trade blocks garlic");p.inTrade=false;FishingContest.useItem(p,41,2638,3446,1550);check(p.fishingContestFlags==1&&!p.getItemAssistant().playerHasItem(1550),"garlic consumed once");p=reload(p);
  p.pos(2638,3443,0);p.getNpcs().firstClickNpc(233);p.getNpcs().firstClickNpc(233);check(p.fishingContestCasting&&!p.getItemAssistant().playerHasItem(338),"casting delayed and cannot duplicate");p.pos(2637,3443,0);ticks();check(!p.getItemAssistant().playerHasItem(338)&&p.getItemAssistant().getItemAmount(25)==3,"movement cancels without bait loss");
  fish(p);check(p.getItemAssistant().getItemAmount(338)==1&&p.getItemAssistant().getItemAmount(25)==2,"first carp after animation");p=reload(p);
  fish(p);check(p.fishingContest==2&&p.getItemAssistant().getItemAmount(338)==2,"second carp");bonzo(p);check(p.fishingContest==2&&!p.getItemAssistant().playerHasItem(26),"cannot win with two fish");fish(p);check(p.fishingContest==3&&!p.getItemAssistant().playerHasItem(25),"third carp completes catch");p=reload(p);
  // Fill remaining slots: replacing a nonstacking carp preserves the trophy safely.
  for(int i=0;i<28;i++)if(p.playerItems[i]==0)p.item(i,995);bonzo(p);check(p.fishingContest==4&&p.getItemAssistant().getItemAmount(26)==1&&!p.getItemAssistant().playerHasItem(338),"full backpack exchanges catch for trophy");p=reload(p);
  p.getItemAssistant().deleteItem(26,1);dwarf(p);check(p.fishingContest==4&&p.questPoints==0,"missing trophy cannot finish");bonzo(p);check(p.getItemAssistant().getItemAmount(26)==1,"lost trophy replacement");
  p.inDuel=true;dwarf(p);check(p.fishingContest==4,"duel blocks completion");p.inDuel=false;int xp=p.playerXP[Constants.FISHING];dwarf(p);check(p.fishingContest==5&&p.questPoints==1&&p.playerXP[Constants.FISHING]-xp==9748,"one QP and2437x4Fishing XP");check(!p.getItemAssistant().playerHasItem(26),"trophy consumed");p=reload(p);
  xp=p.playerXP[Constants.FISHING];for(int i=0;i<8;i++){dwarf(p);bonzo(p);DialogueOptions.handleDialogueOptions(p,9157);}check(p.questPoints==1&&p.playerXP[Constants.FISHING]==xp,"replay and relog cannot duplicate rewards");
  QuestAssistant.questButtons(p,28191);check(QuestAssistant.Quests.FISHING_CONTEST.questStatus()&&QuestAssistant.MAXIMUM_QUESTPOINTS==Integer.getInteger("emberveil.test.expectedQuestPoints",43),"real quest journal enabled");
 }
 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/fishing-quest-save-check").normalize().toAbsolutePath();check(!Files.exists(root.resolve("data/characters/fishingquestqa.txt")),"preserve any pre-existing fixture");
  IndexedFileSystem cache=new IndexedFileSystem(Paths.get("data/cache"),true);new ItemDefinitionDecoder(cache).run();ItemDefinitions.load();new NpcDefinitionDecoder(cache).run();new ObjectDefinitionDecoder(cache).run();RegionFactory.load(cache);
  try{world();story();System.out.println("PASS "+checks+" Fishing Contest progression, inventory, persistence, reward and world checks");}
  finally{System.setProperty("user.dir",original);PlayerHandler.players[1]=null;Files.deleteIfExists(root.resolve("data/characters/fishingquestqa.txt"));Files.deleteIfExists(root.resolve("data/characters/fishingquestqa.txt.bak"));}
 }
}