Emberveil source

tests/ClockWorldCheck.java

import java.nio.file.*;import java.util.*;import org.apollo.cache.*;import org.apollo.cache.decoder.*;import com.rs2.world.clip.*;import com.rs2.game.content.quests.impl.ClockTower;
public class ClockWorldCheck {
 static int checks;
 static int[][] objects={{1754,2566,3242,0},{1755,2566,9642,0},{1754,2621,3261,0},{1755,2621,9661,0},{100,2575,3255,0},{1755,2575,9655,0},
 {1738,2572,3240,0},{1739,2572,3240,1},{1740,2572,3241,2},{37,2595,9657,0},{39,2579,9656,0},{1586,2575,9631,0},
 {1530,2567,3245,0},{1530,2569,3239,0},{1530,2574,3250,0},{1530,2575,9648,0},{1530,2575,9651,0},{1530,2582,9648,0},{1530,2582,9651,0},{1530,2595,9644,0},{1530,2598,9648,0},{1530,2602,9638,0}};
 static long key(int x,int y,int z){return ((long)z<<32)|((long)x<<16)|y;}
 static void add(ArrayDeque<int[]> q,Set<Long>s,int x,int y,int z){if(x<2550||x>2626||!((y>=3200&&y<=3270)||(y>=9600&&y<=9675)))return;if(s.add(key(x,y,z)))q.add(new int[]{x,y,z});}
 static void route(int sx,int sy,int sz,int tx,int ty,int tz,int radius,int flags,String label){
  ClockTowerCheck.F p=new ClockTowerCheck.F();p.clockTower=1;p.clockPuzzle=flags;
  ArrayDeque<int[]> q=new ArrayDeque<>();Set<Long>s=new HashSet<>();add(q,s,sx,sy,sz);int best=9999,bx=0,by=0;
  while(!q.isEmpty()){
   int[] t=q.remove();int x=t[0],y=t[1],z=t[2];
   if(z==tz){int d=Math.max(Math.abs(x-tx),Math.abs(y-ty));if(d<best){best=d;bx=x;by=y;}if(d<=radius){checks++;System.out.println("ROUTE PASS "+label+" goal="+x+","+y+","+z+" explored="+s.size());return;}}
   for(int dx=-1;dx<=1;dx++)for(int dy=-1;dy<=1;dy++)if((dx!=0||dy!=0)&&Region.canMove(x,y,x+dx,y+dy,z,1,1))add(q,s,x+dx,y+dy,z);
   for(int[] a:objects)if(a[3]==z&&Math.abs(x-a[1])<=1&&Math.abs(y-a[2])<=1){
    for(int action=1;action<=3;action++){p.pos(x,y,z);ClockTower.object(p,a[0],a[1],a[2],action);if(p.teleportToX!=0)add(q,s,p.teleportToX,p.teleportToY,p.teleHeight);}
   }
  }throw new AssertionError(label+" inaccessible, closest="+bx+","+by+" d="+best+" visited="+s.size());
 }
 static void safe(int id,int x,int y,int size){for(int dx=0;dx<size;dx++)for(int dy=0;dy<size;dy++)if((Region.getClipping(x+dx,y+dy,0)&0x1280100)!=0)throw new AssertionError("Blocked NPC "+id+" "+x+","+y);checks++;}
 public static void main(String[]args)throws Exception{
  IndexedFileSystem c=new IndexedFileSystem(Paths.get("data/cache"),true);new ObjectDefinitionDecoder(c).run();RegionFactory.load(c);
  route(2568,3248,0,2574,9633,0,1,0,"Kojo to hot black cog");
  route(2574,9633,0,2570,9642,0,1,8,"black cog to basement spindle");
  route(2568,3248,0,2583,9613,0,1,0,"Kojo to red cog");
  route(2583,9613,0,2568,3243,0,1,0,"red cog to ground spindle");
  route(2568,3248,0,2613,9639,0,1,0,"Kojo to blue cog via outside ladder");
  route(2613,9639,0,2569,3240,1,1,0,"blue cog to upstairs spindle");
  route(2568,3248,0,2564,9662,0,1,0,"Kojo to rat poison");
  route(2564,9662,0,2591,9661,0,1,0,"poison to first lever");
  route(2591,9660,0,2593,9661,0,1,1,"first to second lever");
  route(2593,9660,0,2586,9654,0,1,3,"open enclosure to trough");
  route(2586,9655,0,2578,9655,0,1,7,"poisoned trough to white cog");
  route(2578,9655,0,2567,3241,2,1,7,"white cog to top spindle");
  route(2567,3242,2,2568,3248,0,1,15,"top spindle back to Kojo");
  for(int[]a:new int[][]{{223,2568,3248,1},{224,2584,9657,1},{224,2587,9657,1},{224,2590,9658,1},{60,2572,9633,1},{60,2576,9633,1},{115,2581,9611,2},{115,2581,9614,2}})safe(a[0],a[1],a[2],a[3]);
  System.out.println("PASS "+checks+" Clock Tower traversals and NPC footprints");
 }
}