From ff7c6fd12622872ebcdbb049687a1eb70f7b96d7 Mon Sep 17 00:00:00 2001 From: Denis Molony Date: Tue, 29 Mar 2022 18:00:32 +1000 Subject: [PATCH] found bug in Wizardry exp points calculation --- .../diskbrowser/wizardry/MazeGridV5.java | 13 +- .../diskbrowser/wizardry/MazeLevel.java | 23 ++ .../diskbrowser/wizardry/Monster.java | 44 ++- .../diskbrowser/wizardry/WizLong.java | 295 ++++++++++++++++++ 4 files changed, 354 insertions(+), 21 deletions(-) create mode 100644 src/com/bytezone/diskbrowser/wizardry/WizLong.java diff --git a/src/com/bytezone/diskbrowser/wizardry/MazeGridV5.java b/src/com/bytezone/diskbrowser/wizardry/MazeGridV5.java index 9b5cc9e..0334f36 100644 --- a/src/com/bytezone/diskbrowser/wizardry/MazeGridV5.java +++ b/src/com/bytezone/diskbrowser/wizardry/MazeGridV5.java @@ -38,8 +38,7 @@ class MazeGridV5 extends AbstractFile for (int col = 0; col < 8; col++) grid[row][col] = getLayout (i, row, col); - MazeGrid mazeGrid = - new MazeGrid (grid, buffer[528 + i] & 0xFF, buffer[512 + i] & 0xFF); + MazeGrid mazeGrid = new MazeGrid (grid, buffer[528 + i] & 0xFF, buffer[512 + i] & 0xFF); grids.add (mazeGrid); minX = Math.min (minX, mazeGrid.xOffset); @@ -60,11 +59,10 @@ class MazeGridV5 extends AbstractFile int gridWidth = (maxX - minX + 8) * cellSize.width; int gridHeight = (maxY - minY + 7) * cellSize.height; - image = new BufferedImage (gridWidth + 1, gridHeight + fudge, - BufferedImage.TYPE_USHORT_555_RGB); + image = + new BufferedImage (gridWidth + 1, gridHeight + fudge, BufferedImage.TYPE_USHORT_555_RGB); Graphics2D g = image.createGraphics (); - g.setRenderingHint (RenderingHints.KEY_ANTIALIASING, - RenderingHints.VALUE_ANTIALIAS_ON); + g.setRenderingHint (RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.setColor (Color.LIGHT_GRAY); g.fillRect (0, 0, gridWidth + 1, gridHeight + fudge); @@ -183,8 +181,7 @@ class MazeGridV5 extends AbstractFile { List messages = messageBlock.getMessageLines (msg); if (messages.size () > 0) - text.append ( - String.format ("%n%4d %02X %04X %s%n", i, i, msg, messages.get (0))); + text.append (String.format ("%n%4d %02X %04X %s%n", i, i, msg, messages.get (0))); else text.append (String.format ("Message not found: %04X%n", msg)); diff --git a/src/com/bytezone/diskbrowser/wizardry/MazeLevel.java b/src/com/bytezone/diskbrowser/wizardry/MazeLevel.java index 81c5236..57482ca 100755 --- a/src/com/bytezone/diskbrowser/wizardry/MazeLevel.java +++ b/src/com/bytezone/diskbrowser/wizardry/MazeLevel.java @@ -247,6 +247,7 @@ public class MazeLevel extends AbstractFile // ---------------------------------------------------------------------------------// { text.append ("\n\n"); + int savePtr = ptr; text.append (String.format ("MINENEMY %04X %04X %04X%n", Utility.getShort (buffer, ptr), Utility.getShort (buffer, ptr + 10), Utility.getShort (buffer, ptr + 20))); @@ -262,6 +263,28 @@ public class MazeLevel extends AbstractFile ptr += 2; text.append (String.format ("PERCWORS %04X %04X %04X%n", Utility.getShort (buffer, ptr), Utility.getShort (buffer, ptr + 10), Utility.getShort (buffer, ptr + 20))); + + ptr = savePtr; + for (int i = 0; i < 3; i++) + { + String pct = i == 0 ? "75" : i == 1 ? "18.75" : "6.25"; + text.append (String.format ("%nEnemy #%d %s%%%n%n", (i + 1), pct)); + int minenemy = Utility.getShort (buffer, ptr); + int multwors = Utility.getShort (buffer, ptr + 2); + int worse01 = Utility.getShort (buffer, ptr + 4); + int range0n = Utility.getShort (buffer, ptr + 6); + int percwors = Utility.getShort (buffer, ptr + 8); + ptr += 10; + + int max = multwors * worse01; + + for (int id = minenemy; id < minenemy + range0n + max; id++) + { + if (id == minenemy + range0n) + text.append ("\n"); + text.append (String.format ("%3d %-16s %n", id, monsters.get (id))); + } + } } // ---------------------------------------------------------------------------------// diff --git a/src/com/bytezone/diskbrowser/wizardry/Monster.java b/src/com/bytezone/diskbrowser/wizardry/Monster.java index caddc0e..a404628 100755 --- a/src/com/bytezone/diskbrowser/wizardry/Monster.java +++ b/src/com/bytezone/diskbrowser/wizardry/Monster.java @@ -23,12 +23,14 @@ class Monster extends AbstractFile public final int imageID; int rewardTable1; int rewardTable2; + public final int partnerID; public final int partnerOdds; public final int armourClass; public final int recsn; public final int mageSpellLevel; public final int priestSpellLevel; + int levelDrain; int healPts; int breathe; @@ -40,14 +42,24 @@ class Monster extends AbstractFile List damage = new ArrayList<> (); static int counter = 0; - static boolean debug = true; - static int[] pwr = { 0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 0, 0, 0, 0, 0 }; - static int[] weight1 = { 0, 1, 2, 4, 8, 16, 32, 64, 253, 506, 0 }; - static int[] weight2 = { 0, 60, 120, 180, 300, 540, 1020, 0 }; public static String[] monsterClass = { "Fighter", "Mage", "Priest", "Thief", "Midget", "Giant", "Mythical", "Dragon", "Animal", "Were", "Undead", "Demon", "Insect", "Enchanted" }; + private static int[] experience = { // + 55, 235, 415, 230, 380, 620, 840, 520, 550, 350, // 00-09 + 475, 515, 920, 600, 735, 520, 795, 780, 990, 795, // 10-19 + 1360, 1320, 1275, 680, 960, 600, 755, 1120, 2075, 870, // 20-29 + 960, 600, 1120, 2435, 1080, 2280, 975, 875, 1135, 1200, // 30-39 + 620, 740, 1460, 1245, 960, 1405, 1040, 1220, 1520, 1000, // 40-49 + 960, 2340, 2160, 2395, 790, 1140, 1235, 1790, 1720, 2240, // 50-59 + 1475, 1540, 1720, 1900, 1240, 1220, 1020, 20435, 5100, 3515, // 60-69 + 2115, 2920, 2060, 2140, 1400, 1640, 1280, 4450, 42840, 3300, // 70-79 + 40875, 5000, 3300, 2395, 1935, 1600, 3330, 44090, 40840, 5200, // 80-89 + 4155, 3000, 9200, 3160, 7460, 7320, 15880, 1600, 2200, 1000, // 90-99 + 1900 // 100 + }; + // ---------------------------------------------------------------------------------// Monster (String name, byte[] buffer, List rewards, List monsters) // ---------------------------------------------------------------------------------// @@ -134,8 +146,8 @@ class Monster extends AbstractFile text.append ("\nBreathe ......... " + breathe); text.append ("\nUnaffect ........ " + unaffect); - text.append ("\n\nResistance ...... " + String.format ("%02X", resistance)); - text.append ("\nAbilities ....... " + String.format ("%02X", abilities)); + text.append ("\n\nResistance ...... " + String.format ("%3d %<02X", resistance)); + text.append ("\nAbilities ....... " + String.format ("%3d %<02X", abilities)); text.append (String.format ("%n%nExperience ...... %-,7d", totalExperience)); @@ -157,21 +169,20 @@ class Monster extends AbstractFile // ---------------------------------------------------------------------------------// { int expHitPoints = hitPoints.qty * hitPoints.sides * (breathe == 0 ? 20 : 40); + int expAc = 40 * (11 - armourClass); int expMage = getBonus (35, mageSpellLevel); int expPriest = getBonus (35, priestSpellLevel); int expDrain = getBonus (200, levelDrain); int expHeal = getBonus (90, healPts); - int expAc = 40 * (11 - armourClass); - int expDamage = recsn <= 1 ? 0 : getBonus (30, recsn); int expUnaffect = unaffect == 0 ? 0 : getBonus (40, (unaffect / 10 + 1)); int expFlags1 = getBonus (35, Integer.bitCount (resistance & 0x7E)); int expFlags2 = getBonus (40, Integer.bitCount (abilities & 0x7F)); - return expHitPoints + expMage + expPriest + expDrain + expHeal + expAc + expDamage + expUnaffect + return expHitPoints + expAc + expMage + expPriest + expDrain + expHeal + expDamage + expUnaffect + expFlags1 + expFlags2; } @@ -183,10 +194,13 @@ class Monster extends AbstractFile return 0; int total = base; - for (int i = 1; i < multiplier; i++) - total *= 2; + while (multiplier > 1) + { + multiplier--; + total += total; // double the value + } - return total + total / 10000 * 10000; + return total + total / 10000 * 10000; // mimics the Wizardry bug } // ---------------------------------------------------------------------------------// @@ -231,17 +245,21 @@ class Monster extends AbstractFile // ---------------------------------------------------------------------------------// { StringBuilder line = new StringBuilder (String.format ("%3d %-16s", monsterID, realName)); + int lo = block == 0 ? 64 : block == 1 ? 88 : block == 2 ? 112 : 136; int hi = lo + 24; if (hi > buffer.length) hi = buffer.length; + for (int i = lo; i < hi; i++) line.append (String.format ("%02X ", buffer[i])); + if (block == 3) { int exp = getExperience (); - line.append (String.format (" %,6d", exp)); + line.append (String.format (" %,6d %,6d", exp, exp - experience[monsterID])); } + return line.toString (); } diff --git a/src/com/bytezone/diskbrowser/wizardry/WizLong.java b/src/com/bytezone/diskbrowser/wizardry/WizLong.java new file mode 100644 index 0000000..80d4dfb --- /dev/null +++ b/src/com/bytezone/diskbrowser/wizardry/WizLong.java @@ -0,0 +1,295 @@ +package com.bytezone.diskbrowser.wizardry; + +// -----------------------------------------------------------------------------------// +public class WizLong +// -----------------------------------------------------------------------------------// +{ + private static final int MAX = 10000; + + int high; // 4 digits per component + int mid; + int low; + + // ---------------------------------------------------------------------------------// + public WizLong (int value) + // ---------------------------------------------------------------------------------// + { + assert value >= 0 && value < MAX; + + low = value; + } + + // ---------------------------------------------------------------------------------// + public void addLong (WizLong other) + // ---------------------------------------------------------------------------------// + { + low += other.low; + if (low >= MAX) + { + mid++; + low -= MAX; + } + + mid += other.mid; + if (mid >= MAX) + { + high++; + mid -= MAX; + } + + high += other.high; + if (high >= MAX) + { + high = MAX - 1; + mid = MAX - 1; + low = MAX - 1; + } + } + + // ---------------------------------------------------------------------------------// + public void subLong (WizLong other) + // ---------------------------------------------------------------------------------// + { + low -= other.low; + if (low < 0) + { + mid--; + low += MAX; + } + + mid -= other.mid; + if (mid < 0) + { + high--; + mid += MAX; + } + + high -= other.high; + if (high < 0) + { + high = 0; + mid = 0; + low = 0; + } + } + + // ---------------------------------------------------------------------------------// + public void multLong (int multiplier) + // ---------------------------------------------------------------------------------// + { + BCD bcd = long2bcd (); + + for (int digit = 12; digit >= 1; digit--) + { + bcd.value[digit] *= multiplier; + } + + for (int digit = 12; digit >= 1; digit--) + { + if (bcd.value[digit] > 9) + { + bcd.value[digit - 1] += bcd.value[digit] / 10; + bcd.value[digit] %= 10; + } + } + bcd2long (bcd); + } + + // ---------------------------------------------------------------------------------// + public void divLong (WizLong other) + // ---------------------------------------------------------------------------------// + { + + } + + // ---------------------------------------------------------------------------------// + public BCD long2bcd () + // ---------------------------------------------------------------------------------// + { + BCD bcd = new BCD (); + + bcd.value[0] = 0; + + int2bcd (high, 1, bcd); + int2bcd (mid, 5, bcd); + int2bcd (low, 9, bcd); + + return bcd; + } + + private static void int2bcd (int part, int digit, BCD bcd) + { + bcd.value[digit++] = part / 1000; + part %= 1000; + bcd.value[digit++] = part / 100; + part %= 100; + bcd.value[digit++] = part / 10; + part %= 10; + bcd.value[digit++] = part; + } + + // ---------------------------------------------------------------------------------// + public void bcd2long (BCD other) + // ---------------------------------------------------------------------------------// + { + high = mid = low = 0; + + high = bcd2int (1, other); + mid = bcd2int (5, other); + low = bcd2int (9, other); + } + + private static int bcd2int (int digit, BCD bcd) + { + int val = bcd.value[digit++] * 1000; + val += bcd.value[digit++] * 100; + val += bcd.value[digit++] * 10; + val += bcd.value[digit]; + + return val; + } + + // ---------------------------------------------------------------------------------// + public int testLong (WizLong other) + // ---------------------------------------------------------------------------------// + { + if (high == other.high) + if (mid == other.mid) + if (low == other.low) + return 0; + else + return low > other.low ? 1 : -1; + else + return mid > other.mid ? 1 : -1; + else + return high > other.high ? 1 : -1; + } + + public int value () + { + return high * 10000 * 10000 + mid * 10000 + low; + } + + // ---------------------------------------------------------------------------------// + public void printLong () + // ---------------------------------------------------------------------------------// + { + BCD bcd = long2bcd (); + int digit = 1; + + while (digit < 12 && bcd.value[digit] == 0) + { + System.out.print (' '); + digit++; + } + + while (digit <= 12) + System.out.print (bcd.value[digit++]); + + System.out.println (); + } + + // ---------------------------------------------------------------------------------// + class BCD + // ---------------------------------------------------------------------------------// + { + int[] value = new int[14]; + } + + // ---------------------------------------------------------------------------------// + private static void multAddKX (WizLong killExp, int multiply, int amount) + // ---------------------------------------------------------------------------------// + { + if (multiply == 0) + return; + + WizLong killExpx = new WizLong (amount); + + while (multiply > 1) + { + multiply--; + killExpx.addLong (killExpx); // double the value + } + + killExp.addLong (killExpx); // add to running total + } + + // ---------------------------------------------------------------------------------// + public static void main (String[] args) + // ---------------------------------------------------------------------------------// + { + // Earth Giant + int hpSides = 1; + int hpLevel = 1; + int ac = 9; + int recsn = 2; + int drain = 0; + int mageSpells = 0; + int priestSpells = 0; + int heal = 0; + int breathe = 0; + int unaffect = 85; + int wepsty = 0x40; + int sppc = 0; + + // Werdna + // int hpSides = 10; + // int hpLevel = 10; + // int ac = -7; + // int recsn = 2; + // int drain = 4; + // int mageSpells = 7; + // int priestSpells = 7; + // int heal = 5; + // int breathe = 0; + // int unaffect = 70; + // int wepsty = 0x0E; + // int sppc = 0x0F; + + // Will O Wisp + // int hpSides = 10; + // int hpLevel = 8; + // int ac = -8; + // int recsn = 1; + // int drain = 0; + // int mageSpells = 0; + // int priestSpells = 0; + // int heal = 0; + // int breathe = 0; + // int unaffect = 95; + // int wepsty = 0; + // int sppc = 0; + + WizLong killExp = new WizLong (0); // running total + + WizLong killExpx = new WizLong (hpLevel * hpSides); + killExpx.multLong (breathe == 0 ? 20 : 40); + killExp.addLong (killExpx); + + killExp.printLong (); + + multAddKX (killExp, mageSpells, 35); + multAddKX (killExp, priestSpells, 35); + multAddKX (killExp, drain, 200); + multAddKX (killExp, heal, 90); + killExp.printLong (); + + killExpx = new WizLong (40 * (11 - ac)); + killExp.addLong (killExpx); + killExp.printLong (); + + if (recsn > 1) + multAddKX (killExp, recsn, 30); + killExp.printLong (); + + if (unaffect > 0) + multAddKX (killExp, (unaffect / 10 + 1), 40); + killExp.printLong (); + + multAddKX (killExp, Integer.bitCount (wepsty & 0x7E), 35); // 6 bits + // System.out.println (Integer.bitCount (wepsty)); + multAddKX (killExp, Integer.bitCount (sppc & 0x7F), 40); // 7 bits + + killExp.printLong (); + } +}