diff --git a/src/com/bytezone/diskbrowser/disk/AppleDisk.java b/src/com/bytezone/diskbrowser/disk/AppleDisk.java index 2ce9a60..323696f 100755 --- a/src/com/bytezone/diskbrowser/disk/AppleDisk.java +++ b/src/com/bytezone/diskbrowser/disk/AppleDisk.java @@ -165,7 +165,7 @@ public class AppleDisk implements Disk this.sectorSize = 512; this.trackSize = sectors * sectorSize; } - else if (file.length () == 143360 && tracks == 256 && sectors == 8) // wiz4 + else if (file.length () == 143360 && tracks == 256 && sectors == 8) // wiz4 or wiz5 { this.blocks = tracks * sectors; this.sectorSize = 512; diff --git a/src/com/bytezone/diskbrowser/disk/DiskFactory.java b/src/com/bytezone/diskbrowser/disk/DiskFactory.java index 0b8163b..04aec3a 100755 --- a/src/com/bytezone/diskbrowser/disk/DiskFactory.java +++ b/src/com/bytezone/diskbrowser/disk/DiskFactory.java @@ -861,9 +861,12 @@ public class DiskFactory System.out.println ("checking Wizardry IV or V"); String fileName = file.getAbsolutePath ().toLowerCase (); - int pos = file.getAbsolutePath ().indexOf ('.'); - char c = fileName.charAt (pos - 1); - int requiredDisks = c == '1' ? 6 : c == 'a' ? 10 : 0; + int pos = fileName.lastIndexOf ('.'); + char c = fileName.charAt (pos - 1); // '1' (wiz4) or 'a' (wiz5) + int requiredDisks = c == '1' ? 7 : c == 'a' ? 10 : 0; + + if (debug) + System.out.printf ("Required disks: %d%n", requiredDisks); if (requiredDisks > 0) { @@ -884,7 +887,7 @@ public class DiskFactory } } if (debug) - System.out.println ("Not a Wizardry IV disk"); + System.out.println ("Not a Wizardry IV or V disk"); PascalDisk pascalDisk = new PascalDisk (disk); return pascalDisk; @@ -894,6 +897,9 @@ public class DiskFactory private static boolean collectDataDisks (String fileName, int dotPos, AppleDisk[] disks) // ---------------------------------------------------------------------------------// { + if (debug) + System.out.println ("Collecting Wizardry disks"); + char c = fileName.charAt (dotPos - 1); String suffix = fileName.substring (dotPos + 1); @@ -901,8 +907,11 @@ public class DiskFactory { String old = new String (c + "." + suffix); String rep = new String ((char) (c + i - 1) + "." + suffix); - File f = new File (fileName.replace (old, rep)); + + if (debug) + System.out.println (f); + if (!f.exists () || !f.isFile ()) return false; diff --git a/src/com/bytezone/diskbrowser/wizardry/Character.java b/src/com/bytezone/diskbrowser/wizardry/Character.java index 9394ff2..90a4379 100755 --- a/src/com/bytezone/diskbrowser/wizardry/Character.java +++ b/src/com/bytezone/diskbrowser/wizardry/Character.java @@ -32,6 +32,7 @@ class Character extends AbstractFile // ---------------------------------------------------------------------------------// { super (name, buffer); + this.scenario = scenario; attributes = new Attributes (); diff --git a/src/com/bytezone/diskbrowser/wizardry/Character4.java b/src/com/bytezone/diskbrowser/wizardry/Character4.java new file mode 100644 index 0000000..11cee9d --- /dev/null +++ b/src/com/bytezone/diskbrowser/wizardry/Character4.java @@ -0,0 +1,16 @@ +package com.bytezone.diskbrowser.wizardry; + +import com.bytezone.diskbrowser.applefile.AbstractFile; + +// -----------------------------------------------------------------------------------// +public class Character4 extends AbstractFile +// -----------------------------------------------------------------------------------// +{ + + // ---------------------------------------------------------------------------------// + Character4 (String name, byte[] buffer) + // ---------------------------------------------------------------------------------// + { + super (name, buffer); + } +} diff --git a/src/com/bytezone/diskbrowser/wizardry/Header.java b/src/com/bytezone/diskbrowser/wizardry/Header.java index 47e750d..c11c0ad 100755 --- a/src/com/bytezone/diskbrowser/wizardry/Header.java +++ b/src/com/bytezone/diskbrowser/wizardry/Header.java @@ -101,6 +101,13 @@ class Header } } + // ---------------------------------------------------------------------------------// + ScenarioData get (int index) + // ---------------------------------------------------------------------------------// + { + return data.get (index); + } + // ---------------------------------------------------------------------------------// private void linkText (String title, DiskAddress da, DefaultMutableTreeNode headerNode) // ---------------------------------------------------------------------------------// diff --git a/src/com/bytezone/diskbrowser/wizardry/Huffman.java b/src/com/bytezone/diskbrowser/wizardry/Huffman.java index c07bd3d..c8005a3 100644 --- a/src/com/bytezone/diskbrowser/wizardry/Huffman.java +++ b/src/com/bytezone/diskbrowser/wizardry/Huffman.java @@ -1,5 +1,8 @@ package com.bytezone.diskbrowser.wizardry; +import java.util.ArrayList; +import java.util.List; + import com.bytezone.diskbrowser.applefile.AbstractFile; // Based on a pascal routine by Tom Ewers @@ -28,19 +31,52 @@ class Huffman extends AbstractFile super (name, buffer); } + // ---------------------------------------------------------------------------------// + byte[] decodeMessage (byte[] buffer, int offset, int length) + // ---------------------------------------------------------------------------------// + { + this.message = buffer; + List decoded = new ArrayList<> (); + int retPtr = 0; + int max = offset + length; + + depth = 0; + msgPtr = offset; + currentByte = 0; + + while (msgPtr < max) + decoded.add (getChar ()); + + byte[] returnBuffer = new byte[decoded.size ()]; + for (byte b : decoded) + returnBuffer[retPtr++] = b; + + return returnBuffer; + } + // ---------------------------------------------------------------------------------// String decodeMessage (byte[] message) // ---------------------------------------------------------------------------------// { this.message = message; + depth = 0; msgPtr = 0; currentByte = 0; - int len = getChar (); + int len = getChar () & 0xFF; StringBuilder text = new StringBuilder (); for (int i = 0; i < len; i++) - text.append ((char) getChar ()); + { + int c = getChar () & 0xFF; + text.append (switch (c) + { + case 0x09 -> " OF "; + case 0x0A -> "POTION"; + case 0x0B -> "STAFF"; + default -> c < 32 ? '?' : (char) c; + }); + } return text.toString (); } diff --git a/src/com/bytezone/diskbrowser/wizardry/Relocator.java b/src/com/bytezone/diskbrowser/wizardry/Relocator.java index 4b475cf..8e57779 100644 --- a/src/com/bytezone/diskbrowser/wizardry/Relocator.java +++ b/src/com/bytezone/diskbrowser/wizardry/Relocator.java @@ -40,21 +40,21 @@ public class Relocator extends AbstractFile for (DiskSegment diskSegment : diskRecord.diskSegments) { int lo = diskSegment.logicalBlock; - int hi = diskSegment.logicalBlock + diskSegment.segmentLength; + int hi = lo + diskSegment.segmentLength; for (int i = lo, count = 0; i < hi; i++, count++) - // if (diskBlocks[i] == 0) // doesn't matter either way - { - if (diskBlocks[i] != 0 && false) + if (diskBlocks[i] == 0) // doesn't matter either way { - System.out.print ("was: "); - System.out.printf ("diskBlocks[%d] = %d%n", i, diskBlocks[i]); - System.out.print ("now: "); - System.out.printf ("diskBlocks[%d] = %d%n", i, diskRecord.diskNumber); + if (diskBlocks[i] != 0 && false) + { + System.out.print ("was: "); + System.out.printf ("diskBlocks[%d] = %d%n", i, diskBlocks[i]); + System.out.print ("now: "); + System.out.printf ("diskBlocks[%d] = %d%n", i, diskRecord.diskNumber); + } + diskBlocks[i] = diskRecord.diskNumber; + diskOffsets[i] = diskSegment.physicalBlock + count; } - diskBlocks[i] = diskRecord.diskNumber; - diskOffsets[i] = diskSegment.physicalBlock + count; - } } } @@ -62,6 +62,8 @@ public class Relocator extends AbstractFile public void createNewBuffer (Disk[] dataDisks) // ---------------------------------------------------------------------------------// { + System.out.println (getText ()); + AppleDisk master = (AppleDisk) dataDisks[0]; // byte[] key1 = { 0x55, 0x55, 0x15, 0x55 }; // byte[] key2 = { 0x00, 0x00, 0x01, 0x41 }; diff --git a/src/com/bytezone/diskbrowser/wizardry/Wizardry4BootDisk.java b/src/com/bytezone/diskbrowser/wizardry/Wizardry4BootDisk.java index 57ea6fb..68cfd31 100644 --- a/src/com/bytezone/diskbrowser/wizardry/Wizardry4BootDisk.java +++ b/src/com/bytezone/diskbrowser/wizardry/Wizardry4BootDisk.java @@ -33,7 +33,7 @@ public class Wizardry4BootDisk extends PascalDisk { super (dataDisks[0]); - version = dataDisks.length == 6 ? 4 : dataDisks.length == 10 ? 5 : 0; + version = dataDisks.length == 7 ? 4 : dataDisks.length == 10 ? 5 : 0; DefaultTreeModel model = (DefaultTreeModel) catalogTree.getModel (); DefaultMutableTreeNode currentRoot = (DefaultMutableTreeNode) model.getRoot (); @@ -83,6 +83,7 @@ public class Wizardry4BootDisk extends PascalDisk } } + // scenario data if (version == 4) { DefaultMutableTreeNode scenarioNode = findNode (currentRoot, "SCENARIO.DATA"); @@ -92,6 +93,7 @@ public class Wizardry4BootDisk extends PascalDisk fileEntry.setFile (null); scenarioNode.setAllowsChildren (true); scenarioHeader = new Header (scenarioNode, this); + linkCharacters4 (scenarioNode, fileEntry); linkMazeLevels4 (scenarioNode, fileEntry); } } @@ -109,7 +111,10 @@ public class Wizardry4BootDisk extends PascalDisk linkBlock2 (scenarioNode, fileEntry); } } + else + System.out.println ("No Wizardry version set"); + // monster images if (version == 4) { DefaultMutableTreeNode monstersNode = findNode (currentRoot, "200.MONSTERS"); @@ -132,6 +137,72 @@ public class Wizardry4BootDisk extends PascalDisk } } + // ---------------------------------------------------------------------------------// + private void linkCharacters4 (DefaultMutableTreeNode scenarioNode, FileEntry fileEntry) + // ---------------------------------------------------------------------------------// + { + ScenarioData sd = scenarioHeader.get (Header.CHARACTER_AREA); + + byte[] buffer = fileEntry.getDataSource ().buffer; + List blocks = fileEntry.getSectors (); + + DefaultMutableTreeNode charactersNode = linkNode ("Characters", "Characters", scenarioNode); + List allCharacterBlocks = new ArrayList<> (); + + int ptr = sd.dataOffset * 512; + + for (int i = 0; i < 500; i++) + { + byte[] out = huffman.decodeMessage (buffer, ptr, sd.totalBlocks); + + String name = HexFormatter.getPascalString (out, 1); + + Character4 c = new Character4 (name, out); + List characterBlocks = new ArrayList<> (); + DiskAddress da = blocks.get (ptr / 512); + characterBlocks.add (da); + addToNode (c, charactersNode, characterBlocks); + + if (!allCharacterBlocks.contains (da)) + allCharacterBlocks.add (da); + + ptr += sd.totalBlocks; + } + + DefaultAppleFileSource afs = (DefaultAppleFileSource) charactersNode.getUserObject (); + afs.setSectors (allCharacterBlocks); + } + + // ---------------------------------------------------------------------------------// + private void linkMazeLevels4 (DefaultMutableTreeNode scenarioNode, FileEntry fileEntry) + // ---------------------------------------------------------------------------------// + { + ScenarioData mazeData = scenarioHeader.get (Header.MAZE_AREA); + + byte[] buffer = fileEntry.getDataSource ().buffer; + List blocks = fileEntry.getSectors (); + + DefaultMutableTreeNode mazeNode = linkNode ("Maze", "Levels string", scenarioNode); + List allMazeBlocks = new ArrayList<> (); + + for (int i = 0; i < mazeData.total; i++) + { + int blockPtr = mazeData.dataOffset + i * 2; + + byte[] level = new byte[0x380]; // 896 + System.arraycopy (buffer, blockPtr * 512, level, 0, level.length); + + List mazeBlocks = new ArrayList<> (); + mazeBlocks.add (blocks.get (blockPtr)); + mazeBlocks.add (blocks.get (blockPtr + 1)); + addToNode (new MazeLevel (level, i), mazeNode, mazeBlocks); + allMazeBlocks.addAll (mazeBlocks); + } + + DefaultAppleFileSource afs = (DefaultAppleFileSource) mazeNode.getUserObject (); + afs.setSectors (allMazeBlocks); + } + // ---------------------------------------------------------------------------------// private void linkMonsterImages4 (DefaultMutableTreeNode monstersNode, FileEntry fileEntry) // ---------------------------------------------------------------------------------// @@ -168,30 +239,6 @@ public class Wizardry4BootDisk extends PascalDisk } } - // ---------------------------------------------------------------------------------// - private void linkMazeLevels4 (DefaultMutableTreeNode scenarioNode, FileEntry fileEntry) - // ---------------------------------------------------------------------------------// - { - ScenarioData mazeData = scenarioHeader.data.get (Header.MAZE_AREA); - - byte[] buffer = fileEntry.getDataSource ().buffer; - List blocks = fileEntry.getSectors (); - - DefaultMutableTreeNode mazeNode = linkNode ("Maze", "Levels string", scenarioNode); - for (int i = 0; i < 15; i++) - { - byte[] level = new byte[0x380]; // 896 - int offset = mazeData.dataOffset * 512 + i * 1024; - System.arraycopy (buffer, offset, level, 0, level.length); - - List mazeBlocks = new ArrayList<> (); - int ptr = mazeData.dataOffset + i * 2; - mazeBlocks.add (blocks.get (ptr)); - mazeBlocks.add (blocks.get (ptr + 1)); - addToNode (new MazeLevel (level, i), mazeNode, mazeBlocks); - } - } - // ---------------------------------------------------------------------------------// private void linkMazeLevels5 (DefaultMutableTreeNode scenarioNode, FileEntry fileEntry) // ---------------------------------------------------------------------------------// @@ -332,6 +379,7 @@ public class Wizardry4BootDisk extends PascalDisk DefaultAppleFileSource afs = new DefaultAppleFileSource (name, text, this); DefaultMutableTreeNode node = new DefaultMutableTreeNode (afs); parent.add (node); + return node; } diff --git a/src/com/bytezone/diskbrowser/wizardry/WizardryScenarioDisk.java b/src/com/bytezone/diskbrowser/wizardry/WizardryScenarioDisk.java index 2ec3367..da3b99f 100755 --- a/src/com/bytezone/diskbrowser/wizardry/WizardryScenarioDisk.java +++ b/src/com/bytezone/diskbrowser/wizardry/WizardryScenarioDisk.java @@ -136,6 +136,7 @@ public class WizardryScenarioDisk extends PascalDisk { byte[] buffer = disk.readBlock (2); int totalFiles = Utility.getShort (buffer, 16); + if (totalFiles != 3) return false;