Advertisement
Guest User

Untitled

a guest
Mar 30th, 2017
68
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 33.40 KB | None | 0 0
  1. public class MPBot {
  2.  
  3. public static final int NO_INPUT = 0x00;
  4.  
  5. public static final int A = 0x01;
  6. public static final int B = 0x02;
  7. public static final int SELECT = 0x04;
  8. public static final int START = 0x08;
  9.  
  10. public static final int RIGHT = 0x10;
  11. public static final int LEFT = 0x20;
  12. public static final int UP = 0x40;
  13. public static final int DOWN = 0x80;
  14.  
  15. private static final int HARD_RESET = 0x800;
  16.  
  17. private static final String gameName;
  18. private static PrintWriter writer;
  19. private static PrintWriter particallyManips;
  20.  
  21. // Graph is only built right now to waste 10 steps, so more would need to be
  22. // added to make use of >= 204 frames.
  23. // Also more intros would need to be spelled out.
  24. private static final int MAX_COST;
  25.  
  26. private static final int MIN_CONSISTENCY = 52; // x/60
  27. private static final Location dest1 = new Location(17, 11);
  28. private static final Location dest2 = new Location(17, 11);
  29. private static final Location dest3 = new Location(28, 5);
  30. private static final Location dest4 = new Location(25, 9);
  31. private static final Location dest5 = new Location(25, 9);
  32. private static final Location dest6 = new Location(3, 2);
  33. private static final Location dest7 = new Location(5, 5);
  34. private static final Location dest8 = new Location(21, 17);
  35. private static final Location dest9 = new Location(12, 31);
  36.  
  37. private static PalStrat pal = new PalStrat("_pal", 0, new Integer[] { RedBlueAddr.biosReadKeypadAddr }, new Integer[] { LEFT }, new Integer[] { 1 });
  38. private static PalStrat nopal = new PalStrat("_nopal", 0, new Integer[] { RedBlueAddr.biosReadKeypadAddr }, new Integer[] { NO_INPUT }, new Integer[] { 1 });
  39. private static PalStrat abss = new PalStrat("_nopal(ab)", 0, new Integer[] { RedBlueAddr.biosReadKeypadAddr, RedBlueAddr.initAddr }, new Integer[] { A, A }, new Integer[] { 0, 0 });
  40. private static PalStrat holdpal = new PalStrat("_pal(hold)", 0, new Integer[] { RedBlueAddr.biosReadKeypadAddr, RedBlueAddr.initAddr }, new Integer[] { LEFT, LEFT }, new Integer[] { 0, 0 });
  41.  
  42. private static IntroSequence sequence;
  43. private static PalStrat palstrat = holdpal;
  44. private static int successes = 0;
  45.  
  46. private static HashMap<OverworldStateMP, ByteBuffer[]> saveMap = new HashMap<OverworldStateMP, ByteBuffer[]>();
  47. private static ArrayList<Long> seenStates = new ArrayList<Long>();
  48.  
  49. static {
  50. MAX_COST = 2 * 7 + 34 * 3;
  51. gameName = "red";
  52. }
  53.  
  54. // Sort tiles by starting cost (lower starting cost takes priority),
  55. // then by starting distance from grass (longer distance takes priority).
  56. //
  57. // The idea being that if you get to a state that's already been reached, it
  58. // has been from a state that has wasted
  59. // fewer frames to get to that point.
  60. static class SaveTileComparator implements Comparator<SaveTile> {
  61. @Override
  62. public int compare(SaveTile o1, SaveTile o2) {
  63. if (o1.getStartCost() != o2.getStartCost()) {
  64. return o1.getTrueStartCost() - o2.getTrueStartCost();
  65. } else {
  66. return o2.getOwPos().getMinStepsToGrass() - o1.getOwPos().getMinStepsToGrass();
  67. }
  68. }
  69. }
  70.  
  71. public static void main(String[] args) throws IOException, InterruptedException {
  72. // Make folder if necessary
  73. if (!new File("logs").exists()) {
  74. new File("logs").mkdir();
  75. }
  76.  
  77. if (!new File("roms").exists()) {
  78. new File("roms").mkdir();
  79. System.err.println("I need ROMs to simulate!");
  80. System.exit(0);
  81. }
  82.  
  83. if (!new File("roms/poke" + gameName + ".gbc").exists()) {
  84. System.err.println("Could not find poke" + gameName + ".gbc in roms directory!");
  85. System.exit(0);
  86. }
  87.  
  88. writer = new PrintWriter(new File(gameName + "_moon_paths.txt"));
  89. particallyManips = new PrintWriter(new File(gameName + "_partially_paths.txt"));
  90.  
  91. sequence = new IntroSequence(palstrat, gfSkip, nido0, title0, cont, cont);
  92. System.out.println("Number of intro sequences: " + 1);
  93.  
  94. long startTime = System.currentTimeMillis();
  95. pw1 = initTiles(pw1, RBMap.MT_MOON_1.getPokeworldOffsetX(), RBMap.MT_MOON_1.getPokeworldOffsetY(), RBMap.MT_MOON_1.getWidthInTiles(), RBMap.MT_MOON_1.getHeightInTiles(), false, new RBMapDestination(RBMap.MT_MOON_1, dest1));
  96. pw2 = initTiles(pw2, RBMap.MT_MOON_2.getPokeworldOffsetX(), RBMap.MT_MOON_2.getPokeworldOffsetY(), RBMap.MT_MOON_2.getWidthInTiles(), RBMap.MT_MOON_2.getHeightInTiles(), false, new RBMapDestination(RBMap.MT_MOON_2, dest2));
  97. pw3 = initTiles(pw3, RBMap.MT_MOON_3.getPokeworldOffsetX(), RBMap.MT_MOON_3.getPokeworldOffsetY(), RBMap.MT_MOON_3.getWidthInTiles(), RBMap.MT_MOON_3.getHeightInTiles(), false, new RBMapDestination(RBMap.MT_MOON_3, dest3));
  98. pw4 = initTiles(pw4, RBMap.MT_MOON_3.getPokeworldOffsetX(), RBMap.MT_MOON_3.getPokeworldOffsetY(), RBMap.MT_MOON_3.getWidthInTiles(), RBMap.MT_MOON_3.getHeightInTiles(), false, new RBMapDestination(RBMap.MT_MOON_3, dest4));
  99. pw5 = initTiles(pw5, RBMap.MT_MOON_2.getPokeworldOffsetX(), RBMap.MT_MOON_2.getPokeworldOffsetY(), RBMap.MT_MOON_2.getWidthInTiles(), RBMap.MT_MOON_2.getHeightInTiles(), false, new RBMapDestination(RBMap.MT_MOON_2, dest5));
  100. pw6 = initTiles(pw6, RBMap.MT_MOON_1.getPokeworldOffsetX(), RBMap.MT_MOON_1.getPokeworldOffsetY(), RBMap.MT_MOON_1.getWidthInTiles(), RBMap.MT_MOON_1.getHeightInTiles(), false, new RBMapDestination(RBMap.MT_MOON_1, dest6));
  101. pw7 = initTiles(pw7, RBMap.MT_MOON_1.getPokeworldOffsetX(), RBMap.MT_MOON_1.getPokeworldOffsetY(), RBMap.MT_MOON_1.getWidthInTiles(), RBMap.MT_MOON_1.getHeightInTiles(), false, new RBMapDestination(RBMap.MT_MOON_1, dest7));
  102. pw8 = initTiles(pw8, RBMap.MT_MOON_2.getPokeworldOffsetX(), RBMap.MT_MOON_2.getPokeworldOffsetY(), RBMap.MT_MOON_2.getWidthInTiles(), RBMap.MT_MOON_2.getHeightInTiles(), false, new RBMapDestination(RBMap.MT_MOON_2, dest8));
  103. pw9 = initTiles(pw9, RBMap.MT_MOON_3.getPokeworldOffsetX(), RBMap.MT_MOON_3.getPokeworldOffsetY(), RBMap.MT_MOON_3.getWidthInTiles(), RBMap.MT_MOON_3.getHeightInTiles(), false, new RBMapDestination(RBMap.MT_MOON_3, dest9));
  104.  
  105. // Connect the stages
  106. pw1[17][10].getEdge(OverworldAction.DOWN).setNextPos(pw2[25][9]);
  107. pw1[16][11].getEdge(OverworldAction.RIGHT).setNextPos(pw2[25][9]);
  108. pw1[17][12].getEdge(OverworldAction.UP).setNextPos(pw2[25][9]);
  109.  
  110. pw2[17][10].getEdge(OverworldAction.DOWN).setNextPos(pw3[25][9]);
  111. pw2[18][11].getEdge(OverworldAction.LEFT).setNextPos(pw3[25][9]);
  112. pw2[16][11].getEdge(OverworldAction.RIGHT).setNextPos(pw3[25][9]);
  113.  
  114.  
  115. pw3[27][5].getEdge(OverworldAction.RIGHT).setNextPos(pw4[28][5]);
  116.  
  117. pw4[26][9].getEdge(OverworldAction.LEFT).setNextPos(pw5[17][11]);
  118. pw4[25][10].getEdge(OverworldAction.UP).setNextPos(pw5[17][11]);
  119. pw4[24][9].getEdge(OverworldAction.RIGHT).setNextPos(pw5[17][11]);
  120. pw4[25][8].getEdge(OverworldAction.DOWN).setNextPos(pw5[17][11]);
  121.  
  122. pw5[25][10].getEdge(OverworldAction.UP).setNextPos(pw6[17][11]);
  123. pw5[24][9].getEdge(OverworldAction.LEFT).setNextPos(pw6[17][11]);
  124. pw5[25][8].getEdge(OverworldAction.DOWN).setNextPos(pw6[17][11]);
  125.  
  126. pw6[3][2].getEdge(OverworldAction.DOWN).setNextPos(pw7[3][3]);
  127. pw6[3][2].getEdge(OverworldAction.RIGHT).setNextPos(pw7[4][2]);
  128.  
  129. pw7[5][4].getEdge(OverworldAction.DOWN).setNextPos(pw8[5][5]);
  130. pw7[4][5].getEdge(OverworldAction.RIGHT).setNextPos(pw8[5][5]);
  131. pw7[6][5].getEdge(OverworldAction.LEFT).setNextPos(pw8[5][5]);
  132.  
  133. pw8[20][17].getEdge(OverworldAction.RIGHT).setNextPos(pw9[21][17]);
  134. pw8[21][16].getEdge(OverworldAction.DOWN).setNextPos(pw9[21][17]);
  135.  
  136. saveTiles.add(new SaveTile(pw1[24][7], 0, false));
  137.  
  138. long endTime = System.currentTimeMillis();
  139. System.out.printf("Generic edge generation time: %d ms\n", endTime - startTime);
  140.  
  141. for (SaveTile saveTile : saveTiles) {
  142. OverworldTile savePos = saveTile.getOwPos();
  143. Gb.loadGambatte(1);
  144. gb = new Gb(0, false);
  145. gb.startEmulator("roms/poke" + gameName + ".gbc");
  146. mem = new GBMemory(gb);
  147. wrap = new GBWrapper(gb, mem);
  148. OverworldStateMP owState = new OverworldStateMP(savePos.toString() + " - " + sequence.toString() + ":", saveTile.getOwPos(), (byte)1, true, new boolean[2], (byte)0, (byte)gb.getDivState(), (byte)mem.getHRA(), (byte)mem.getHRS(), saveTile.isViridianNpc(), (byte)mem.getTurnFrameStatus(), mem.getNPCTimers(), (short)0, (short)0);
  149. overworldSearch(owState);
  150. }
  151. writer.close();
  152. }
  153.  
  154. private static boolean isNull(ByteBuffer[] saves) {
  155. for(ByteBuffer save : saves) {
  156. if(save != null) {
  157. return false;
  158. }
  159. }
  160. return true;
  161. }
  162.  
  163. private static int i = 0;
  164.  
  165. private static void overworldSearch(OverworldStateMP ow) {
  166. i++;
  167. if(i % 80 == 0) {
  168. ArrayList<OverworldStateMP> sortedList = new ArrayList<>(saveMap.keySet());
  169. Collections.sort(sortedList);
  170. for(int i = 0; i < 30; i++) {
  171. saveMap.remove(sortedList.get(i));
  172. }
  173. }
  174. if(!seenStates.add(ow.getFfefUniqId())) {
  175. return;
  176. }
  177. if (ow.getWastedFrames() > MAX_COST) {
  178. return;
  179. }
  180. if (ow.getMap() == 33 && ow.getX() == 33 && ow.getY() == 11 && ow.getWastedFrames() + 34 > MAX_COST) {
  181. return;
  182. }
  183. ByteBuffer[] saves = saveMap.get(ow);
  184. if(saves == null) {
  185. saves = new ByteBuffer[60];
  186. }
  187. for (OverworldEdge edge : ow.getPos().getEdgeList()) {
  188. OverworldAction edgeAction = edge.getAction();
  189. if (ow.getMap() == 1 && ow.getX() == 47 - 30 && edgeAction == OverworldAction.RIGHT && ow.isViridianNpc()) {
  190. continue;
  191. }
  192. if (ow.aPressCounter() > 0 && (edgeAction == OverworldAction.A || edgeAction == OverworldAction.START_B || edgeAction == OverworldAction.S_A_B_S || edgeAction == OverworldAction.S_A_B_A_B_S)) {
  193. continue;
  194. }
  195. if (!ow.canPressStart() && (edgeAction == OverworldAction.START_B || edgeAction == OverworldAction.S_A_B_S || edgeAction == OverworldAction.S_A_B_A_B_S)) {
  196. continue;
  197. }
  198. int edgeCost = edge.getCost();
  199. if (ow.getWastedFrames() + edgeCost > MAX_COST) {
  200. continue;
  201. }
  202. OverworldStateMP newState;
  203. int owFrames = ow.getOverworldFrames() + edge.getFrames();
  204. ByteBuffer[] newsaves = new ByteBuffer[60];
  205. for(int i = 0; i < 60; i++) {
  206. newsaves[i] = saves[i];
  207. }
  208. switch (edgeAction) {
  209. case LEFT:
  210. case UP:
  211. case RIGHT:
  212. case DOWN:
  213. newState = checkIGT0(newsaves, ow, edge, Math.max(0, ow.aPressCounter() - 1), true);
  214. if (successes < MIN_CONSISTENCY) {
  215. break;
  216. }
  217. if (mem.getX() == dest9.x && mem.getY() == dest9.y && mem.getMap() == 61) {
  218. writer.println(ow.toString() + " " + edgeAction.logStr() + ", cost: " + (ow.getWastedFrames() + edgeCost) + ", owFrames: " + (owFrames) + " - " + successes + "/60");
  219. writer.flush();
  220. } else {
  221. particallyManips.println(ow.toString() + " " + edgeAction.logStr() + ", cost: " + (ow.getWastedFrames() + edgeCost) + ", owFrames: " + (owFrames) + " - " + successes + "/60");
  222. particallyManips.flush();
  223. saveMap.put(newState, newsaves);
  224. overworldSearch(newState);
  225. }
  226. break;
  227. case A:
  228. newState = checkIGT0(newsaves, ow, edge, 2, true);
  229. if (successes < MIN_CONSISTENCY) {
  230. break;
  231. }
  232. if (mem.getX() == dest9.x && mem.getY() == dest9.y && mem.getMap() == 61) {
  233. writer.println(ow.toString() + " " + edgeAction.logStr() + ", cost: " + (ow.getWastedFrames() + edgeCost) + ", owFrames: " + (owFrames) + " - " + successes + "/60");
  234. writer.flush();
  235. } else {
  236. particallyManips.println(ow.toString() + " " + edgeAction.logStr() + ", cost: " + (ow.getWastedFrames() + edgeCost) + ", owFrames: " + (owFrames) + " - " + successes + "/60");
  237. particallyManips.flush();
  238. saveMap.put(newState, newsaves);
  239. overworldSearch(newState);
  240. }
  241. break;
  242. case START_B:
  243. newState = checkIGT0(newsaves, ow, edge, 1, true);
  244. if (successes < MIN_CONSISTENCY) {
  245. break;
  246. }
  247. if (mem.getX() == dest9.x && mem.getY() == dest9.y && mem.getMap() == 61) {
  248. writer.println(ow.toString() + " " + edgeAction.logStr() + ", cost: " + (ow.getWastedFrames() + edgeCost) + ", owFrames: " + (owFrames) + " - " + successes + "/60");
  249. writer.flush();
  250. } else {
  251. particallyManips.println(ow.toString() + " " + edgeAction.logStr() + ", cost: " + (ow.getWastedFrames() + edgeCost) + ", owFrames: " + (owFrames) + " - " + successes + "/60");
  252. particallyManips.flush();
  253. saveMap.put(newState, newsaves);
  254. overworldSearch(newState);
  255. }
  256. break;
  257. case S_A_B_S:
  258. newState = checkIGT0(newsaves, ow, edge, 1, false);
  259. if (successes < MIN_CONSISTENCY) {
  260. break;
  261. }
  262. if (mem.getX() == dest9.x && mem.getY() == dest9.y && mem.getMap() == 61) {
  263. writer.println(ow.toString() + " " + edgeAction.logStr() + ", cost: " + (ow.getWastedFrames() + edgeCost) + ", owFrames: " + (owFrames) + " - " + successes + "/60");
  264. writer.flush();
  265. } else {
  266. particallyManips.println(ow.toString() + " " + edgeAction.logStr() + ", cost: " + (ow.getWastedFrames() + edgeCost) + ", owFrames: " + (owFrames) + " - " + successes + "/60");
  267. particallyManips.flush();
  268. saveMap.put(newState, newsaves);
  269. overworldSearch(newState);
  270. }
  271. break;
  272. case S_A_B_A_B_S:
  273. newState = checkIGT0(newsaves, ow, edge, 1, false);
  274. if (successes < MIN_CONSISTENCY) {
  275. break;
  276. }
  277. if (mem.getX() == dest9.x && mem.getY() == dest9.y && mem.getMap() == 61) {
  278. writer.println(ow.toString() + " " + edgeAction.logStr() + ", cost: " + (ow.getWastedFrames() + edgeCost) + ", owFrames: " + (owFrames) + " - " + successes + "/60");
  279. writer.flush();
  280. } else {
  281. particallyManips.println(ow.toString() + " " + edgeAction.logStr() + ", cost: " + (ow.getWastedFrames() + edgeCost) + ", owFrames: " + (owFrames) + " - " + successes + "/60");
  282. particallyManips.flush();
  283. saveMap.put(newState, newsaves);
  284. overworldSearch(newState);
  285. }
  286. break;
  287. default:
  288. break;
  289. }
  290. }
  291. }
  292.  
  293. private static OverworldStateMP checkIGT0(ByteBuffer[] saves, OverworldStateMP ow, OverworldEdge edge, int aPress, boolean startPress) {
  294. int successes = 60;
  295. ByteBuffer save = null;
  296. boolean areSavesNull = isNull(saves);
  297. if(areSavesNull) {
  298. gb.step(HARD_RESET);
  299. palstrat.execute(wrap);
  300. gfSkip.execute(wrap);
  301. nido0.execute(wrap);
  302. title0.execute(wrap);
  303. wrap.advanceToAddress(RedBlueAddr.igtInjectAddr);
  304. save = gb.saveState();
  305. }
  306. for (int i = 0; i <= 59; i++) {
  307. save = !areSavesNull ? saves[i] : save;
  308. if(save == null) {
  309. successes--;
  310. continue;
  311. }
  312. wrap.loadState(save);
  313. if(areSavesNull) {
  314. gb.writeMemory(0xDA45, i);
  315. cont.execute(wrap);
  316. cont.execute(wrap);
  317. wrap.advanceToAddress(RedBlueAddr.joypadOverworldAddr);
  318. }
  319. if (!execute(ow, edge, i)) {
  320. successes--;
  321. saves[i] = null;
  322. continue;
  323. }
  324. int res = wrap.advanceToAddress(RedBlueAddr.joypadOverworldAddr, RedBlueAddr.playCryAddr);
  325. if(res == RedBlueAddr.joypadOverworldAddr) {
  326. saves[i] = gb.saveState();
  327. }
  328. }
  329. boolean[] itemsPickedUp = ow.getItemsPickedUp();
  330. int itemIdx = ow.getItemIdx();
  331. if(timeToPickUpItem(ow.getMap(), ow.getX(), ow.getY(), itemsPickedUp)) {
  332. itemsPickedUp[itemIdx++] = true;
  333. }
  334. OverworldStateMP newState = new OverworldStateMP(ow.toString() + " " + edge.getAction().logStr(), edge.getNextPos(), (byte)aPress, startPress, itemsPickedUp, (byte)itemIdx, (byte)gb.getDivState(), (byte)mem.getHRA(), (byte)mem.getHRS(), ow.isViridianNpc(), (byte)mem.getTurnFrameStatus(), mem.getNPCTimers(), (short)(ow.getWastedFrames() + edge.getCost()), (short)(ow.getOverworldFrames() + (byte)edge.getFrames()));
  335. MPBot.successes = successes;
  336. return newState;
  337. }
  338.  
  339. private static boolean execute(OverworldStateMP ow, OverworldEdge edge, int i) {
  340. OverworldAction owAction = edge.getAction();
  341. int res;
  342. // System.out.print(owAction.logStr());
  343. switch (owAction) {
  344. case LEFT:
  345. case UP:
  346. case RIGHT:
  347. case DOWN:
  348. int input = 16 * (int) (Math.pow(2.0, (owAction.ordinal())));
  349.  
  350. // Execute the action
  351. wrap.injectRBInput(input);
  352. wrap.advanceWithJoypadToAddress(input, RedBlueAddr.joypadOverworldAddr + 1);
  353. if (travellingToWarp(edge.getNextPos().getMap(), edge.getNextPos().getX(), edge.getNextPos().getY())) {
  354. wrap.advanceWithJoypadToAddress(input, RedBlueAddr.enterMapAddr);
  355. wrap.advanceToAddress(RedBlueAddr.joypadOverworldAddr);
  356. } else {
  357. int result = wrap.advanceWithJoypadToAddress(input, RedBlueAddr.joypadOverworldAddr, RedBlueAddr.newBattleAddr, RedBlueAddr.manualTextScrollAddr);
  358. if (result == RedBlueAddr.manualTextScrollAddr) {
  359. System.out.println("TEXTBOX HIT AT " + mem.getX() + " " + mem.getY());
  360. return false;
  361. }
  362. // Did we turnframe or hit an
  363. // ignored input frame after
  364. // a
  365. // warp?
  366. while (mem.getX() != edge.getNextPos().getX() || mem.getY() != edge.getNextPos().getY()) {
  367. if (result == RedBlueAddr.newBattleAddr) {
  368. // Check for garbage
  369. int result2 = wrap.advanceWithJoypadToAddress(input, RedBlueAddr.encounterTestAddr, RedBlueAddr.joypadOverworldAddr);
  370.  
  371. if (result2 == RedBlueAddr.encounterTestAddr) {
  372. // Yes we can. What's up
  373. // on this tile?
  374. int hra = mem.getHRA();
  375. // logLN("hrandom add was "+hra);
  376. if (hra < 10) {
  377. return false;
  378. }
  379. }
  380. }
  381. // Do that input again
  382. wrap.advanceToAddress(RedBlueAddr.joypadOverworldAddr);
  383. wrap.injectRBInput(input);
  384. wrap.advanceWithJoypadToAddress(input, RedBlueAddr.joypadOverworldAddr + 1);
  385. result = wrap.advanceWithJoypadToAddress(input, RedBlueAddr.newBattleAddr, RedBlueAddr.joypadOverworldAddr);
  386. }
  387. // Can we get an encounter now?
  388. int result2 = wrap.advanceToAddress(RedBlueAddr.encounterTestAddr, RedBlueAddr.joypadOverworldAddr, RedBlueAddr.manualTextScrollAddr);
  389. if (result2 == RedBlueAddr.manualTextScrollAddr) {
  390. System.out.println("TEXTBOX HIT AT " + mem.getX() + " " + mem.getY());
  391. return false;
  392. }
  393. if (result2 == RedBlueAddr.encounterTestAddr) {
  394. int hra = mem.getHRA();
  395. if (hra < 10) {
  396. return false;
  397. }
  398. wrap.advanceToAddress(RedBlueAddr.joypadOverworldAddr);
  399. if (timeToPickUpItem(mem.getMap(), mem.getX(), mem.getY(), ow.getItemsPickedUp())) {
  400. // Pick it up
  401. wrap.injectRBInput(A);
  402. wrap.advanceWithJoypadToAddress(A, RedBlueAddr.textJingleCommandAddr);
  403. wrap.advanceToAddress(RedBlueAddr.joypadOverworldAddr);
  404. }
  405. }
  406. }
  407. return true;
  408. case A:
  409. wrap.injectRBInput(A);
  410. wrap.advanceFrame(A);
  411. res = wrap.advanceWithJoypadToAddress(A, RedBlueAddr.joypadOverworldAddr, RedBlueAddr.printLetterDelayAddr, RedBlueAddr.manualTextScrollAddr);
  412. if (res == RedBlueAddr.manualTextScrollAddr) {
  413. System.out.println("TEXTBOX HIT AT " + mem.getX() + " " + mem.getY());
  414. return false;
  415. }
  416. if (res == RedBlueAddr.joypadOverworldAddr) {
  417. return true;
  418. } else {
  419. return false;
  420. }
  421. case START_B:
  422. wrap.injectRBInput(START);
  423. wrap.advanceFrame(START);
  424. wrap.advanceWithJoypadToAddress(START, RedBlueAddr.joypadAddr);
  425. wrap.injectRBInput(B);
  426. wrap.advanceFrame(B);
  427. wrap.advanceWithJoypadToAddress(B, RedBlueAddr.joypadOverworldAddr);
  428. return true;
  429. case S_A_B_S:
  430. wrap.injectRBInput(START);
  431. wrap.advanceFrame(START);
  432. wrap.advanceToAddress(RedBlueAddr.joypadAddr);
  433. wrap.injectRBInput(A);
  434. wrap.advanceFrame(A);
  435. wrap.advanceWithJoypadToAddress(A, RedBlueAddr.joypadAddr);
  436. wrap.injectRBInput(B);
  437. wrap.advanceFrame(B);
  438. wrap.advanceWithJoypadToAddress(B, RedBlueAddr.joypadAddr);
  439. wrap.injectRBInput(START);
  440. wrap.advanceFrame(START);
  441. wrap.advanceWithJoypadToAddress(START, RedBlueAddr.joypadOverworldAddr);
  442. return true;
  443. case S_A_B_A_B_S:
  444. wrap.injectRBInput(START);
  445. wrap.advanceFrame(START);
  446. wrap.advanceWithJoypadToAddress(START, RedBlueAddr.joypadAddr);
  447. wrap.injectRBInput(A);
  448. wrap.advanceFrame(A);
  449. wrap.advanceWithJoypadToAddress(A, RedBlueAddr.joypadAddr);
  450. wrap.injectRBInput(B);
  451. wrap.advanceFrame(B);
  452. wrap.advanceWithJoypadToAddress(B, RedBlueAddr.joypadAddr);
  453. wrap.injectRBInput(A);
  454. wrap.advanceFrame(A);
  455. wrap.advanceWithJoypadToAddress(A, RedBlueAddr.joypadAddr);
  456. wrap.injectRBInput(B);
  457. wrap.advanceFrame(B);
  458. wrap.advanceWithJoypadToAddress(B, RedBlueAddr.joypadAddr);
  459. wrap.injectRBInput(START);
  460. wrap.advanceFrame(START);
  461. wrap.advanceWithJoypadToAddress(START, RedBlueAddr.joypadOverworldAddr);
  462. return true;
  463. default:
  464. return false;
  465. }
  466.  
  467. }
  468.  
  469. private static List<SaveTile> saveTiles = new ArrayList<>();
  470. private static OverworldTile[][] pw1 = new OverworldTile[RBMap.MT_MOON_1.getWidthInTiles() + 1][RBMap.MT_MOON_1.getHeightInTiles() + 1];
  471. private static OverworldTile[][] pw2 = new OverworldTile[RBMap.MT_MOON_2.getWidthInTiles() + 1][RBMap.MT_MOON_2.getHeightInTiles() + 1];
  472. private static OverworldTile[][] pw3 = new OverworldTile[RBMap.MT_MOON_3.getWidthInTiles() + 1][RBMap.MT_MOON_3.getHeightInTiles() + 1];
  473. private static OverworldTile[][] pw4 = new OverworldTile[RBMap.MT_MOON_3.getWidthInTiles() + 1][RBMap.MT_MOON_3.getHeightInTiles() + 1];
  474. private static OverworldTile[][] pw5 = new OverworldTile[RBMap.MT_MOON_2.getWidthInTiles() + 1][RBMap.MT_MOON_2.getHeightInTiles() + 1];
  475. private static OverworldTile[][] pw6 = new OverworldTile[RBMap.MT_MOON_1.getWidthInTiles() + 1][RBMap.MT_MOON_1.getHeightInTiles() + 1];
  476. private static OverworldTile[][] pw7 = new OverworldTile[RBMap.MT_MOON_1.getWidthInTiles() + 1][RBMap.MT_MOON_1.getHeightInTiles() + 1];
  477. private static OverworldTile[][] pw8 = new OverworldTile[RBMap.MT_MOON_2.getWidthInTiles() + 1][RBMap.MT_MOON_2.getHeightInTiles() + 1];
  478. private static OverworldTile[][] pw9 = new OverworldTile[RBMap.MT_MOON_3.getWidthInTiles() + 1][RBMap.MT_MOON_3.getHeightInTiles() + 1];
  479.  
  480. private static Gb gb;
  481. private static GBWrapper wrap;
  482. private static GBMemory mem;
  483.  
  484. private static OverworldTile[][] initTiles(OverworldTile[][] pw, int PW_START_X, int PW_START_Y, int PW_WIDTH, int PW_HEIGHT, boolean onBike, RBMapDestination... destinations) {
  485. int numFramesPerStep = 17;
  486. HashMap<RBMap, RBMapDestination> dests = new HashMap<RBMap, RBMapDestination>();
  487. HashMap<OverworldTile, List<Node>> paths = new HashMap<OverworldTile, List<Node>>();
  488. for (RBMapDestination dest : destinations) {
  489. dests.put(dest.getMap(), dest);
  490. }
  491. for (int i = 0; i <= PW_WIDTH; i++) {
  492. for (int j = 0; j <= PW_HEIGHT; j++) {
  493. int pwX = i + PW_START_X;
  494. int pwY = j + PW_START_Y;
  495. RBMap map = RBMap.getMapByPosition(pwX, pwY);
  496. int tileX = pwX - map.getPokeworldOffsetX();
  497. int tileY = pwY - map.getPokeworldOffsetY();
  498. if (map.getOverworldTile(tileX, tileY) != null) {
  499. pw[i][j] = new OverworldTile(map.getId(), tileX, tileY);
  500. }
  501. }
  502. }
  503. for (int i = 0; i <= PW_WIDTH; i++) {
  504. for (int j = 0; j <= PW_HEIGHT; j++) {
  505. if (pw[i][j] == null) {
  506. // tile is solid, don't want to waste calculating paths
  507. continue;
  508. }
  509. RBMap map = RBMap.getMapByID(pw[i][j].getMap());
  510. RBMapDestination dest = dests.get(map);
  511. if (dest == null) {
  512. dest = new RBMapDestination(map);
  513. dests.put(map, dest);
  514. }
  515. OverworldTilePath path = new OverworldTilePath(pw[i][j], dest);
  516. if (path.getShortestPath() == null) {
  517. // could not find a path to the destination
  518. continue;
  519. }
  520. List<Node> shortestPath = path.getShortestPath();
  521. pw[i][j].setMinStepsToGrass(shortestPath.size());
  522. paths.put(pw[i][j], shortestPath);
  523. }
  524. }
  525. for (int i = 0; i <= PW_WIDTH; i++) {
  526. for (int j = 0; j <= PW_HEIGHT; j++) {
  527. if (pw[i][j] == null) {
  528. // tile is solid, don't want to waste calculating paths
  529. continue;
  530. }
  531. RBMap map = RBMap.getMapByID(pw[i][j].getMap());
  532. RBMapDestination dest = dests.get(map);
  533. List<Node> path = paths.get(pw[i][j]);
  534. if (path == null) {
  535. continue;
  536. }
  537. if (dest.getMode() == RBMapDestination.WEST_CONNECTION && path.get(path.size() - 1).getPosition().x == 0) {
  538. RBMap destMap = map.getWestConnection();
  539. int tileX = destMap.getWidthInTiles() - 1;
  540. int tileY = path.get(path.size() - 1).getPosition().y + map.getPokeworldOffsetY() - destMap.getPokeworldOffsetY();
  541. pw[i][j].setMinStepsToGrass(pw[i][j].getMinStepsToGrass() + destMap.getOverworldTile(tileX, tileY).getMinStepsToGrass());
  542. }
  543. if (dest.getMode() == RBMapDestination.EAST_CONNECTION && path.get(path.size() - 1).getPosition().x == map.getWidthInTiles() - 1) {
  544. RBMap destMap = map.getWestConnection();
  545. int tileX = destMap.getWidthInTiles() + 1;
  546. int tileY = path.get(path.size() - 1).getPosition().y + map.getPokeworldOffsetY() - destMap.getPokeworldOffsetY();
  547. pw[i][j].setMinStepsToGrass(pw[i][j].getMinStepsToGrass() + destMap.getOverworldTile(tileX, tileY).getMinStepsToGrass());
  548. }
  549. if (dest.getMode() == RBMapDestination.SOUTH_CONNECTION && path.get(path.size() - 1).getPosition().y == map.getHeightInTiles() - 1) {
  550. RBMap destMap = map.getWestConnection();
  551. int tileX = path.get(path.size() - 1).getPosition().x + map.getPokeworldOffsetX() - destMap.getPokeworldOffsetX();
  552. int tileY = destMap.getHeightInTiles() + 1;
  553. pw[i][j].setMinStepsToGrass(pw[i][j].getMinStepsToGrass() + destMap.getOverworldTile(tileX, tileY).getMinStepsToGrass());
  554. }
  555. if (dest.getMode() == RBMapDestination.NORTH_CONNECTION && path.get(path.size() - 1).getPosition().y == 0) {
  556. RBMap destMap = map.getWestConnection();
  557. int tileX = path.get(path.size() - 1).getPosition().x + map.getPokeworldOffsetX() - destMap.getPokeworldOffsetX();
  558. int tileY = destMap.getHeightInTiles() - 1;
  559. pw[i][j].setMinStepsToGrass(pw[i][j].getMinStepsToGrass() + destMap.getOverworldTile(tileX, tileY).getMinStepsToGrass());
  560. }
  561. }
  562. }
  563. for (int i = 0; i <= PW_WIDTH; i++) {
  564. for (int j = 0; j <= PW_HEIGHT; j++) {
  565. if (pw[i][j] == null) {
  566. // tile is solid, don't want to waste calculating edges
  567. continue;
  568. }
  569. RBMap map = RBMap.getMapByID(pw[i][j].getMap());
  570. RBMapTile tile = map.getTile(pw[i][j].getX(), pw[i][j].getY());
  571. if (tile.canMoveLeft()) {
  572. if (i != 0) {
  573. OverworldTile destTile = pw[i - 1][j];
  574. if (destTile != null) {
  575. int cost = Math.abs(numFramesPerStep * (destTile.getMinStepsToGrass() - pw[i][j].getMinStepsToGrass() + 1));
  576. pw[i][j].addEdge(new OverworldEdge(OverworldAction.LEFT, cost, numFramesPerStep, destTile));
  577. }
  578. }
  579. }
  580. if (tile.canMoveRight()) {
  581. if (i != PW_WIDTH) {
  582. OverworldTile destTile = pw[i + 1][j];
  583. if (destTile != null) {
  584. int cost = Math.abs(numFramesPerStep * (destTile.getMinStepsToGrass() - pw[i][j].getMinStepsToGrass() + 1));
  585. pw[i][j].addEdge(new OverworldEdge(OverworldAction.RIGHT, cost, numFramesPerStep, destTile));
  586. }
  587. }
  588. }
  589. if (tile.canMoveUp()) {
  590. if (j != 0) {
  591. OverworldTile destTile = pw[i][j - 1];
  592. if (destTile != null) {
  593. int cost = Math.abs(numFramesPerStep * (destTile.getMinStepsToGrass() - pw[i][j].getMinStepsToGrass() + 1));
  594. pw[i][j].addEdge(new OverworldEdge(OverworldAction.UP, cost, numFramesPerStep, destTile));
  595. }
  596. }
  597. }
  598. if (tile.canMoveDown()) {
  599. if (j != PW_HEIGHT) {
  600. OverworldTile destTile = pw[i][j + 1];
  601. if (destTile != null) {
  602. int cost = Math.abs(numFramesPerStep * (destTile.getMinStepsToGrass() - pw[i][j].getMinStepsToGrass() + 1));
  603. pw[i][j].addEdge(new OverworldEdge(OverworldAction.DOWN, cost, numFramesPerStep, destTile));
  604. }
  605. }
  606. }
  607. pw[i][j].addEdge(new OverworldEdge(OverworldAction.A, 2, 2, pw[i][j]));
  608. int sbcost = 52;
  609. pw[i][j].addEdge(new OverworldEdge(OverworldAction.START_B, sbcost, sbcost, pw[i][j]));
  610. pw[i][j].addEdge(new OverworldEdge(OverworldAction.S_A_B_S, sbcost + 30, sbcost + 30, pw[i][j]));
  611. pw[i][j].addEdge(new OverworldEdge(OverworldAction.S_A_B_A_B_S, sbcost + 60, sbcost + 60, pw[i][j]));
  612. Collections.sort(pw[i][j].getEdgeList());
  613. }
  614. }
  615. return pw;
  616. }
  617.  
  618. public static Position getDestination(GBMemory mem, int input) {
  619. if (input == LEFT) {
  620. return new Position(mem.getMap(), mem.getX() - 1, mem.getY());
  621. } else if (input == RIGHT) {
  622. return new Position(mem.getMap(), mem.getX() + 1, mem.getY());
  623. } else if (input == UP) {
  624. return new Position(mem.getMap(), mem.getX(), mem.getY() - 1);
  625. } else if (input == DOWN) {
  626. return new Position(mem.getMap(), mem.getX(), mem.getY() + 1);
  627. } else {
  628. return new Position(mem.getMap(), mem.getX(), mem.getY());
  629. }
  630. }
  631.  
  632. public static boolean timeToPickUpItem(int map, int x, int y, boolean[] pickedUpItems) {
  633. if (map == 61) {
  634. if (!pickedUpItems[0] && x == 28 && y == 5) {
  635. return true;
  636. }
  637. }
  638. if (map == 59) {
  639. if (!pickedUpItems[1] && x == 3 && y == 2) {
  640. return true;
  641. }
  642. }
  643. return false;
  644. }
  645.  
  646. static class Strat {
  647. String name;
  648. int cost;
  649. Integer[] addr;
  650. Integer[] input;
  651. Integer[] advanceFrames;
  652.  
  653. Strat(String name, int cost, Integer[] addr, Integer[] input, Integer[] advanceFrames) {
  654. this.addr = addr;
  655. this.cost = cost;
  656. this.name = name;
  657. this.input = input;
  658. this.advanceFrames = advanceFrames;
  659. }
  660.  
  661. public void execute(GBWrapper wrap) {
  662. for (int i = 0; i < addr.length; i++) {
  663. wrap.advanceToAddress(addr[i]);
  664. wrap.injectRBInput(input[i]);
  665. for (int j = 0; j < advanceFrames[i]; j++) {
  666. wrap.advanceFrame();
  667. }
  668. }
  669. }
  670. }
  671.  
  672. static class IntroSequence extends ArrayList<Strat> implements Comparable<IntroSequence> {
  673. private static final long serialVersionUID = -7505108790448829235L;
  674.  
  675. IntroSequence(Strat... strats) {
  676. super(Arrays.asList(strats));
  677. }
  678.  
  679. IntroSequence(IntroSequence other) {
  680. super(other);
  681. }
  682.  
  683. @Override
  684. public String toString() {
  685. String ret = gameName;
  686. for (Strat s : this) {
  687. ret += s.name;
  688. }
  689. return ret;
  690. }
  691.  
  692. void execute(GBWrapper wrap) {
  693. for (Strat s : this) {
  694. s.execute(wrap);
  695. }
  696. }
  697.  
  698. int cost() {
  699. return this.stream().mapToInt((Strat s) -> s.cost).sum();
  700. }
  701.  
  702. @Override
  703. public int compareTo(IntroSequence o) {
  704. return this.cost() - o.cost();
  705. }
  706. }
  707.  
  708. private static boolean travellingToWarp(int map, int x, int y) {
  709. if (map == 59) {
  710. if (x == 5 && y == 5) {
  711. return true;
  712. } else if (x == 17 && y == 11) {
  713. return true;
  714. }
  715. } else if (map == 60) {
  716. if (x == 25 && y == 9) {
  717. return true;
  718. } else if (x == 17 && y == 11) {
  719. return true;
  720. } else if (x == 21 && y == 17) {
  721. return true;
  722. }
  723. } else {
  724. if (x == 25 && y == 9) {
  725. return true;
  726. }
  727. }
  728. return false;
  729. }
  730.  
  731. private static class PalStrat extends Strat {
  732. PalStrat(String name, int cost, Integer[] addr, Integer[] input, Integer[] advanceFrames) {
  733. super(name, cost, addr, input, advanceFrames);
  734. }
  735.  
  736. @Override
  737. public void execute(GBWrapper wrap) {
  738. for (int i = 0; i < addr.length; i++) {
  739. wrap.advanceWithJoypadToAddress(input[i], addr[i]);
  740. wrap.advanceFrame(input[i]);
  741. for (int j = 0; j < advanceFrames[i]; j++) {
  742. wrap.advanceFrame();
  743. }
  744. }
  745. }
  746. }
  747.  
  748. private static Strat nido0 = new Strat("_hop0", 0, new Integer[] { RedBlueAddr.joypadAddr }, new Integer[] { UP | SELECT | B }, new Integer[] { 1 });
  749. private static Strat nido1 = new Strat("_hop1", 131, new Integer[] { RedBlueAddr.animateNidorinoAddr, RedBlueAddr.checkInterruptAddr, RedBlueAddr.joypadAddr }, new Integer[] { NO_INPUT, NO_INPUT, A }, new Integer[] { 0, 0, 1 });
  750. private static Strat nido2 = new Strat("_hop2", 190, new Integer[] { RedBlueAddr.animateNidorinoAddr, RedBlueAddr.checkInterruptAddr, RedBlueAddr.animateNidorinoAddr, RedBlueAddr.checkInterruptAddr, RedBlueAddr.joypadAddr }, new Integer[] { NO_INPUT, NO_INPUT, NO_INPUT, NO_INPUT, A }, new Integer[] { 0, 0, 0, 0, 1 });
  751. private static Strat nido3 = new Strat("_hop3", 298, new Integer[] { RedBlueAddr.animateNidorinoAddr, RedBlueAddr.checkInterruptAddr, RedBlueAddr.animateNidorinoAddr, RedBlueAddr.checkInterruptAddr, RedBlueAddr.animateNidorinoAddr, RedBlueAddr.checkInterruptAddr, RedBlueAddr.joypadAddr }, new Integer[] { NO_INPUT, NO_INPUT, NO_INPUT, NO_INPUT, NO_INPUT, NO_INPUT, A }, new Integer[] { 0, 0, 0, 0, 0, 0, 1 });
  752. private static Strat nido4 = new Strat("_hop4", 447, new Integer[] { RedBlueAddr.animateNidorinoAddr, RedBlueAddr.checkInterruptAddr, RedBlueAddr.animateNidorinoAddr, RedBlueAddr.checkInterruptAddr, RedBlueAddr.animateNidorinoAddr, RedBlueAddr.checkInterruptAddr, RedBlueAddr.animateNidorinoAddr, RedBlueAddr.checkInterruptAddr, RedBlueAddr.joypadAddr }, new Integer[] { NO_INPUT, NO_INPUT, NO_INPUT, NO_INPUT, NO_INPUT, NO_INPUT, NO_INPUT, NO_INPUT, A }, new Integer[] { 0, 0, 0, 0, 0, 0, 0, 0, 1 });
  753. private static Strat nido5 = new Strat("_hop5", 536, new Integer[] { RedBlueAddr.displayTitleScreenAddr }, new Integer[] { NO_INPUT }, new Integer[] { 0 });
  754.  
  755. private static Strat cont = new Strat("", 0, new Integer[] { RedBlueAddr.joypadAddr }, new Integer[] { A }, new Integer[] { 1 });
  756.  
  757. private static Strat backout = new Strat("_backout", 97, new Integer[] { RedBlueAddr.joypadAddr }, new Integer[] { B }, new Integer[] { 1 });
  758. private static Strat gfSkip = new Strat("_gfskip", 0, new Integer[] { RedBlueAddr.joypadAddr }, new Integer[] { UP | SELECT | B }, new Integer[] { 1 });
  759. private static Strat gfWait = new Strat("_gfwait", 253, new Integer[] { RedBlueAddr.delayAtEndOfShootingStarAddr }, new Integer[] { NO_INPUT }, new Integer[] { 0 });
  760. private static Strat title0 = new Strat("", 0, new Integer[] { RedBlueAddr.joypadAddr }, new Integer[] { START }, new Integer[] { 1 });
  761. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement