found bug in Wizardry exp points calculation

This commit is contained in:
Denis Molony 2022-03-29 18:00:32 +10:00
parent 91846d8563
commit ff7c6fd126
4 changed files with 354 additions and 21 deletions

View File

@ -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<String> 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));

View File

@ -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)));
}
}
}
// ---------------------------------------------------------------------------------//

View File

@ -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<Dice> 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<Reward> rewards, List<Monster> 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 ();
}

View File

@ -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 ();
}
}