Guest User

DW3 metal babble encounter search

a guest
Feb 1st, 2016
168
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 24.13 KB | None | 0 0
  1. #include <assert.h>
  2. #include <stdint.h>
  3. #include <stdio.h>
  4. #define random __stdlib_random
  5. #include <stdlib.h>
  6. #undef random
  7. #include <string.h>
  8.  
  9. #define lenof(array)  ((int)(sizeof(array) / sizeof(*array)))
  10. #define UNUSED  __attribute__((unused))
  11.  
  12. //#define DEBUG
  13. #define VDEBUG
  14. #ifdef DEBUG
  15.     #define dprintf printf
  16.     #ifdef VDEBUG
  17.         #define ddprintf printf
  18.     #else
  19.         #define dprintf(...) /*nothing*/
  20.     #endif
  21. #else
  22.     #define dprintf(...) /*nothing*/
  23.     #define ddprintf(...) /*nothing*/
  24. #endif
  25.  
  26. /*************************************************************************/
  27. /******************************* Constants *******************************/
  28. /*************************************************************************/
  29.  
  30. #define SAVE_SIZE  0x313
  31.  
  32. static const struct {uint8_t code; char text;} textmap[] = {
  33.     {0x00, '\0'},
  34.     {0x0B, 'a'},
  35.     {0x0C, 'b'},
  36.     {0x0D, 'c'},
  37.     {0x0E, 'd'},
  38.     {0x0F, 'e'},
  39.     {0x10, 'f'},
  40.     {0x11, 'g'},
  41.     {0x12, 'h'},
  42.     {0x13, 'i'},
  43.     {0x14, 'j'},
  44.     {0x15, 'k'},
  45.     {0x16, 'l'},
  46.     {0x17, 'm'},
  47.     {0x18, 'n'},
  48.     {0x19, 'o'},
  49.     {0x1A, 'p'},
  50.     {0x1B, 'q'},
  51.     {0x1C, 'r'},
  52.     {0x1D, 's'},
  53.     {0x1E, 't'},
  54.     {0x1F, 'u'},
  55.     {0x20, 'v'},
  56.     {0x21, 'w'},
  57.     {0x22, 'x'},
  58.     {0x23, 'y'},
  59.     {0x24, 'z'},
  60.     {0x25, 'A'},
  61.     {0x26, 'B'},
  62.     {0x27, 'C'},
  63.     {0x28, 'D'},
  64.     {0x29, 'E'},
  65.     {0x2A, 'F'},
  66.     {0x2B, 'G'},
  67.     {0x2C, 'H'},
  68.     {0x2D, 'I'},
  69.     {0x2E, 'J'},
  70.     {0x2F, 'K'},
  71.     {0x30, 'L'},
  72.     {0x31, 'M'},
  73.     {0x32, 'N'},
  74.     {0x33, 'O'},
  75.     {0x34, 'P'},
  76.     {0x35, 'Q'},
  77.     {0x36, 'R'},
  78.     {0x37, 'S'},
  79.     {0x38, 'T'},
  80.     {0x39, 'U'},
  81.     {0x3A, 'V'},
  82.     {0x3B, 'W'},
  83.     {0x3C, 'X'},
  84.     {0x3D, 'Y'},
  85.     {0x3E, 'Z'},
  86.     {0x50, ' '},
  87.     {0x68, '\''},
  88.     {0x6A, ','},
  89.     {0x6B, '-'},
  90.     {0x6C, '.'},
  91.     {0x6D, '('},
  92.     {0x6E, ')'},
  93.     {0x6F, '?'},
  94.     {0x70, '!'},
  95. };
  96. static uint8_t char_to_code[256];
  97.  
  98. static const char * const initial_names[3][4] = {
  99.     {"Brindar", "Ragnar", "Adan", "Glennard"},
  100.     {"Theron", "Elucidus", "Harley", "Mathias"},
  101.     {"Sartris", "Petrus", "Hiram", "Viron"},
  102. };
  103. static const uint8_t initial_class[3] = {4, 1, 2};
  104.  
  105. static const struct {
  106.     uint16_t offset;
  107.     uint8_t class_stats[8];
  108.     uint8_t initial_stats[5];
  109. } class_stats[5] = {
  110.     {0x0C, {7, 1, 3, 0, 7, 4,15, 3}, {7, 1, 3, 0, 9}},
  111.     {0x18, {5, 4, 4, 0, 2, 1, 8, 2}, {5, 4, 4, 0, 2}},
  112.     {0x3C, {7, 2, 3, 0, 7, 4, 5, 4}, {7, 2, 3, 0, 7}},
  113.     {0x24, {6, 8, 7, 0, 1, 5, 4, 1}, {6, 9, 8, 0, 1}},
  114.     {0x30, {4, 2, 2, 0, 2, 3, 1, 8}, {4, 2, 3, 0, 2}},
  115. };
  116.  
  117. static const uint16_t rate_table[] = {
  118.     0x0010, 0x0040, 0x0080, 0x0100, 0x0200, 0x0400, 0x0800, 0x1000};
  119. static const struct {uint8_t base, range;} count_table[] = {
  120.     {8, 1}, {4, 2}, {2, 2}, {3, 5}};
  121. static const struct {
  122.     uint8_t chance[13];
  123.     uint8_t add_group_chance[2];
  124.     uint8_t count_index[5];
  125. } chance_table[] = {
  126.     {{28,56,70,84,112,132,146,160,174,188,216,227,241}, { 0,  0}, {2,1,3,2,2}},
  127.     {{20,40,55,70,100,120,140,150,165,175,215,226,241}, {64,128}, {1,0,3,2,1}},
  128.     {{18,50,63,68,103,113,132,157,176,191,221,226,241}, {64, 16}, {0,1,3,2,2}},
  129.     {{10,20,38,48,118,118,128,138,156,166,236,246,255}, {64,  0}, {3,0,1,2,1}},
  130. };
  131. UNUSED static const char * const preemptive_names[] = {
  132.     "Normal", "Preempt+", "Back+", "None"};
  133. typedef struct EncounterInfo {
  134.     uint8_t rate_index;
  135.     uint8_t chance_index;
  136.     uint8_t preemptive_index;
  137.     uint8_t enemies[14];
  138. } EncounterInfo;
  139. // 108 = Metal Babble
  140. static const EncounterInfo rimuldar_encounters = {
  141.     3, 2, 0, {116, 83, 105, 255, 116, 108, 116, 113, 116, 108, 116, 255, 255, 255}};
  142.  
  143. /*************************************************************************/
  144. /****************** Random number generator and helpers ******************/
  145. /*************************************************************************/
  146.  
  147. static int seed = 0x3D27;
  148. static int counter = 1;
  149. static int multi_counter = 0;
  150.  
  151. /*-----------------------------------------------------------------------*/
  152.  
  153. static int random(void)
  154. {
  155.     for (int i = 0; i < 2; i++) {
  156.         for (int y = 8; y > 0; y--) {
  157.             int a = (seed >> 15) ^ 1;
  158.             seed = (seed << 1) & 0xFFFF;
  159.             if (a) {
  160.                 seed ^= 0x1021;
  161.             }
  162.         }
  163.     }
  164.     counter = (counter + 1) & 0xFF;
  165.     return (seed + counter) & 0xFF;
  166. }
  167.  
  168. /*-----------------------------------------------------------------------*/
  169.  
  170. /* Returns values from 0 through range-1 inclusive. */
  171. static int random_range(int range)
  172. {
  173.     int mask = 0;
  174.     for (int temp = range; temp != 0; temp >>= 1) {
  175.         mask = (mask << 1) | 1;
  176.     }
  177.     for (;;) {
  178.         const int value = random() & mask;
  179.         if (value < range) {
  180.             return value;
  181.         }
  182.     }
  183. }
  184.  
  185. /*-----------------------------------------------------------------------*/
  186.  
  187. static int multi_random(void)
  188. {
  189.     for (int i = 0; i < multi_counter + 1; i++) {
  190.         random();
  191.     }
  192.     return random();
  193. }
  194.  
  195. /*-----------------------------------------------------------------------*/
  196.  
  197. static int multi_random_range(int range)
  198. {
  199.     return (multi_random() * range) >> 8;
  200. }
  201.  
  202. /*-----------------------------------------------------------------------*/
  203.  
  204. static int choose_encounter(const EncounterInfo *info, int base_rate,
  205.                             int overworld, int day,
  206.                             int enemies_ret[4], int counts_ret[4])
  207. {
  208.     int rate = rate_table[info->rate_index];
  209.     if (rate < 0x100) {
  210.         if (random() >= rate) {
  211.             return 0;
  212.         }
  213.         rate = 0x100;
  214.     }
  215.     rate = (rate >> 8) * base_rate;
  216.     if (rate > 100) {
  217.         rate = 100;
  218.     }
  219.     if (random() >= rate) {
  220.         return 0;
  221.     }
  222.  
  223.     int group, enemy;
  224.     for (int try = 100; ; try--) {
  225.         if (try == 1) {
  226.             return 0;
  227.         }
  228.         const int encount_selector = random();
  229.         int i;
  230.         for (i = 0; i < 13; i++) {
  231.             if (encount_selector < chance_table[info->chance_index].chance[i]) {
  232.                 break;
  233.             }
  234.         }
  235.         group = i;
  236.         enemy = info->enemies[i];
  237.         if (overworld) {
  238.             if (day) {
  239.                 if (group == 4 || group == 10 || group == 13) {
  240.                     continue;
  241.                 }
  242.             } else {
  243.                 if (group == 0 || group == 6) {
  244.                     continue;
  245.                 }
  246.             }
  247.         }
  248.         if (enemy != 255) {
  249.             break;
  250.         }
  251.     }
  252.  
  253.     for (int i = 0; i < 4; i++) {
  254.         enemies_ret[i] = 255;
  255.         counts_ret[i] = 0;
  256.     }
  257.  
  258.     if (group < 5) {
  259.         enemies_ret[0] = enemy;
  260.         int seen[6] = {0,0,0,0,0,0};
  261.         seen[group] = 1;
  262.         int encounter_5_group = -1;
  263.         int added_groups = 0;
  264.         for (int try = 20; try > 1; try--) {
  265.             const int extra_group = random_range(6);
  266.             if (overworld) {
  267.                 if ((day && extra_group == 4) || (!day && extra_group == 0)) {
  268.                     continue;
  269.                 }
  270.             }
  271.             if (seen[extra_group] || info->enemies[extra_group] == 255) {
  272.                 continue;
  273.             }
  274.             enemies_ret[1 + added_groups] = info->enemies[extra_group];
  275.             seen[extra_group] = 1;
  276.             if (extra_group == 5) {
  277.                 encounter_5_group = 1 + added_groups;
  278.             }
  279.             const int more_groups_chance =
  280.                 chance_table[info->chance_index].add_group_chance[added_groups];
  281.             added_groups++;
  282.             if (random() >= more_groups_chance) {
  283.                 break;
  284.             }
  285.             if (added_groups == 2) {
  286.                 added_groups = 3;  // Replicate off-by-one bug.
  287.                 break;
  288.             }
  289.         }
  290.         for (int i = 0; i < 1 + added_groups; i++) {
  291.             counts_ret[i] = 1;
  292.         }
  293.         int try = 0;
  294.         while (random_range(3) != 0) {
  295.             if (++try > 65536) {
  296.                 dprintf("Detected deadlock in encounter generation\n");
  297.                 break;
  298.             }
  299.             const int inc_group = random_range(1 + added_groups);
  300.             if (inc_group != encounter_5_group) {
  301.                 counts_ret[inc_group]++;
  302.             }
  303.         }
  304.  
  305.     } else if (group == 5) {
  306.         enemies_ret[0] = enemy;
  307.         counts_ret[0] = 1;
  308.         for (int try = 20; try > 1; try--) {
  309.             const int extra_group = random_range(5);
  310.             if (overworld) {
  311.                 if ((day && extra_group == 4) || (!day && extra_group == 0)) {
  312.                     continue;
  313.                 }
  314.             }
  315.             if (info->enemies[extra_group] == 255) {
  316.                 continue;
  317.             }
  318.             enemies_ret[1] = info->enemies[extra_group];
  319.             counts_ret[1] = 8;
  320.             break;
  321.         }
  322.  
  323.     } else if (group < 11) {
  324.         const int range_index =
  325.             chance_table[info->chance_index].count_index[group - 6];
  326.         enemies_ret[0] = enemy;
  327.         counts_ret[0] = (count_table[range_index].base
  328.                          + random_range(count_table[range_index].range));
  329.  
  330.     } else if (group == 11) {
  331.         enemies_ret[0] = enemy;
  332.         counts_ret[0] = 1;
  333.  
  334.     } else {  // 12 or 13
  335.         assert(!"not implemented");
  336.     }
  337.  
  338.     ddprintf("encounter:");
  339.     for (int i = 0; i < 4; i++) {
  340.         if (enemies_ret[i] != 255) {
  341.             ddprintf(" %dx%d", enemies_ret[i], counts_ret[i]);
  342.         }
  343.     }
  344.     ddprintf("\n");
  345.     return 1;
  346. }
  347.  
  348. /*************************************************************************/
  349. /********************** Save file utility routines ***********************/
  350. /*************************************************************************/
  351.  
  352. static int checksum(const uint8_t *data, int size)
  353. {
  354.     int sum = 0x3A3A;
  355.     for (int i = 0; i < size; i++) {
  356.         int byte = data[i];
  357.         for (int y = 8; y > 0; y--) {
  358.             int a = (sum >> 8) ^ byte;
  359.             sum = (sum << 1) & 0xFFFF;
  360.             byte = (byte << 1) & 0xFF;
  361.             if (a & 0x80) {
  362.                 sum ^= 0x1021;
  363.             }
  364.         }
  365.     }
  366.     return sum;
  367. }
  368.  
  369. /*-----------------------------------------------------------------------*/
  370.  
  371. static void set_name(uint8_t *save, int slot, const char *name)
  372. {
  373.     for (int i = 0; name[i]; i++) {
  374.         const unsigned char ch = name[i];
  375.         const int code = char_to_code[ch];
  376.         if (!code) {
  377.             fprintf(stderr, "No code for character 0x%02X '%c'\n", ch, ch);
  378.             exit(1);
  379.         }
  380.         save[0x114 + slot*8 + i] = code;
  381.     }
  382. }
  383.  
  384. /*-----------------------------------------------------------------------*/
  385.  
  386. static void add_character(uint8_t *save, int is_initial, int slot,
  387.                           const char *name, int class, int sex)
  388. {
  389.     int filled_slots = save[0x237] | save[0x238]<<8;
  390.     filled_slots |= 1 << slot;
  391.     save[0x237] = filled_slots & 0xFF;
  392.     save[0x238] = filled_slots >> 8;
  393.  
  394.     set_name(save, slot, name);
  395.     save[0x0 + slot] = 1;  // Level
  396.     save[0x48 + slot] = class | sex<<3;
  397.     save[0xB4 + slot*2] = 0x80;  // Condition (1st byte)
  398.     save[0xB5 + slot*2] = 0x80;  // Condition (2st byte)
  399.     save[0xF0 + slot*3] = 1;  // Return flag for Aliahan
  400.     for (int i = 0; i < 5; i++) {
  401.         const int offset = class_stats[i].offset;
  402.         const int stat = is_initial ? class_stats[i].initial_stats[class]
  403.                                     : class_stats[i].class_stats[class];
  404.         save[offset + slot] = stat;
  405.     }
  406.  
  407.     if (is_initial) {
  408.         for (int i = 4; i >= 0; i--) {
  409.             const int offset = class_stats[i].offset;
  410.             save[offset + slot] += random() & 1;
  411.         }
  412.     } else {
  413.         int inc_count = multi_random_range(5) + 2;
  414.         for (int i = 0; i < inc_count; i++) {
  415.             const int index = multi_random_range(5);
  416.             const int offset = class_stats[index].offset;
  417.             save[offset + slot] += 1;
  418.         }
  419.     }
  420.  
  421.     const int vitality = save[0x3C + slot];
  422.     const int hp = (vitality*3/2) + 5;
  423.     save[0x54 + slot*2] = hp & 0xFF;
  424.     save[0x55 + slot*2] = hp >> 8;
  425.     save[0x6C + slot*2] = hp & 0xFF;
  426.     save[0x6D + slot*2] = hp >> 8;
  427.     if (class < 4) {
  428.         const int intelligence = save[0x24 + slot];
  429.         const int mp = intelligence;
  430.         save[0x84 + slot*2] = mp & 0xFF;
  431.         save[0x85 + slot*2] = mp >> 8;
  432.         save[0x9C + slot*2] = mp & 0xFF;
  433.         save[0x9D + slot*2] = mp >> 8;
  434.     }
  435.  
  436.     const int armor = class==2 ? 0xB0 : class==4 ? 0xA2 : 0xA0;
  437.     const int weapon = class==1 ? 0x80 : 0x81;
  438.     save[0x174 + slot*8] = weapon;
  439.     save[0x175 + slot*8] = armor;
  440.     // Replicate the off-by-one error.
  441.     memset(&save[0x176 + slot*8], 0xFF, 7);
  442.  
  443.     // Initial spells.
  444.     if (class == 1) {
  445.         save[0x1D4 + slot*8] = 1;
  446.     } else if (class == 2) {
  447.         save[0x1D8 + slot*8] = 2;
  448.         save[0x1DB + slot*8] = 1;
  449.     }
  450. }
  451.  
  452. /*-----------------------------------------------------------------------*/
  453.  
  454. static void gen_save(uint8_t *save, int file, const char *name, int sex,
  455.                      int speed)
  456. {
  457.     memset(save, 0, SAVE_SIZE);
  458.     memset(&save[0x249], 0xFF, 128);
  459.     save[0x312] = file;
  460.  
  461.     add_character(save, 1, 0, name, 0, sex);
  462.     seed = checksum(save, SAVE_SIZE);
  463.     // Fix hero's equipment (done after the checksum).
  464.     save[0x174] = 0x82;
  465.     save[0x175] = 0xA2;
  466.  
  467.     for (int i = 0; i < 3; i++) {
  468.         const int name_index = random() & 3;
  469.         const int slot = i + 1;
  470.         const char *name = initial_names[i][name_index];
  471.         const int class = initial_class[i];
  472.         add_character(save, 1, slot, name, class, 0);
  473.         seed = checksum(save, SAVE_SIZE);
  474.     }
  475.  
  476.     memset(&save[0x23A], 0xFF, 3);
  477.     save[0x311] = speed;
  478. }
  479.  
  480. /*************************************************************************/
  481. /************************** State test routines **************************/
  482. /*************************************************************************/
  483.  
  484. int test_battle(int num_enemies, const char **info_ret)
  485. {
  486.     enum {ATTACK, PARRY, HEAL, FIREBAL, FLEE};
  487.     static const int party_actions[4][3] = {{ATTACK, PARRY},
  488.                                             {ATTACK, HEAL, PARRY},
  489.                                             {ATTACK, HEAL, PARRY},
  490.                                             {ATTACK, PARRY}};
  491.     static const int enemy_actions[] = {FLEE, ATTACK, FLEE, FIREBAL,
  492.                                         FLEE, FLEE, FIREBAL, FLEE};
  493.  
  494.     UNUSED int enemy_hp[3];
  495.     for (int i = 0; i < num_enemies; i++) {
  496.         enemy_hp[i] = 6 - multi_random_range(2);
  497.     }
  498.     for (int i = 0; i < num_enemies; i++) {
  499.         (void) multi_random();  // Initial focus target
  500.     }
  501.     if (random() < 8) {
  502.         dprintf("BAD: back attack");
  503.         return 0;
  504.     }
  505.     if (random() >= 8) {
  506.         dprintf("BAD: not preemptive attack");
  507.         return 0;
  508.     }
  509.  
  510.     const int agility[4] = {5, 5, 5, 6};
  511.  
  512.     int turn_speed[4];
  513.     for (int i = 0; i < 4; i++) {
  514.         const int agility_4 = agility[i] / 4;
  515.         turn_speed[i] = agility_4 + multi_random_range(agility[i] - agility_4);
  516.     }
  517.     for (int i = 4; i < 12; i++) {
  518.         (void) multi_random();  // Enemy turn order
  519.     }
  520.     int turn_order[4];
  521.     for (int i = 0; i < 4; i++) {
  522.         int best = 0;
  523.         for (int j = 1; j < 4; j++) {
  524.             if (turn_speed[j] >= turn_speed[best]) {
  525.                 best = j;
  526.             }
  527.         }
  528.         turn_order[i] = best;
  529.         turn_speed[best] = -1;
  530.     }
  531.  
  532.     multi_counter = random() & 15;
  533.  
  534.     for (int i = 0; i < num_enemies; i++) {
  535.         (void) multi_random();  // Enemy action
  536.         (void) multi_random();  // Enemy target
  537.     }
  538.  
  539.     int best_kills = 0;
  540.     int best_act[4];
  541.     int best_multi;
  542.     int saved_seed = seed;
  543.     int saved_counter = counter;
  544.     int saved_multi = multi_counter;
  545.     for (int try = 0; try < 2*3*3*2; try++) {
  546.         seed = saved_seed;
  547.         counter = saved_counter;
  548.         multi_counter = saved_multi;
  549.  
  550.         int act[4];
  551.         int temp = try;
  552.         act[3] = party_actions[3][temp%2];
  553.         temp /= 2;
  554.         act[2] = party_actions[2][temp%3];
  555.         temp /= 3;
  556.         act[1] = party_actions[1][temp%3];
  557.         temp /= 3;
  558.         act[0] = party_actions[0][temp%2];
  559.  
  560.         int kills = 0;
  561.         for (int i = 0; i < 4 && kills < num_enemies; i++) {
  562.             const int ch = turn_order[i];
  563.             if (act[ch] == ATTACK) {
  564.                 for (int enemy = 0; enemy < num_enemies - kills; enemy++) {
  565.                     int damage = multi_random() & 1;
  566.                     const int intelligence = 0;  // don't care
  567.                     damage += (damage * multi_random_range(255-intelligence) / 4) >> 8;
  568.                 }
  569.                 const int target = num_enemies - kills - 1;
  570.                 int is_kill = 0;
  571.                 if (ch == 3) {
  572.                     is_kill = (multi_random() < 32);
  573.                 } else {
  574.                     const int is_crit = (multi_random() < 4);
  575.                     if (is_crit) {
  576.                         static const int attack[3] = {128, 10, 11};
  577.                         const int damage = attack[ch] * (54 + multi_random_range(11)) / 64 + 1;
  578.                         // Don't worry about multiple hits on a target for now
  579.                         is_kill = (damage >= enemy_hp[target]);
  580.                     }
  581.                 }
  582.                 if (is_kill) {
  583.                     ddprintf("try %d: char %d kills\n", try, ch);
  584.                 }
  585.                 kills += is_kill;
  586.             } else if (act[ch] == HEAL) {
  587.                 (void) multi_random();
  588.             }
  589.         }
  590.  
  591.         if (kills == 0) {
  592.             continue;
  593.         }
  594.  
  595.         if (kills < num_enemies) {
  596.             // Simulate the second turn to get the final battle RNG seed
  597.             // and make sure all remaining enemies flee
  598.             for (int i = 0; i < 12; i++) {
  599.                 (void) multi_random();  // Turn order
  600.             }
  601.             multi_counter = random() & 15;
  602.             int ok = 1;
  603.             for (int i = 0; i < num_enemies - kills; i++) {
  604.                 const int r = multi_random();
  605.                 const int enemy_action = enemy_actions[r/32];
  606.                 (void) multi_random();  // Enemy target
  607.                 if (enemy_action != FLEE) {
  608.                     ok = 0;
  609.                     break;
  610.                 }
  611.             }
  612.             if (!ok) {
  613.                 continue;
  614.             }
  615.         }
  616.  
  617.         if (kills > best_kills) {
  618.             best_kills = kills;
  619.             memcpy(best_act, act, sizeof(act));
  620.             best_multi = multi_counter;
  621.         }
  622.     }
  623.  
  624.     if (best_kills < 2) {
  625.         dprintf("BAD: not enough kills");
  626.         return 0;
  627.     }
  628.  
  629.     const char * const act_names[] =
  630.         {[ATTACK] = "Attack", [HEAL] = "Heal", [PARRY] = "Parry"};
  631.     static char buf[100];
  632.     snprintf(buf, sizeof(buf), "Seed:$%X Kills:%d/%d Hr:%s P2:%s P1:%s Wz:%s",
  633.              best_multi, best_kills, num_enemies,
  634.              act_names[best_act[0]], act_names[best_act[1]],
  635.              act_names[best_act[2]], act_names[best_act[3]]);
  636.     *info_ret = buf;
  637.     return 1;
  638. }
  639.  
  640. /*-----------------------------------------------------------------------*/
  641.  
  642. int test_seed(int initial_seed, const char **info_ret)
  643. {
  644.     dprintf("Seed: $%04X\n", initial_seed);
  645.  
  646.     // File load -> Rimuldar
  647.     seed = initial_seed;
  648.     counter = 1;
  649.     multi_counter = 0xD;
  650.     random();
  651.     random();
  652.  
  653.     // Check up to 256 steps ahead for the desired encounter
  654.     const int start_seed = seed;
  655.     const int start_counter = counter;
  656.     for (int steps = 1; steps <= 256; steps++) {
  657.         seed = start_seed;
  658.         counter = start_counter;
  659.  
  660.         for (int i = 0; i < steps - 1; i++) {
  661.             (void) random();
  662.         }
  663.         int groups[4], counts[4];
  664.         if (!choose_encounter(&rimuldar_encounters, 10, 1, 0, groups, counts)) {
  665.             continue;
  666.         }
  667.         if (groups[0] != 108 || counts[0] < 2
  668.          || groups[1] != 255 || groups[2] != 255 || groups[3] != 255) {
  669.             continue;
  670.         }
  671.         ddprintf("steps=%d: battle entry %04X %02X\n", steps, seed, counter);
  672.         if (test_battle(counts[0], info_ret)) {
  673.             dprintf("ok (%d steps, %s)\n", steps, *info_ret);
  674.             return steps;
  675.         }
  676.     }
  677.  
  678.     dprintf("BAD (no encounter found)");
  679.     return 0;
  680. }
  681.  
  682. /*-----------------------------------------------------------------------*/
  683.  
  684. int test_file(const char *name, int sex, int speed, int target_seed)
  685. {
  686.     const int file = 2;
  687.  
  688.     dprintf("Hr: %s/%s  Speed: %d  ", name, sex ? "F" : "M", speed + 1);
  689.     fflush(stdout);
  690.  
  691.     uint8_t save[SAVE_SIZE];
  692.  
  693.     seed = 0x3D27;
  694.     counter = 1;
  695.     gen_save(save, file, name, sex, speed);
  696.     seed = checksum(save, SAVE_SIZE);
  697.     ddprintf("Checksum: %04X\n", seed);
  698.     assert(counter == 0x18);
  699.  
  700.     return seed == target_seed;
  701. }
  702.  
  703. /*************************************************************************/
  704. /************************** Program entry point **************************/
  705. /*************************************************************************/
  706.  
  707. int main(int argc, char **argv)
  708. {
  709.     for (int i = 0; i < lenof(textmap); i++) {
  710.         if (textmap[i].text) {
  711.             char_to_code[(unsigned char)textmap[i].text] = textmap[i].code;
  712.         }
  713.     }
  714.  
  715.     int seeds[4][2];
  716.     int num_seeds = 0;
  717.     for (int s = 0; s < 0x10000; s++) {
  718.         const char *info;
  719.         const int steps = test_seed(s, &info);
  720.         if (steps) {
  721.             printf("Seed: $%04X (%d steps, %s)\n", s, steps, info);
  722.             if (num_seeds == lenof(seeds)) {
  723.                 int worst = 0;
  724.                 for (int i = 1; i < lenof(seeds); i++) {
  725.                     if (seeds[i][1] > seeds[worst][1]) {
  726.                         worst = i;
  727.                     }
  728.                 }
  729.                 if (steps < seeds[worst][1]) {
  730.                     seeds[worst][0] = s;
  731.                     seeds[worst][1] = steps;
  732.                 }
  733.             } else {
  734.                 seeds[num_seeds][0] = s;
  735.                 seeds[num_seeds][1] = steps;
  736.                 num_seeds++;
  737.             }
  738. #ifdef DEBUG
  739.             return 0;
  740. #endif
  741.         }
  742.     }
  743.     if (!num_seeds) {
  744.         fprintf(stderr, "Error: No usable seed found\n");
  745.         return 1;
  746.     }
  747.  
  748.     char name[8+1];
  749.     memset(name, 0, sizeof(name));
  750.     for (int i3 = 0; i3 < lenof(textmap); i3++) {
  751.         if (textmap[i3].text == ' ') continue;
  752.         name[3] = textmap[i3].text;
  753.         for (int i2 = 0; i2 < lenof(textmap); i2++) {
  754.             if (!i2 && i3) continue;
  755.             if (textmap[i2].text == ' ') continue;
  756.             name[2] = textmap[i2].text;
  757.             for (int i1 = 0; i1 < lenof(textmap); i1++) {
  758.                 if (!i1 && i2) continue;
  759.                 if (textmap[i1].text == ' ') continue;
  760.                 name[1] = textmap[i1].text;
  761.                 fprintf(stderr, "Hr: a%s\r", &name[1]);
  762.                 for (int i0 = 1; i0 < lenof(textmap); i0++) {
  763.                     if (textmap[i0].text == ' ') continue;
  764.                     name[0] = textmap[i0].text;
  765.                     for (int sex = 0; sex < 2; sex++) {
  766.                         for (int speed = 0; speed < 8; speed++) {
  767.                             for (int si = 0; si < num_seeds; si++) {
  768.                                 if (test_file(name, sex, speed, seeds[si][0])) {
  769.                                     printf("Hr: %s/%s  Speed: %d  Seed: $%04X  Steps: %d\n",
  770.                                            name, sex ? "F" : "M", speed + 1,
  771.                                            seeds[si][0], seeds[si][1]);
  772.                                 }
  773. #ifdef DEBUG
  774.                                 return 0;
  775. #endif
  776.                             }
  777.                         }
  778.                     }
  779.                 }
  780.             }
  781.         }
  782.     }
  783.     return 0;
  784. }
  785.  
  786. /*************************************************************************/
  787. /*************************************************************************/
Add Comment
Please, Sign In to add comment