Compare commits

...

78 Commits

Author SHA1 Message Date
Denis Molony
2bc330e377 tidying 2024-05-07 08:34:02 +10:00
Denis Molony
6c81bcc93b allow dos 4.5 2024-05-07 08:28:33 +10:00
Denis Molony
171fd66ba1 tidying 2024-05-02 12:38:45 +10:00
Denis Molony
aa77ec1cd4 fixed catalog date display problem 2024-04-29 18:26:31 +10:00
Denis Molony
8f95988596 link to DiskBrowserApp 2024-04-06 16:33:53 +10:00
Denis Molony
8cb682f068 added C1/4100 2024-03-12 17:37:13 +10:00
Denis Molony
dfc7a68580 renamed jarFolder 2023-09-30 23:55:41 +10:00
Denis Molony
4b476457d3 added ant build.xml 2023-09-28 15:27:27 +10:00
Denis Molony
3bf972a761 tidying 2023-09-16 06:51:31 +10:00
Denis Molony
fd5bee6e5c tidying 2023-04-07 19:50:02 +10:00
Denis Molony
0af6714119 tidying 2023-03-16 09:00:31 +10:00
Denis Molony
22dfaf65c6 spacing 2023-03-11 16:35:48 +10:00
Denis Molony
f4a6465b04 shorten absolute path 2023-02-24 12:33:21 +10:00
Denis Molony
64d5ce9ee2 allow 2img length = 0 2023-02-20 13:02:53 +10:00
Denis Molony
4e48437adc tidying 2023-02-15 20:30:34 +10:00
Denis Molony
e2abdcabc9 added comment 2023-01-16 13:08:46 +10:00
Denis Molony
bc0993e9d3 better pascal TEXT handling 2022-12-15 20:35:26 +10:00
Denis Molony
9fba3893ba tidying 2022-12-11 01:59:44 +10:00
Denis Molony
09c4542118 Merge branch 'master' of https://github.com/dmolony/DiskBrowser.git 2022-12-11 01:56:35 +10:00
Denis Molony
af3ead0441 tidying 2022-12-11 01:54:00 +10:00
Denis Molony
c12392200b
Merge pull request #24 from frankmilliron/master
Add some new equates
2022-11-27 04:53:01 +10:00
frankmilliron
794fef8610
Add some new equates 2022-11-26 10:31:06 -08:00
frankmilliron
2ec0e10c5e
Add some new equates 2022-11-26 10:27:06 -08:00
Denis Molony
668ed719fa tidying 2022-09-16 06:26:52 +10:00
Denis Molony
23b95675cf tidying 2022-08-22 16:55:32 +10:00
Denis Molony
b98ecbed8d allow truncated bin2 files 2022-08-10 21:01:21 +10:00
Denis Molony
82381a6a47 fixed DateTime bug 2022-08-10 18:06:43 +10:00
Denis Molony
3f2f1bfbca stupid eclipse 2022-08-10 15:10:16 +10:00
Denis Molony
a7119528a6 reorder block allocations 2022-08-10 15:08:10 +10:00
Denis Molony
6f943ae8c2 tidying 2022-07-31 10:08:15 +10:00
Denis Molony
5add6c0729 tidying 2022-07-31 09:58:00 +10:00
Denis Molony
921c946ab5 Added Squeeze format (BQY) 2022-07-31 09:21:52 +10:00
Denis Molony
898587b23b Added a formatted checkbox to the save dialog 2022-07-31 07:13:59 +10:00
Denis Molony
37c489f252 Fixed Pascal bug with invalid dates 2022-07-29 23:00:30 +10:00
Denis Molony
036e47b9b1 tidying 2022-07-09 08:13:05 +10:00
Denis Molony
250c1a9bd9 more spell code 2022-06-21 13:59:42 +10:00
Denis Molony
b19e89d7cf fixed bug in known spells 2022-06-21 12:51:43 +10:00
Denis Molony
d71cabb754 tidying 2022-06-17 18:24:43 +10:00
Denis Molony
848b2469ae refactoring Character 2022-06-11 15:52:58 +10:00
Denis Molony
989b1d5ab9 fixed link to WizardryApp 2022-06-10 15:59:47 +10:00
Denis Molony
e0a2c50d5b fixed attributes bug 2022-06-10 15:56:48 +10:00
Denis Molony
8765299cf4 tidying 2022-06-09 16:14:52 +10:00
Denis Molony
97fe58d94d refactoring getWizLong and getSignedShort 2022-06-06 10:15:14 +10:00
Denis Molony
7d4d8c75e6 adjusted huffman decode routine 2022-06-04 13:06:20 +10:00
Denis Molony
f5664a9ce9 Updated Item 2022-05-31 17:44:41 +10:00
Denis Molony
9d8cdcd67b explained wiz4 naming convention 2022-05-29 19:58:12 +10:00
Denis Molony
12b74f9d21 Wizardry IV screen 2022-05-29 19:51:19 +10:00
Denis Molony
1b405c6f38 tidying 2022-05-29 18:53:08 +10:00
Denis Molony
66d6910f91 started combining CharacterV1 and CharacterV4 2022-05-29 16:21:20 +10:00
Denis Molony
572ee8c3a1 added possessions to characters 2022-05-29 15:16:11 +10:00
Denis Molony
2a14b7baad display attributes and spells 2022-05-29 12:52:42 +10:00
Denis Molony
a633e28ed3 added character parties 2022-05-29 10:43:10 +10:00
Denis Molony
ca11e8ee68 improved group routine 2022-05-28 19:15:32 +10:00
Denis Molony
ce52253f5d found how to group characters 2022-05-28 18:54:06 +10:00
Denis Molony
e408aa3d62 tidying 2022-05-28 16:19:37 +10:00
Denis Molony
c4b4d17f52 Items and Monsters for Wizardry IV 2022-05-28 12:59:25 +10:00
Denis Molony
0b72f1a37d Added characters to Wiz4 2022-05-27 18:30:30 +10:00
Denis Molony
1b86b31233 removed GregorianCalendar 2022-05-11 10:09:27 +10:00
Denis Molony
1b9e9d47ac checking Wiz4 disks 2022-05-03 15:36:37 +10:00
Denis Molony
decc781572 tidying 2022-04-13 09:51:17 +10:00
Denis Molony
16ccc2632a allow woz disks to be saved as converted disk images 2022-04-09 18:25:02 +10:00
Denis Molony
40c2afbd48 tidying 2022-04-06 18:05:37 +10:00
Denis Molony
f9038810d2 wrong picture 2022-03-31 12:06:39 +10:00
Denis Molony
3435e825df use stored experience points 2022-03-31 12:04:23 +10:00
Denis Molony
ff7c6fd126 found bug in Wizardry exp points calculation 2022-03-29 18:00:32 +10:00
Denis Molony
91846d8563 later screen 2022-03-28 18:36:17 +10:00
Denis Molony
19b6339ac5 calculate experience points correctly 2022-03-28 17:02:01 +10:00
Denis Molony
db4953618c allow woz format pascal disks 2022-03-28 13:55:49 +10:00
Denis Molony
c1deee56a0 tidying 2022-03-26 21:37:41 +10:00
Denis Molony
b1ed1a74ba tidying 2022-03-26 18:07:17 +10:00
Denis Molony
cf0cfd278b added Message 2022-03-18 19:22:07 +10:00
Denis Molony
48aca6e1eb tidying 2022-03-14 08:46:56 +10:00
Denis Molony
d83ac3afda changed Maze hex output to debug screen 2022-03-10 21:06:52 +10:00
Denis Molony
2270b1f6db tidying 2022-03-10 19:04:52 +10:00
Denis Molony
da67dbe0d7 more details on maze levels 2022-03-10 16:21:18 +10:00
Denis Molony
133352ba31 various 2022-02-07 15:28:22 +10:00
Denis Molony
761c43dc3d changed award function 2022-02-07 15:26:42 +10:00
Denis Molony
d03de97247 fixed stack overflow bug 2022-02-07 15:26:17 +10:00
78 changed files with 3164 additions and 1602 deletions

4
.gitignore vendored
View File

@ -1,4 +0,0 @@
/bin/
.project
.classpath
build.xml

View File

@ -1,5 +1,6 @@
# Apple II Disk Browser # Apple II Disk Browser
### Alternative
There is a new release of [DiskBrowser2](https://github.com/dmolony/diskbrowser2) available.
### Features ### Features
- Cross-platform (Windows, MacOS, Linux) - Cross-platform (Windows, MacOS, Linux)
- Disk formats - Disk formats
@ -61,7 +62,10 @@ For the truly retro look, programs can be displayed in the [original 40-column l
#### Infocom #### Infocom
![Infocom](resources/zork.png?raw=true "Infocom") ![Infocom](resources/zork.png?raw=true "Infocom")
#### Wizardry #### Wizardry
Wizardry scenarios 1 to 3 are reasonably complete, Wizardry IV and V are partially done. For a dedicated Wizardry application see [WizardryApp](https://github.com/dmolony/WizardryApp).
![Wizardry](resources/wizardry.png?raw=true "Wizardry") ![Wizardry](resources/wizardry.png?raw=true "Wizardry")
Scenarios 4 and 5 come on multiple disks, and they need to be named so that the only difference between disk names is the identifier before the '.dsk' suffix.
![Wizardry](resources/wizardry4.png?raw=true "Wizardry IV")
#### Visicalc #### Visicalc
DiskBrowser has an inbuilt Visicalc processor which will evaluate the sheet and display the results. DiskBrowser has an inbuilt Visicalc processor which will evaluate the sheet and display the results.
![Visicalc](resources/visicalc.png?raw=true "Visicalc") ![Visicalc](resources/visicalc.png?raw=true "Visicalc")

40
build.xml Normal file
View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="DiskBrowser" default="jar" basedir=".">
<property name="srcDir" location="src" />
<property name="binDir" location="bin" />
<property name="jarDir" location="${user.home}/Dropbox/Java" />
<property name="jarFile" location="${jarDir}/DiskBrowser.jar" />
<target name="version">
<echo>DiskBrowser.jar</echo>
<echo>${ant.version}</echo>
<echo>Java/JVM version: ${ant.java.version}</echo>
<echo>Java/JVM detail version: ${java.version}</echo>
</target>
<target name="init" depends="version">
<delete file="${binDir}/*.class" />
<delete file="${jarFile}" />
</target>
<target name="compile" depends="init">
<javac debug="on" srcdir="${srcDir}" destdir="${binDir}" includeantruntime="false">
<classpath>
<pathelement location="." />
</classpath>
</javac>
</target>
<target name="jar" depends="compile">
<jar destfile="${jarFile}">
<fileset dir="${binDir}" />
<zipfileset src="${jarDir}/InputPanel.jar" />
<manifest>
<attribute name="Main-Class" value="com.bytezone.diskbrowser.gui.DiskBrowser" />
</manifest>
</jar>
</target>
</project>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 642 KiB

After

Width:  |  Height:  |  Size: 1.0 MiB

BIN
resources/wizardry4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

View File

@ -15,7 +15,7 @@ public abstract class AbstractFile implements DataSource
{ {
static boolean showDebugText; static boolean showDebugText;
String name; protected String name;
public byte[] buffer; public byte[] buffer;
AssemblerProgram assembler; AssemblerProgram assembler;
protected BufferedImage image; protected BufferedImage image;

View File

@ -10,7 +10,7 @@ public class ApplesoftBasicProgram extends BasicProgram implements ApplesoftCons
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
{ {
private final List<SourceLine> sourceLines = new ArrayList<> (); private final List<SourceLine> sourceLines = new ArrayList<> ();
private int ptr; // end-of-program marker private int ptr = 0; // end-of-program marker
private final UserBasicFormatter userBasicFormatter; private final UserBasicFormatter userBasicFormatter;
private final AppleBasicFormatter appleBasicFormatter; private final AppleBasicFormatter appleBasicFormatter;

View File

@ -8,8 +8,8 @@ import com.bytezone.diskbrowser.utilities.HexFormatter;
public class BasicTextFile extends TextFile public class BasicTextFile extends TextFile
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
{ {
private static String underline = "------------------------------------------" private static String underline =
+ "------------------------------------\n"; "------------------------------------------" + "------------------------------------\n";
private static String fullUnderline = "---------- ------- " + underline; private static String fullUnderline = "---------- ------- " + underline;
private int recordLength; // prodos aux private int recordLength; // prodos aux
private List<TextBuffer> buffers; // only used if it is a Prodos text file private List<TextBuffer> buffers; // only used if it is a Prodos text file
@ -30,6 +30,7 @@ public class BasicTextFile extends TextFile
super (name, buffer); super (name, buffer);
this.eof = eof; this.eof = eof;
recordLength = auxType; recordLength = auxType;
prodosFile = true; prodosFile = true;
} }
@ -42,6 +43,7 @@ public class BasicTextFile extends TextFile
this.buffers = buffers; this.buffers = buffers;
this.eof = eof; this.eof = eof;
recordLength = auxType; recordLength = auxType;
prodosFile = true; prodosFile = true;
} }
@ -167,8 +169,7 @@ public class BasicTextFile extends TextFile
if (textPreferences.showTextOffsets) if (textPreferences.showTextOffsets)
{ {
line = line.replaceAll ("\\n", "\n "); line = line.replaceAll ("\\n", "\n ");
text.append ( text.append (String.format ("%,10d %,8d %s%n", recNo * recordLength, recNo, line));
String.format ("%,10d %,8d %s%n", recNo * recordLength, recNo, line));
} }
else else
text.append (String.format ("%s%n", line)); text.append (String.format ("%s%n", line));

View File

@ -20,10 +20,12 @@ public abstract class HiResImage extends AbstractFile
{ "Paintworks Packed SHR Image", "Packed Super Hi-Res Image", { "Paintworks Packed SHR Image", "Packed Super Hi-Res Image",
"Super Hi-Res Image (Apple Preferred Format)", "Packed QuickDraw II PICT File", "Super Hi-Res Image (Apple Preferred Format)", "Packed QuickDraw II PICT File",
"Packed Super Hi-Res 3200 color image", "DreamGraphix" }; "Packed Super Hi-Res 3200 color image", "DreamGraphix" };
static final int COLOR_TABLE_SIZE = 32; static final int COLOR_TABLE_SIZE = 32;
static final int COLOR_TABLE_OFFSET_AUX_0 = 32_256; static final int COLOR_TABLE_OFFSET_AUX_0 = 32_256;
static final int COLOR_TABLE_OFFSET_AUX_2 = 32_000; static final int COLOR_TABLE_OFFSET_AUX_2 = 32_000;
public static final int FADDEN_AUX = 0x8066; public static final int FADDEN_AUX = 0x8066;
private byte[] fourBuf = new byte[4]; private byte[] fourBuf = new byte[4];
private ColorTable defaultColorTable320 = new ColorTable (0, 0x00); private ColorTable defaultColorTable320 = new ColorTable (0, 0x00);
private ColorTable defaultColorTable640 = new ColorTable (0, 0x80); private ColorTable defaultColorTable640 = new ColorTable (0, 0x80);

View File

@ -4,6 +4,8 @@ package com.bytezone.diskbrowser.applefile;
public class PascalText extends TextFile public class PascalText extends TextFile
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
{ {
private final static int PAGE_SIZE = 1024;
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
public PascalText (String name, byte[] buffer) public PascalText (String name, byte[] buffer)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
@ -16,28 +18,34 @@ public class PascalText extends TextFile
public String getText () public String getText ()
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
// Text files are broken up into 1024-byte pages.
// [DLE] [indent] [text] [CR] ... [nulls]
StringBuilder text = new StringBuilder (getHeader ()); StringBuilder text = new StringBuilder (getHeader ());
int ptr = 0x400; int ptr = PAGE_SIZE; // skip text editor header
while (ptr < buffer.length) while (ptr < buffer.length)
{ {
if (buffer[ptr] == 0x00) if (buffer[ptr] == 0x00) // padding to page boundary
{ {
++ptr; ptr = (ptr / PAGE_SIZE + 1) * PAGE_SIZE; // skip to next page
continue; continue;
} }
if (buffer[ptr] == 0x10) if (buffer[ptr] == 0x10) // Data Link Escape code
{ {
int tab = buffer[ptr + 1] - 0x20; int tab = (buffer[ptr + 1] & 0xFF) - 32; // indent amaount
while (tab-- > 0) while (tab-- > 0)
text.append (" "); text.append (" ");
ptr += 2; ptr += 2;
} }
String line = getLine (ptr); while (buffer[ptr] != 0x0D)
text.append (line + "\n"); text.append ((char) buffer[ptr++]);
ptr += line.length () + 1;
text.append ("\n");
ptr++;
} }
if (text.length () > 0) if (text.length () > 0)
@ -45,16 +53,4 @@ public class PascalText extends TextFile
return text.toString (); return text.toString ();
} }
// ---------------------------------------------------------------------------------//
private String getLine (int ptr)
// ---------------------------------------------------------------------------------//
{
StringBuilder line = new StringBuilder ();
while (buffer[ptr] != 0x0D)
line.append ((char) buffer[ptr++]);
return line.toString ();
}
} }

View File

@ -3,6 +3,7 @@ package com.bytezone.diskbrowser.applefile;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.List; import java.util.List;
import java.util.Locale;
import com.bytezone.diskbrowser.disk.FormattedDisk; import com.bytezone.diskbrowser.disk.FormattedDisk;
import com.bytezone.diskbrowser.prodos.DirectoryHeader; import com.bytezone.diskbrowser.prodos.DirectoryHeader;
@ -15,7 +16,8 @@ import com.bytezone.diskbrowser.utilities.Utility;
public class ProdosDirectory extends AbstractFile implements ProdosConstants public class ProdosDirectory extends AbstractFile implements ProdosConstants
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
{ {
static final DateTimeFormatter df = DateTimeFormatter.ofPattern ("d-LLL-yy"); private static Locale US = Locale.US; // to force 3 character months
static final DateTimeFormatter df = DateTimeFormatter.ofPattern ("d-LLL-yy", US);
static final DateTimeFormatter tf = DateTimeFormatter.ofPattern ("H:mm"); static final DateTimeFormatter tf = DateTimeFormatter.ofPattern ("H:mm");
static final String UNDERLINE = static final String UNDERLINE =
"----------------------------------------------------\n"; "----------------------------------------------------\n";
@ -86,7 +88,6 @@ public class ProdosDirectory extends AbstractFile implements ProdosConstants
int nameLength = buffer[i] & 0x0F; int nameLength = buffer[i] & 0x0F;
String filename = HexFormatter.getString (buffer, i + 1, nameLength); String filename = HexFormatter.getString (buffer, i + 1, nameLength);
String subType = ""; String subType = "";
String locked;
switch (storageType) switch (storageType)
{ {
@ -121,12 +122,12 @@ public class ProdosDirectory extends AbstractFile implements ProdosConstants
int eof = Utility.intValue (buffer[i + 21], buffer[i + 22], buffer[i + 23]); int eof = Utility.intValue (buffer[i + 21], buffer[i + 22], buffer[i + 23]);
int fileType = buffer[i + 16] & 0xFF; int fileType = buffer[i + 16] & 0xFF;
locked = (buffer[i + 30] & 0xE0) == 0xE0 ? " " : "*"; String locked = (buffer[i + 30] & 0xE0) == 0xE0 ? " " : "*";
int aux = Utility.getShort (buffer, i + 31);
switch (fileType) switch (fileType)
{ {
case FILE_TYPE_TEXT: case FILE_TYPE_TEXT:
int aux = Utility.getShort (buffer, i + 31);
subType = String.format ("R=%5d", aux); subType = String.format ("R=%5d", aux);
break; break;
@ -134,14 +135,13 @@ public class ProdosDirectory extends AbstractFile implements ProdosConstants
case FILE_TYPE_PNT: case FILE_TYPE_PNT:
case FILE_TYPE_PIC: case FILE_TYPE_PIC:
case FILE_TYPE_FOT: case FILE_TYPE_FOT:
aux = Utility.getShort (buffer, i + 31);
subType = String.format ("A=$%4X", aux); subType = String.format ("A=$%4X", aux);
break; break;
case FILE_TYPE_AWP: case FILE_TYPE_AWP:
aux = Utility.intValue (buffer[i + 32], buffer[i + 31]); // backwards! int flags = Utility.intValue (buffer[i + 32], buffer[i + 31]); // aux backwards!
if (aux != 0) if (flags != 0)
filename = convert (filename, aux); filename = convert (filename, flags);
break; break;
default: default:
@ -149,9 +149,10 @@ public class ProdosDirectory extends AbstractFile implements ProdosConstants
} }
String forkFlag = storageType == 5 ? "+" : " "; String forkFlag = storageType == 5 ? "+" : " ";
text.append (String.format ("%s%-15s %3s%s %5d %9s %5s %9s %5s %8d %7s%n", text.append (
locked, filename, ProdosConstants.fileTypes[type], forkFlag, blocks, dateM, String.format ("%s%-15s %3s%s %5d %9s %5s %9s %5s %8d %7s %04X%n",
timeM, dateC, timeC, eof, subType)); locked, filename, ProdosConstants.fileTypes[type], forkFlag, blocks,
dateM, timeM, dateC, timeC, eof, subType, aux));
break; break;
default: default:

View File

@ -88,8 +88,8 @@ public class QuickDrawFont extends CharacterList
firstChar = Utility.getShort (buffer, ptr + 2); firstChar = Utility.getShort (buffer, ptr + 2);
lastChar = Utility.getShort (buffer, ptr + 4); lastChar = Utility.getShort (buffer, ptr + 4);
widMax = Utility.getShort (buffer, ptr + 6); widMax = Utility.getShort (buffer, ptr + 6);
kernMax = Utility.signedShort (buffer, ptr + 8); kernMax = Utility.getSignedShort (buffer, ptr + 8);
nDescent = Utility.signedShort (buffer, ptr + 10); nDescent = Utility.getSignedShort (buffer, ptr + 10);
fRectWidth = Utility.getShort (buffer, ptr + 12); fRectWidth = Utility.getShort (buffer, ptr + 12);
fRectHeight = Utility.getShort (buffer, ptr + 14); fRectHeight = Utility.getShort (buffer, ptr + 14);

View File

@ -243,7 +243,7 @@ public class SHRPictureFile1 extends HiResImage
colorTables[i] = new ColorTable (i, data, ptr); colorTables[i] = new ColorTable (i, data, ptr);
else else
colorTables[i] = new ColorTable (i, 0x00); // default empty table !! not colorTables[i] = new ColorTable (i, 0x00); // default empty table !! not
// finished // finished
ptr += 32; ptr += 32;
} }
} }

View File

@ -1,16 +1,40 @@
package com.bytezone.diskbrowser.applefile; package com.bytezone.diskbrowser.applefile;
import com.bytezone.diskbrowser.utilities.Utility;
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
public class SegmentDictionary public class SegmentDictionary
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
{ {
private final boolean isValid; private final boolean isValid;
private int[] codeAddress = new int[16];
private int[] codeLength = new int[16];
private String[] segName = new String[16];
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
public SegmentDictionary (String name, byte[] buffer) public SegmentDictionary (String name, byte[] buffer)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
isValid = !name.equals ("SYSTEM.INTERP"); // temporary isValid = !name.equals ("SYSTEM.INTERP"); // temporary
int ptr = 0;
for (int seg = 0; seg < 16; seg++)
{
codeAddress[seg] = Utility.getShort (buffer, ptr);
ptr += 2;
codeLength[seg] = Utility.getShort (buffer, ptr);
ptr += 2;
}
ptr = 64;
for (int seg = 0; seg < 16; seg++)
{
segName[seg] = new String (buffer, ptr, 8);
ptr += 8;
}
// for (int seg = 0; seg < 16; seg++)
// System.out.printf ("%04X %04X %s%n", codeAddress[seg], codeLength[seg], segName[seg]);
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//

View File

@ -202,7 +202,7 @@ public class SubLine implements ApplesoftConstants
private void checkFunction (String var, byte terminator) private void checkFunction (String var, byte terminator)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
assert terminator == ASCII_LEFT_BRACKET; // assert terminator == ASCII_LEFT_BRACKET;
if (!functions.contains (var)) if (!functions.contains (var))
functions.add (var); functions.add (var);

View File

@ -22,10 +22,19 @@
0035 YSAV1 0035 YSAV1
0036 CSWL 0036 CSWL
0037 CSHW 0037 CSHW
0044 A5L - volume number? 003D A1H
003C A1L
003F A2H
003E A2L
0041 A3H
0040 A3L
0043 A4H
0042 A4L
0045 A5H
0044 A5L
004E RND-LO 004E RND-LO
004F RND-HI 004F RND-HI
0050 LINNUM 0050 LINNUM line number, unsigned word
0067 Basic program address LO 0067 Basic program address LO
0068 Basic program address HI 0068 Basic program address HI
0069 Basic variables address LO 0069 Basic variables address LO
@ -52,8 +61,48 @@
0200 Input buffer 0200 Input buffer
03D0 Applesoft warm start 03D0 Applesoft warm start
03EA VECT
A56E catalog routine 03F2 RST: Control-reset vector
03F3 RST: Control-reset vector
03F4 RST: Control-reset checksum (EOR #$A5)
03FB NMI: Non-Maskable Interrupt vector
03FC NMI: Non-Maskable Interrupt vector
03F8 USR: user vector (Control-Y)
03F9 USR: user vector (Control-Y)
03FE IRQ: Interrupt Request/BRK vector
03FF IRQ: Interrupt Request/BRK vector
A54F DOS 3.3 INIT
A413 DOS 3.3 LOAD
A397 DOS 3.3 SAVE
A4D1 DOS 3.3 RUN
A4F0 DOS 3.3 CHAIN
A263 DOS 3.3 DELETE
A271 DOS 3.3 LOCK
A275 DOS 3.3 UNLOCK
A2EA DOS 3.3 CLOSE
A51B DOS 3.3 READ
A5C6 DOS 3.3 EXEC
A510 DOS 3.3 WRITE
A5DD DOS 3.3 POSITION
A2A3 DOS 3.3 OPEN
A298 DOS 3.3 APPEND
A281 DOS 3.3 RENAME
A56E DOS 3.3 CATALOG
A233 DOS 3.3 MON
A23D DOS 3.3 NOMON
A229 DOS 3.3 PR#
A22E DOS 3.3 IN#
A251 DOS 3.3 MAXFILES
A57A DOS 3.3 FP
A59E DOS 3.3 INT
A331 DOS 3.3 BSAVE
A35D DOS 3.3 BLOAD
A38E DOS 3.3 BRUN
A27D DOS 3.3 VERIFY
BF00 ProDOS MLI entry point
BF98 ProDOS Machine ID Byte
* C000 80STOREOFF Allow page2 to switch video page1 page2 * C000 80STOREOFF Allow page2 to switch video page1 page2
C001 80STOREON Allow page2 to switch main & aux video memory C001 80STOREON Allow page2 to switch main & aux video memory
@ -68,8 +117,12 @@ C009 ALTZPON Enable aux memory from $0000-$01FF & avl BSR
C00A SLOTC3ROMOFF Enable main ROM from $C300-$C3FF C00A SLOTC3ROMOFF Enable main ROM from $C300-$C3FF
C00B SLOTC3ROMON Enable slot ROM from $C300-$C3FF C00B SLOTC3ROMON Enable slot ROM from $C300-$C3FF
C000 KYBD - last key pressed C000 KBD - Last key pressed
C010 STROBE - Clear KYBD C010 KBDSTRB - Clear KYBD
C019 VBL - Vertical Blank
C020 TAPEOUT - Toggle cassette output
C030 SPKR - Toggle speaker
C040 STROBE - Output strobe pulse to game I/O connector
C050 TXTCLR - Display Graphics C050 TXTCLR - Display Graphics
C051 TXTSET - Display Text C051 TXTSET - Display Text
C052 MIXCLR - Display Full Screen C052 MIXCLR - Display Full Screen
@ -78,6 +131,15 @@ C054 TXTPAGE1 - Display Page 1
C055 TXTPAGE2 - If 80STORE Off: Display Page 2, If 80STORE On: Read/Write Aux Display Mem C055 TXTPAGE2 - If 80STORE Off: Display Page 2, If 80STORE On: Read/Write Aux Display Mem
C056 LORES - Display LoRes Graphics C056 LORES - Display LoRes Graphics
C057 HIRES - Display HiRes Graphics C057 HIRES - Display HiRes Graphics
C060 TAPEIN - Read audio from cassette input
C061 PB0 - Read joystick button 0/Open-Apple key
C062 PB1 - Read joystick button 1/Closed-Apple key
C063 PB2 - Read joystick button 2
C064 PADDL0 - Read paddle/joystick 0
C065 PADDL1 - Read paddle/joystick 1
C066 PADDL2 - Read paddle/joystick 2
C067 PADDL3 - Read paddle/joystick 3
C070 PTRIG - Clear paddle/joystick timer
C080 Read RAM bank 2; no write C080 Read RAM bank 2; no write
C081 ROMIN - Read ROM; write RAM bank 2 C081 ROMIN - Read ROM; write RAM bank 2
@ -96,6 +158,9 @@ C08D Read ROM; write RAM bank 1
C08E Read ROM; no write C08E Read ROM; no write
C08F Read/write RAM bank 1 C08F Read/write RAM bank 1
C600 BOOT0 - Disk II controller ROM
0801 BOOT1 - Disk II bootstrap RAM
D52C INLIN numeric input D52C INLIN numeric input
DB3A STROUT - output a string DB3A STROUT - output a string
DB5C output a character DB5C output a character
@ -106,6 +171,7 @@ DEC0 SYNCHR
DEC9 syntax error DEC9 syntax error
DFE3 PTRGET DFE3 PTRGET
E000 Applesoft BASIC entry
E053 find a variable E053 find a variable
E10C convert FP to INT E10C convert FP to INT
E2F2 GIVAYF - convert (A,Y) to FP E2F2 GIVAYF - convert (A,Y) to FP
@ -177,15 +243,16 @@ F941 PRINTAX - print AX registers in hex
F948 PRBLNK - print 3 spaces F948 PRBLNK - print 3 spaces
F94A PRBL2 - print X blank spaces F94A PRBL2 - print X blank spaces
FAA6 reboot DOS FAA6 PWRUP - reboot
FAFF 0 = Autostart ROM, 1 = Old Monitor FAFF 0 = Autostart ROM, 1 = Old Monitor
FB1E PREAD - read game paddle FB1E PREAD - read game paddle
FB2F initialise text screen FB2F INIT - initialise text screen
FB39 text mode - SETTXT FB39 text mode - SETTXT
FB40 SETGR FB40 SETGR
FB5B TABV - monitor tab routine FB5B TABV - monitor tab routine
FB6F set powerup checksum FB6F SETPWRC - set powerup checksum
FBB3 VERSION - monitor ROM ID byte
FBC1 BASCALC - calculate video address FBC1 BASCALC - calculate video address
FBDD BELL1 - beep speaker FBDD BELL1 - beep speaker
FBF4 CURSRIT - move cursor right FBF4 CURSRIT - move cursor right
@ -193,6 +260,7 @@ FBF4 CURSRIT - move cursor right
FC10 CURSLFT - move cursor left FC10 CURSLFT - move cursor left
FC1A CURSUP - move cursor up FC1A CURSUP - move cursor up
FC22 VTAB FC22 VTAB
FC24 VTABZ
FC42 CLREOP - clear to end of page FC42 CLREOP - clear to end of page
FC58 HOME - clear screen FC58 HOME - clear screen
FC62 CR FC62 CR
@ -215,12 +283,13 @@ FDE3 PRHEX - print a hex digit
FDED COUT - print a character (in Acc) FDED COUT - print a character (in Acc)
FDF0 COUT1 - print character to screen FDF0 COUT1 - print character to screen
FE2C move a block of memory FE1F IDROUTINE - detect //gs
FE2C MOVE - move a block of memory
FE80 SETINV - set inverse mode FE80 SETINV - set inverse mode
FE84 SETNORM - set normal mode FE84 SETNORM - set normal mode
FE89 disconnect DOS from I/O links FE89 SETKBD - disconnect DOS from I/O links
FE8B INPORT FE8B INPORT
FE93 disconnect DOS from I/O links FE93 SETVID - disconnect DOS from I/O links
FE95 OUTPORT FE95 OUTPORT
FECD WRITE FECD WRITE
FEFD READ FEFD READ
@ -231,6 +300,14 @@ FF3A BELL
FF3F IOREST - restore all registers FF3F IOREST - restore all registers
FF4A IOSAVE - save all registers FF4A IOSAVE - save all registers
FF58 RTS - jump to <address on stack> + 1 FF58 RTS - jump to <address on stack> + 1
FF59 Monitor cold entry point FF59 MON - Monitor cold entry point (w/BELL)
FF69 MONZ - Monitor entry point from BASIC (CALL -151)
FFA7 GETNUM - move num to A2L.A2H FFA7 GETNUM - move num to A2L.A2H
FFC7 ZMODE - monitor get ASCII return FFC7 ZMODE - monitor get ASCII return
FFFA NMI_VECTOR
FFFB NMI_VECTOR
FFFC RESET_VECTOR
FFFD RESET_VECTOR
FFFE IRQ_VECTOR
FFFF IRQ_VECTOR

View File

@ -16,6 +16,7 @@ import com.bytezone.diskbrowser.disk.SectorType;
import com.bytezone.diskbrowser.gui.DataSource; import com.bytezone.diskbrowser.gui.DataSource;
import com.bytezone.diskbrowser.utilities.HexFormatter; import com.bytezone.diskbrowser.utilities.HexFormatter;
// https://www.retrotechnology.com/dri/howto_cpm.html
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
public class CPMDisk extends AbstractFormattedDisk public class CPMDisk extends AbstractFormattedDisk
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
@ -88,7 +89,7 @@ public class CPMDisk extends AbstractFormattedDisk
if (b1 > 31 && b1 != EMPTY_BYTE_VALUE) if (b1 > 31 && b1 != EMPTY_BYTE_VALUE)
break; break;
if (b2 < 32 || (b2 > 126 && b2 != EMPTY_BYTE_VALUE)) if (b2 <= 32 || (b2 > 126 && b2 != EMPTY_BYTE_VALUE))
break; break;
for (int i = 0; i < buffer.length; i += 32) for (int i = 0; i < buffer.length; i += 32)
@ -99,7 +100,7 @@ public class CPMDisk extends AbstractFormattedDisk
if (b1 == EMPTY_BYTE_VALUE) // deleted file?? if (b1 == EMPTY_BYTE_VALUE) // deleted file??
continue; continue;
if (b2 < 32 || (b2 > 126 && b2 != EMPTY_BYTE_VALUE)) if (b2 <= 32 || (b2 > 126 && b2 != EMPTY_BYTE_VALUE))
break; break;
DirectoryEntry entry = new DirectoryEntry (this, buffer, i); DirectoryEntry entry = new DirectoryEntry (this, buffer, i);
@ -188,9 +189,8 @@ public class CPMDisk extends AbstractFormattedDisk
public AppleFileSource getCatalog () public AppleFileSource getCatalog ()
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
String line = String line = "---- --------- --- - - -- -- -- -- ----------------------------"
"---- --------- --- - - -- -- -- -- ----------------------------" + "-------------------\n";
+ "-------------------\n";
StringBuilder text = new StringBuilder (); StringBuilder text = new StringBuilder ();
text.append (String.format ("File : %s%n%n", getDisplayPath ())); text.append (String.format ("File : %s%n%n", getDisplayPath ()));
text.append ("User Name Typ R S Ex S2 S1 RC Blocks\n"); text.append ("User Name Typ R S Ex S2 S1 RC Blocks\n");

View File

@ -139,9 +139,8 @@ class DirectoryEntry implements AppleFileSource
char ro = readOnly ? '*' : ' '; char ro = readOnly ? '*' : ' ';
char sf = systemFile ? '*' : ' '; char sf = systemFile ? '*' : ' ';
String text = String text = String.format ("%3d %-8s %-3s %s %s %02X %02X %02X %02X %s",
String.format ("%3d %-8s %-3s %s %s %02X %02X %02X %02X %s", userNumber, name, type, ro, sf, extent, s2, s1, recordsUsed, bytes);
userNumber, name, type, ro, sf, extent, s2, s1, recordsUsed, bytes);
for (DirectoryEntry entry : entries) for (DirectoryEntry entry : entries)
text = text + "\n" + entry.line (); text = text + "\n" + entry.line ();
@ -218,14 +217,13 @@ class DirectoryEntry implements AppleFileSource
else if ("DVR".equals (type)) else if ("DVR".equals (type))
appleFile = new DefaultAppleFile (name, exactBuffer, "DVR File"); appleFile = new DefaultAppleFile (name, exactBuffer, "DVR File");
else if ("ASM".equals (type) || "DOC".equals (type) || "COB".equals (type) else if ("ASM".equals (type) || "DOC".equals (type) || "COB".equals (type)
|| "HLP".equals (type) || "TXT".equals (type) || "LET".equals (type) || "HLP".equals (type) || "TXT".equals (type) || "LET".equals (type) || "ALX".equals (type)
|| "ALX".equals (type) || "SRC".equals (type) || "H".equals (type) || "SRC".equals (type) || "H".equals (type) || exactBuffer[len - 1] == 0x1A)
|| exactBuffer[len - 1] == 0x1A)
appleFile = new CPMTextFile (name, exactBuffer); appleFile = new CPMTextFile (name, exactBuffer);
else if ("BAS".equals (type)) else if ("BAS".equals (type))
appleFile = new CPMBasicFile (name, exactBuffer); appleFile = new CPMBasicFile (name, exactBuffer);
else else
appleFile = new DefaultAppleFile (name, exactBuffer, "CPM File : " + type); appleFile = new DefaultAppleFile (name, exactBuffer, "CPM File : " + name + "." + type);
return appleFile; return appleFile;
} }

View File

@ -206,8 +206,7 @@ public abstract class AbstractFormattedDisk implements FormattedDisk
DefaultMutableTreeNode root = getCatalogTreeRoot (); DefaultMutableTreeNode root = getCatalogTreeRoot ();
if (root.getUserObject () == null) if (root.getUserObject () == null)
root.setUserObject ( root.setUserObject (new DefaultAppleFileSource (getName (), disk.toString (), this));
new DefaultAppleFileSource (getName (), disk.toString (), this));
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
@ -234,15 +233,15 @@ public abstract class AbstractFormattedDisk implements FormattedDisk
public String getDisplayPath () public String getDisplayPath ()
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
// if (originalPath != null)
// return originalPath.toString ();
String home = System.getProperty ("user.home"); String home = System.getProperty ("user.home");
String path = originalPath != null ? originalPath.toString () String path =
: disk.getFile ().getAbsolutePath (); originalPath != null ? originalPath.toString () : disk.getFile ().getAbsolutePath ();
if (path.startsWith (home))
return "~" + path.substring (home.length ()); int pos = path.indexOf (home);
if (pos == 0 || (path.startsWith ("/Volumes/") && pos > 0))
return "~" + path.substring (home.length () + pos);
return disk.getFile ().getAbsolutePath (); return disk.getFile ().getAbsolutePath ();
} }
@ -327,8 +326,7 @@ public abstract class AbstractFormattedDisk implements FormattedDisk
if (children != null) if (children != null)
while (children.hasMoreElements ()) while (children.hasMoreElements ())
{ {
DefaultMutableTreeNode childNode = DefaultMutableTreeNode childNode = (DefaultMutableTreeNode) children.nextElement ();
(DefaultMutableTreeNode) children.nextElement ();
if (childNode.getUserObject ().toString ().indexOf (name) > 0) if (childNode.getUserObject ().toString ().indexOf (name) > 0)
return childNode; return childNode;
} }

View File

@ -48,8 +48,8 @@ public class AppleDisk implements Disk
private int interleave = 0; private int interleave = 0;
private static int[][] interleaveSector = // private static int[][] interleaveSector = //
{ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, { { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, //
22, 23, 24, 25, 26, 27, 28, 29, 30, 31 }, // None 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 }, // None
{ 0, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 15 }, // Prodos/Pascal { 0, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 15 }, // Prodos/Pascal
{ 0, 13, 11, 9, 7, 5, 3, 1, 14, 12, 10, 8, 6, 4, 2, 15 }, // Infocom { 0, 13, 11, 9, 7, 5, 3, 1, 14, 12, 10, 8, 6, 4, 2, 15 }, // Infocom
{ 0, 6, 12, 3, 9, 15, 14, 5, 11, 2, 8, 7, 13, 4, 10, 1 } }; // CPM { 0, 6, 12, 3, 9, 15, 14, 5, 11, 2, 8, 7, 13, 4, 10, 1 } }; // CPM
@ -101,8 +101,7 @@ public class AppleDisk implements Disk
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
public AppleDisk (File file, int tracks, int sectors, int skip) public AppleDisk (File file, int tracks, int sectors, int skip) throws FileFormatException
throws FileFormatException
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
assert (file.exists ()) : "No such path :" + file.getAbsolutePath (); assert (file.exists ()) : "No such path :" + file.getAbsolutePath ();
@ -158,7 +157,7 @@ public class AppleDisk implements Disk
tracks = blocks / 8; // change parameter! tracks = blocks / 8; // change parameter!
sectors = 8; // change parameter! sectors = 8; // change parameter!
} }
else if (suffix.equalsIgnoreCase ("HDV") else if (suffix.equalsIgnoreCase ("HDV") //
|| (suffix.equalsIgnoreCase ("po") && tracks > 50)) // ULTIMATE APPLE1 CFFA 3.5.po || (suffix.equalsIgnoreCase ("po") && tracks > 50)) // ULTIMATE APPLE1 CFFA 3.5.po
{ {
//this.blocks = (int) file.length () / 4096 * 8; // reduce blocks to a multiple of 8 //this.blocks = (int) file.length () / 4096 * 8; // reduce blocks to a multiple of 8
@ -166,7 +165,7 @@ public class AppleDisk implements Disk
this.sectorSize = 512; this.sectorSize = 512;
this.trackSize = sectors * sectorSize; 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.blocks = tracks * sectors;
this.sectorSize = 512; this.sectorSize = 512;
@ -557,8 +556,7 @@ public class AppleDisk implements Disk
{ {
if (!isValidAddress (block)) if (!isValidAddress (block))
{ {
System.out.printf ("getDiskAddress: Invalid block : %d of %d%n", block, System.out.printf ("getDiskAddress: Invalid block : %d of %d%n", block, this.blocks);
this.blocks);
return null; return null;
// return new AppleDiskAddress (this, 0); // this was looping 26/07/2016 // return new AppleDiskAddress (this, 0); // this was looping 26/07/2016
} }
@ -624,10 +622,9 @@ public class AppleDisk implements Disk
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
assert da.getDisk () == this : "Disk address not applicable to this disk"; assert da.getDisk () == this : "Disk address not applicable to this disk";
assert sectorSize == SECTOR_SIZE assert sectorSize == SECTOR_SIZE || sectorSize == BLOCK_SIZE : "Invalid sector size : "
|| sectorSize == BLOCK_SIZE : "Invalid sector size : " + sectorSize; + sectorSize;
assert interleave >= 0 && interleave <= MAX_INTERLEAVE : "Invalid interleave : " assert interleave >= 0 && interleave <= MAX_INTERLEAVE : "Invalid interleave : " + interleave;
+ interleave;
if (sectorSize == SECTOR_SIZE) if (sectorSize == SECTOR_SIZE)
{ {
@ -640,8 +637,7 @@ public class AppleDisk implements Disk
System.arraycopy (diskBuffer, diskOffset, buffer, bufferOffset, SECTOR_SIZE); System.arraycopy (diskBuffer, diskOffset, buffer, bufferOffset, SECTOR_SIZE);
diskOffset = getBufferOffset (da, 1); diskOffset = getBufferOffset (da, 1);
System.arraycopy (diskBuffer, diskOffset, buffer, bufferOffset + SECTOR_SIZE, System.arraycopy (diskBuffer, diskOffset, buffer, bufferOffset + SECTOR_SIZE, SECTOR_SIZE);
SECTOR_SIZE);
} }
} }
@ -650,10 +646,9 @@ public class AppleDisk implements Disk
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
assert da.getDisk () == this : "Disk address not applicable to this disk"; assert da.getDisk () == this : "Disk address not applicable to this disk";
assert sectorSize == SECTOR_SIZE assert sectorSize == SECTOR_SIZE || sectorSize == BLOCK_SIZE : "Invalid sector size : "
|| sectorSize == BLOCK_SIZE : "Invalid sector size : " + sectorSize; + sectorSize;
assert interleave >= 0 && interleave <= MAX_INTERLEAVE : "Invalid interleave : " assert interleave >= 0 && interleave <= MAX_INTERLEAVE : "Invalid interleave : " + interleave;
+ interleave;
if (sectorSize == SECTOR_SIZE) if (sectorSize == SECTOR_SIZE)
{ {
@ -738,12 +733,8 @@ public class AppleDisk implements Disk
{ {
StringBuilder text = new StringBuilder (); StringBuilder text = new StringBuilder ();
String path = file.getAbsolutePath (); text.append (
String home = System.getProperty ("user.home"); String.format ("Path ......... %s%n", Utility.getShortPath (file.getAbsolutePath ())));
if (path.startsWith (home))
path = "~" + path.substring (home.length ());
text.append (String.format ("Path ......... %s%n", path));
text.append (String.format ("File name .... %s%n", file.getName ())); text.append (String.format ("File name .... %s%n", file.getName ()));
text.append (String.format ("File size .... %,d%n", file.length ())); text.append (String.format ("File size .... %,d%n", file.length ()));
text.append (String.format ("Tracks ....... %d%n", tracks)); text.append (String.format ("Tracks ....... %d%n", tracks));

View File

@ -148,7 +148,7 @@ public class DiskFactory
if ("sdk".equals (suffix) // NuFX disk if ("sdk".equals (suffix) // NuFX disk
|| "shk".equals (suffix) // NuFX files or disk || "shk".equals (suffix) // NuFX files or disk
|| "bxy".equals (suffix)) // NuFX in Binary2 || "bxy".equals (suffix)) // NuFX in Bin2
{ {
if (debug) if (debug)
System.out.println (" ** sdk/shk/bxy **"); System.out.println (" ** sdk/shk/bxy **");
@ -156,7 +156,11 @@ public class DiskFactory
{ {
nuFX = new NuFX (file.toPath ()); nuFX = new NuFX (file.toPath ());
if (nuFX.getTotalDisks () == 0 && nuFX.getTotalFiles () == 0) if (nuFX.getTotalDisks () == 0 && nuFX.getTotalFiles () == 0)
{
if (debug)
System.out.println ("Empty NuFX file");
return null; return null;
}
byte[] diskBuffer = nuFX.getDiskBuffer (); byte[] diskBuffer = nuFX.getDiskBuffer ();
if (diskBuffer == null) if (diskBuffer == null)
@ -173,7 +177,7 @@ public class DiskFactory
} }
catch (Exception e) catch (Exception e)
{ {
// e.printStackTrace (); // e.printStackTrace ();
if (e.getMessage () == null) if (e.getMessage () == null)
System.out.println (e); System.out.println (e);
else else
@ -183,10 +187,10 @@ public class DiskFactory
return null; return null;
} }
} }
else if ("bny".equals (suffix)) // Binary2 uncompressed files else if ("bny".equals (suffix) || "bqy".equals (suffix)) // Binary2 uncompressed files
{ {
if (debug) if (debug)
System.out.println (" ** bny **"); System.out.println (" ** bny/bqy **");
try try
{ {
binary2 = new Binary2 (file.toPath ()); binary2 = new Binary2 (file.toPath ());
@ -279,7 +283,7 @@ public class DiskFactory
} }
if (debug) if (debug)
System.out.printf (" Checking po or dsk hard drive: %,d%n", file.length ()); System.out.printf ("Checking po or dsk hard drive: %,d%n", file.length ());
disk = checkHardDisk (file); disk = checkHardDisk (file);
if (disk != null) if (disk != null)
@ -346,9 +350,10 @@ public class DiskFactory
{ {
if (debug) if (debug)
System.out.println (" --> PRODOS hard disk"); System.out.println (" --> PRODOS hard disk");
return new ProdosDisk (disk800); disk = new ProdosDisk (disk800);
} }
disk = new DataDisk (disk800); else
disk = new DataDisk (disk800);
} }
else else
{ {
@ -356,11 +361,15 @@ public class DiskFactory
disk = checkDos (appleDisk256); disk = checkDos (appleDisk256);
if (disk == null) if (disk == null)
disk = checkProdos (new AppleDisk (wozFile, 35, 8)); disk = checkProdos (new AppleDisk (wozFile, 35, 8));
if (disk == null)
disk = checkPascalDisk (new AppleDisk (wozFile, 35, 8));
if (disk == null) if (disk == null)
disk = new DataDisk (appleDisk256); disk = new DataDisk (appleDisk256);
} }
} }
disk.setOriginalPath (originalPath); // allow Save converted disk...
return disk; return disk;
} }
catch (Exception e) catch (Exception e)
@ -583,7 +592,7 @@ public class DiskFactory
private static FormattedDisk check (FormattedDisk disk) private static FormattedDisk check (FormattedDisk disk)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
if (disk.getDisk ()instanceof AppleDisk appleDisk) if (disk.getDisk () instanceof AppleDisk appleDisk)
{ {
if (nuFX != null) if (nuFX != null)
appleDisk.setNuFX (nuFX); appleDisk.setNuFX (nuFX);
@ -677,7 +686,7 @@ public class DiskFactory
{ {
if (debug) if (debug)
{ {
System.out.println ("\nChecking Prodos hard disk"); System.out.println ("\nChecking Prodos/Pascal hard disk");
System.out.printf ("Total blocks : %f%n", (float) file.length () / 512); System.out.printf ("Total blocks : %f%n", (float) file.length () / 512);
System.out.printf ("Total tracks : %f%n", (float) file.length () / 4096); System.out.printf ("Total tracks : %f%n", (float) file.length () / 4096);
System.out.printf ("File length : %d%n", file.length ()); System.out.printf ("File length : %d%n", file.length ());
@ -712,6 +721,7 @@ public class DiskFactory
System.out.println (" --> PRODOS hard disk"); System.out.println (" --> PRODOS hard disk");
return new ProdosDisk (disk); return new ProdosDisk (disk);
} }
if (PascalDisk.isCorrectFormat (disk, debug)) if (PascalDisk.isCorrectFormat (disk, debug))
{ {
if (debug) if (debug)
@ -727,7 +737,7 @@ public class DiskFactory
} }
if (debug) if (debug)
System.out.println (" not a Prodos hard disk\n"); System.out.println (" not a Prodos/Pascal hard disk\n");
return null; return null;
} }
@ -852,11 +862,16 @@ public class DiskFactory
if (Wizardry4BootDisk.isWizardryIVorV (disk, debug)) if (Wizardry4BootDisk.isWizardryIVorV (disk, debug))
{ {
if (debug)
System.out.println ("checking Wizardry IV or V");
String fileName = file.getAbsolutePath ().toLowerCase (); String fileName = file.getAbsolutePath ().toLowerCase ();
int pos = file.getAbsolutePath ().indexOf ('.'); int pos = fileName.lastIndexOf ('.');
char c = fileName.charAt (pos - 1); char c = fileName.charAt (pos - 1); // '1' (wiz4) or 'a' (wiz5)
// String suffix = fileName.substring (pos + 1); int requiredDisks = c == '1' ? 7 : c == 'a' ? 10 : 0;
int requiredDisks = c == '1' ? 6 : c == 'a' ? 10 : 0;
if (debug)
System.out.printf ("Required disks: %d%n", requiredDisks);
if (requiredDisks > 0) if (requiredDisks > 0)
{ {
@ -877,7 +892,7 @@ public class DiskFactory
} }
} }
if (debug) 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); PascalDisk pascalDisk = new PascalDisk (disk);
return pascalDisk; return pascalDisk;
@ -887,6 +902,9 @@ public class DiskFactory
private static boolean collectDataDisks (String fileName, int dotPos, AppleDisk[] disks) private static boolean collectDataDisks (String fileName, int dotPos, AppleDisk[] disks)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
if (debug)
System.out.println ("Collecting Wizardry disks");
char c = fileName.charAt (dotPos - 1); char c = fileName.charAt (dotPos - 1);
String suffix = fileName.substring (dotPos + 1); String suffix = fileName.substring (dotPos + 1);
@ -894,14 +912,16 @@ public class DiskFactory
{ {
String old = new String (c + "." + suffix); String old = new String (c + "." + suffix);
String rep = new String ((char) (c + i - 1) + "." + suffix); String rep = new String ((char) (c + i - 1) + "." + suffix);
File f = new File (fileName.replace (old, rep)); File f = new File (fileName.replace (old, rep));
if (debug)
System.out.println (f);
if (!f.exists () || !f.isFile ()) if (!f.exists () || !f.isFile ())
return false; return false;
AppleDisk dataDisk = new AppleDisk (f, 35, 8); disks[i] = new AppleDisk (f, 35, 8);
dataDisk.setInterleave (1); disks[i].setInterleave (1);
disks[i] = dataDisk;
} }
return true; return true;

View File

@ -51,6 +51,9 @@ public class Prefix2mg
if (format == 0 && flagsVolume == 0) if (format == 0 && flagsVolume == 0)
flagsVolume = 254; flagsVolume = 254;
if (length == 0)
length = 512 * blocks;
// see /Asimov disks/images/gs/os/prodos16/ProDOS 16v1_3.2mg // see /Asimov disks/images/gs/os/prodos16/ProDOS 16v1_3.2mg
// System.out.println (this); // System.out.println (this);
} }

View File

@ -89,8 +89,8 @@ abstract class AbstractCatalogEntry implements AppleFileSource
lastModified = Utility.getDateTime (entryBuffer, 0x1B); lastModified = Utility.getDateTime (entryBuffer, 0x1B);
// CATALOG command only formats the LO byte - see Beneath Apple DOS pp4-6 // CATALOG command only formats the LO byte - see Beneath Apple DOS pp4-6
String base = String.format ("%s%s %03d ", locked ? "*" : " ", getFileType (), String base =
reportedSize & 0xFF); String.format ("%s%s %03d ", locked ? "*" : " ", getFileType (), reportedSize & 0xFF);
catalogName = getName (base, entryBuffer); catalogName = getName (base, entryBuffer);
displayName = getDisplayName (entryBuffer); displayName = getDisplayName (entryBuffer);
} }
@ -235,18 +235,28 @@ abstract class AbstractCatalogEntry implements AppleFileSource
case IntegerBasic: case IntegerBasic:
reportedLength = Utility.getShort (buffer, 0); reportedLength = Utility.getShort (buffer, 0);
exactBuffer = new byte[reportedLength]; if (reportedLength > 0)
System.arraycopy (buffer, 2, exactBuffer, 0, reportedLength); {
appleFile = new IntegerBasicProgram (name, exactBuffer); exactBuffer = new byte[reportedLength];
System.arraycopy (buffer, 2, exactBuffer, 0, reportedLength);
appleFile = new IntegerBasicProgram (name, exactBuffer);
}
else
appleFile = new DefaultAppleFile (name, buffer);
break; break;
case ApplesoftBasic: case ApplesoftBasic:
reportedLength = Utility.getShort (buffer, 0); reportedLength = Utility.getShort (buffer, 0);
exactBuffer = new byte[reportedLength]; if (reportedLength > 0)
if (reportedLength > buffer.length) {
reportedLength = buffer.length - 2; exactBuffer = new byte[reportedLength];
System.arraycopy (buffer, 2, exactBuffer, 0, reportedLength); if (reportedLength > buffer.length)
appleFile = new ApplesoftBasicProgram (name, exactBuffer); reportedLength = buffer.length - 2;
System.arraycopy (buffer, 2, exactBuffer, 0, reportedLength);
appleFile = new ApplesoftBasicProgram (name, exactBuffer);
}
else
appleFile = new DefaultAppleFile (name, buffer);
break; break;
case Binary: // binary file case Binary: // binary file
@ -256,8 +266,8 @@ abstract class AbstractCatalogEntry implements AppleFileSource
reportedLength = Utility.getShort (buffer, 2); reportedLength = Utility.getShort (buffer, 2);
if (reportedLength == 0) if (reportedLength == 0)
{ {
System.out.println (name.trim () + " reported length : 0 - reverting to " System.out.println (
+ (buffer.length - 4)); name.trim () + " reported length : 0 - reverting to " + (buffer.length - 4));
reportedLength = buffer.length - 4; reportedLength = buffer.length - 4;
} }
@ -268,9 +278,8 @@ abstract class AbstractCatalogEntry implements AppleFileSource
exactBuffer = new byte[buffer.length - 4]; // reported length is too long exactBuffer = new byte[buffer.length - 4]; // reported length is too long
System.arraycopy (buffer, 4, exactBuffer, 0, exactBuffer.length); System.arraycopy (buffer, 4, exactBuffer, 0, exactBuffer.length);
if ((name.endsWith (".FONT") || name.endsWith (" FONT") if ((name.endsWith (".FONT") || name.endsWith (" FONT") || name.endsWith (".SET")
|| name.endsWith (".SET") || name.startsWith ("ASCII.")) || name.startsWith ("ASCII.")) && FontFile.isFont (exactBuffer))
&& FontFile.isFont (exactBuffer))
appleFile = new FontFile (name, exactBuffer, loadAddress); appleFile = new FontFile (name, exactBuffer, loadAddress);
else if (name.endsWith (".MW")) else if (name.endsWith (".MW"))
appleFile = new MagicWindowText (name, exactBuffer); appleFile = new MagicWindowText (name, exactBuffer);
@ -305,8 +314,7 @@ abstract class AbstractCatalogEntry implements AppleFileSource
appleFile = new AssemblerProgram (name, exactBuffer, loadAddress); appleFile = new AssemblerProgram (name, exactBuffer, loadAddress);
} }
else if (reportedLength == 0x240 // else if (reportedLength == 0x240 //
&& (loadAddress == 0x5800 || loadAddress == 0x6000 && (loadAddress == 0x5800 || loadAddress == 0x6000 || loadAddress == 0x7800))
|| loadAddress == 0x7800))
appleFile = new PrintShopGraphic (name, exactBuffer); appleFile = new PrintShopGraphic (name, exactBuffer);
else if (isRunCommand (exactBuffer)) else if (isRunCommand (exactBuffer))
{ {
@ -319,8 +327,8 @@ abstract class AbstractCatalogEntry implements AppleFileSource
{ {
appleFile = new AssemblerProgram (name, exactBuffer, loadAddress); appleFile = new AssemblerProgram (name, exactBuffer, loadAddress);
if ((exactBuffer.length + 4) < buffer.length) if ((exactBuffer.length + 4) < buffer.length)
((AssemblerProgram) appleFile).setExtraBuffer (buffer, ((AssemblerProgram) appleFile).setExtraBuffer (buffer, exactBuffer.length + 4,
exactBuffer.length + 4, buffer.length - (exactBuffer.length + 4)); buffer.length - (exactBuffer.length + 4));
} }
break; break;
@ -362,8 +370,8 @@ abstract class AbstractCatalogEntry implements AppleFileSource
int reportedLength = Utility.getShort (buffer, 2); int reportedLength = Utility.getShort (buffer, 2);
if (reportedLength == 0) if (reportedLength == 0)
{ {
System.out.println ( System.out
name.trim () + " reported length : 0 - reverting to " + (buffer.length - 4)); .println (name.trim () + " reported length : 0 - reverting to " + (buffer.length - 4));
reportedLength = buffer.length - 4; reportedLength = buffer.length - 4;
} }

View File

@ -326,6 +326,8 @@ public class DosDisk extends AbstractFormattedDisk
return "4.2"; return "4.2";
case 0x43: case 0x43:
return "4.3"; return "4.3";
case 0x45:
return "4.5";
default: default:
return "??"; return "??";
} }
@ -376,7 +378,7 @@ public class DosDisk extends AbstractFormattedDisk
int version = buffer[3] & 0xFF; int version = buffer[3] & 0xFF;
if (debug) if (debug)
System.out.printf ("Version: %02X%n", buffer[3]); System.out.printf ("Version: %02X%n", buffer[3]);
if (version == 0 || (version > 0x43 && version != 0xFF)) if (version == 0 || (version > 0x45 && version != 0xFF))
{ {
if (debug) if (debug)
System.out.printf ("Bad version : %02X%n", version); System.out.printf ("Bad version : %02X%n", version);

View File

@ -15,27 +15,21 @@ import com.bytezone.diskbrowser.utilities.DefaultAction;
public abstract class AbstractSaveAction extends DefaultAction public abstract class AbstractSaveAction extends DefaultAction
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
{ {
private JFileChooser fileChooser; protected JFileChooser fileChooser = new JFileChooser ();
private String dialogTitle;
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
public AbstractSaveAction (String menuText, String tip, String dialogTitle) public AbstractSaveAction (String menuText, String tip, String dialogTitle)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
super (menuText, tip); super (menuText, tip);
this.dialogTitle = dialogTitle;
fileChooser.setDialogTitle (dialogTitle);
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
void setSelectedFile (File file) void setSelectedFile (File file)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
if (fileChooser == null)
{
fileChooser = new JFileChooser ();
fileChooser.setDialogTitle (dialogTitle);
}
fileChooser.setSelectedFile (file); fileChooser.setSelectedFile (file);
} }
@ -43,26 +37,22 @@ public abstract class AbstractSaveAction extends DefaultAction
void saveBuffer (byte[] buffer) void saveBuffer (byte[] buffer)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
if (fileChooser.showSaveDialog (null) != JFileChooser.APPROVE_OPTION)
return;
File file = fileChooser.getSelectedFile (); File file = fileChooser.getSelectedFile ();
try try
{ {
Files.write (file.toPath (), buffer, StandardOpenOption.CREATE_NEW); Files.write (file.toPath (), buffer, StandardOpenOption.CREATE_NEW);
JOptionPane.showMessageDialog (null, JOptionPane.showMessageDialog (null, String.format ("File %s saved", file.getName ()));
String.format ("File %s saved", file.getName ()));
} }
catch (FileAlreadyExistsException e) catch (FileAlreadyExistsException e)
{ {
JOptionPane.showMessageDialog (null, "File " + file.getName () + " already exists", JOptionPane.showMessageDialog (null, "File " + file.getName () + " already exists", "Failed",
"Failed", JOptionPane.ERROR_MESSAGE); JOptionPane.ERROR_MESSAGE);
} }
catch (IOException e) catch (IOException e)
{ {
e.printStackTrace (); e.printStackTrace ();
JOptionPane.showMessageDialog (null, "File failed to save - " + e.getMessage (), JOptionPane.showMessageDialog (null, "File failed to save - " + e.getMessage (), "Failed",
"Failed", JOptionPane.ERROR_MESSAGE); JOptionPane.ERROR_MESSAGE);
} }
} }
} }

View File

@ -36,6 +36,7 @@ public class FontAction extends DefaultAction implements QuitListener
{ {
super ("Set Font...", "Set display to a different font or font size", super ("Set Font...", "Set display to a different font or font size",
"/com/bytezone/loadlister/"); "/com/bytezone/loadlister/");
int mask = Toolkit.getDefaultToolkit ().getMenuShortcutKeyMaskEx (); int mask = Toolkit.getDefaultToolkit ().getMenuShortcutKeyMaskEx ();
putValue (Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke (KeyEvent.VK_F, mask)); putValue (Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke (KeyEvent.VK_F, mask));
} }
@ -146,8 +147,7 @@ public class FontAction extends DefaultAction implements QuitListener
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
FontChangeEvent fontChangeEvent = new FontChangeEvent (font); FontChangeEvent fontChangeEvent = new FontChangeEvent (font);
FontChangeListener[] listeners = FontChangeListener[] listeners = (listenerList.getListeners (FontChangeListener.class));
(listenerList.getListeners (FontChangeListener.class));
for (FontChangeListener listener : listeners) for (FontChangeListener listener : listeners)
listener.changeFont (fontChangeEvent); listener.changeFont (fontChangeEvent);
} }

View File

@ -33,6 +33,7 @@ import com.bytezone.diskbrowser.disk.DiskAddress;
import com.bytezone.diskbrowser.disk.SectorList; import com.bytezone.diskbrowser.disk.SectorList;
import com.bytezone.diskbrowser.gui.FontAction.FontChangeEvent; import com.bytezone.diskbrowser.gui.FontAction.FontChangeEvent;
import com.bytezone.diskbrowser.gui.FontAction.FontChangeListener; import com.bytezone.diskbrowser.gui.FontAction.FontChangeListener;
import com.bytezone.diskbrowser.wizardry.MazeLevel;
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
public class OutputPanel extends JTabbedPane public class OutputPanel extends JTabbedPane
@ -86,8 +87,7 @@ public class OutputPanel extends JTabbedPane
formattedText.setText ("Please use the 'File->Set HOME folder...' command to " formattedText.setText ("Please use the 'File->Set HOME folder...' command to "
+ "\ntell DiskBrowser where your Apple disks are located." + "\ntell DiskBrowser where your Apple disks are located."
+ "\n\nTo see the contents of a disk in more detail, double-click" + "\n\nTo see the contents of a disk in more detail, double-click"
+ "\nthe disk. You will then be able to select individual files to " + "\nthe disk. You will then be able to select individual files to " + "view them.");
+ "view them.");
hexText = new JTextArea (10, TEXT_WIDTH); hexText = new JTextArea (10, TEXT_WIDTH);
setPanel (hexText, "Hex dump"); setPanel (hexText, "Hex dump");
@ -95,9 +95,8 @@ public class OutputPanel extends JTabbedPane
disassemblyText = new JTextArea (10, TEXT_WIDTH); disassemblyText = new JTextArea (10, TEXT_WIDTH);
setPanel (disassemblyText, "Disassembly"); setPanel (disassemblyText, "Disassembly");
imagePane = imagePane = new JScrollPane (imagePanel, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
new JScrollPane (imagePanel, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
imagePane.setBorder (null); imagePane.setBorder (null);
@ -272,9 +271,10 @@ public class OutputPanel extends JTabbedPane
AbstractFile.setDebug (value); AbstractFile.setDebug (value);
setText (formattedText, currentDataSource.getText ()); setText (formattedText, currentDataSource.getText ());
if (currentDataSource instanceof HiResImage if (currentDataSource instanceof HiResImage //
|| currentDataSource instanceof MazeLevel // Wizardry
|| currentDataSource instanceof QuickDrawFont) || currentDataSource instanceof QuickDrawFont)
setDataSource (currentDataSource); // toggles text/image setDataSource (currentDataSource); // toggles text/image
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
@ -493,8 +493,7 @@ public class OutputPanel extends JTabbedPane
public void setAssemblerPreferences (AssemblerPreferences assemblerPreferences) public void setAssemblerPreferences (AssemblerPreferences assemblerPreferences)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
if (currentDataSource instanceof AssemblerProgram if (currentDataSource instanceof AssemblerProgram || currentDataSource instanceof BootSector)
|| currentDataSource instanceof BootSector)
setDataSource (currentDataSource); setDataSource (currentDataSource);
} }

View File

@ -3,6 +3,7 @@ package com.bytezone.diskbrowser.gui;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.io.File; import java.io.File;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane; import javax.swing.JOptionPane;
import com.bytezone.diskbrowser.disk.AppleDisk; import com.bytezone.diskbrowser.disk.AppleDisk;
@ -40,7 +41,9 @@ class SaveDiskAction extends AbstractSaveAction implements DiskSelectionListener
String suffix = blocks <= 560 ? ".dsk" : ".hdv"; String suffix = blocks <= 560 ? ".dsk" : ".hdv";
setSelectedFile (new File (formattedDisk.getName () + suffix)); setSelectedFile (new File (formattedDisk.getName () + suffix));
saveBuffer (appleDisk.getBuffer ());
if (fileChooser.showSaveDialog (null) == JFileChooser.APPROVE_OPTION)
saveBuffer (appleDisk.getBuffer ());
} }
else else
System.out.println ("Not an AppleDisk"); // impossible System.out.println ("Not an AppleDisk"); // impossible

View File

@ -1,9 +1,15 @@
package com.bytezone.diskbrowser.gui; package com.bytezone.diskbrowser.gui;
import java.awt.Toolkit;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.io.File; import java.io.File;
import javax.swing.Action;
import javax.swing.JCheckBox;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane; import javax.swing.JOptionPane;
import javax.swing.KeyStroke;
import com.bytezone.diskbrowser.applefile.AppleFileSource; import com.bytezone.diskbrowser.applefile.AppleFileSource;
@ -12,12 +18,17 @@ class SaveFileAction extends AbstractSaveAction implements FileSelectionListener
//-----------------------------------------------------------------------------------// //-----------------------------------------------------------------------------------//
{ {
AppleFileSource appleFileSource; AppleFileSource appleFileSource;
private JCheckBox formatted = new JCheckBox ("Formatted");
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
SaveFileAction () SaveFileAction ()
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
super ("Save file...", "Save currently selected file", "Save File"); super ("Save file...", "Save currently selected file", "Save File");
fileChooser.setAccessory (formatted);
int mask = Toolkit.getDefaultToolkit ().getMenuShortcutKeyMaskEx ();
putValue (Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke (KeyEvent.VK_S, mask));
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
@ -31,8 +42,18 @@ class SaveFileAction extends AbstractSaveAction implements FileSelectionListener
return; return;
} }
setSelectedFile (new File (appleFileSource.getUniqueName () + ".bin")); if (formatted.isSelected ())
saveBuffer (appleFileSource.getDataSource ().getBuffer ()); setSelectedFile (new File (appleFileSource.getUniqueName () + ".txt"));
else
setSelectedFile (new File (appleFileSource.getUniqueName () + ".bin"));
if (fileChooser.showSaveDialog (null) != JFileChooser.APPROVE_OPTION)
return;
if (formatted.isSelected ())
saveBuffer (appleFileSource.getDataSource ().getText ().getBytes ());
else
saveBuffer (appleFileSource.getDataSource ().getBuffer ());
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
@ -41,8 +62,8 @@ class SaveFileAction extends AbstractSaveAction implements FileSelectionListener
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
this.appleFileSource = event.appleFileSource; this.appleFileSource = event.appleFileSource;
setEnabled (
event.appleFileSource != null && event.appleFileSource.getDataSource () != null setEnabled (appleFileSource != null && appleFileSource.getDataSource () != null
&& event.appleFileSource.getDataSource ().getBuffer () != null); && appleFileSource.getDataSource ().getBuffer () != null);
} }
} }

View File

@ -4,6 +4,7 @@ import java.awt.event.ActionEvent;
import java.io.File; import java.io.File;
import java.util.List; import java.util.List;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane; import javax.swing.JOptionPane;
import com.bytezone.diskbrowser.disk.Disk; import com.bytezone.diskbrowser.disk.Disk;
@ -41,7 +42,9 @@ class SaveSectorsAction extends AbstractSaveAction implements SectorSelectionLis
blocks.size () == 1 ? disk.readBlock (blocks.get (0)) : disk.readBlocks (blocks); blocks.size () == 1 ? disk.readBlock (blocks.get (0)) : disk.readBlocks (blocks);
setSelectedFile (new File ("SavedSectors.bin")); setSelectedFile (new File ("SavedSectors.bin"));
saveBuffer (buffer);
if (fileChooser.showSaveDialog (null) == JFileChooser.APPROVE_OPTION)
saveBuffer (buffer);
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//

View File

@ -15,10 +15,8 @@ import com.bytezone.diskbrowser.utilities.Utility;
public class WozFile public class WozFile
//-----------------------------------------------------------------------------------// //-----------------------------------------------------------------------------------//
{ {
private static final byte[] address16prologue = private static final byte[] address16prologue = { (byte) 0xD5, (byte) 0xAA, (byte) 0x96 };
{ (byte) 0xD5, (byte) 0xAA, (byte) 0x96 }; private static final byte[] address13prologue = { (byte) 0xD5, (byte) 0xAA, (byte) 0xB5 };
private static final byte[] address13prologue =
{ (byte) 0xD5, (byte) 0xAA, (byte) 0xB5 };
private static final byte[] dataPrologue = { (byte) 0xD5, (byte) 0xAA, (byte) 0xAD }; private static final byte[] dataPrologue = { (byte) 0xD5, (byte) 0xAA, (byte) 0xAD };
private static final byte[] epilogue = { (byte) 0xDE, (byte) 0xAA, (byte) 0xEB }; private static final byte[] epilogue = { (byte) 0xDE, (byte) 0xAA, (byte) 0xEB };
// apparently it can be DE AA Ex // apparently it can be DE AA Ex
@ -29,9 +27,9 @@ public class WozFile
private static final int TRK_SIZE = 0x1A00; private static final int TRK_SIZE = 0x1A00;
private static final int DATA_SIZE = TRK_SIZE - 10; private static final int DATA_SIZE = TRK_SIZE - 10;
private static int[][] interleave = private static int[][] interleave = //
{ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, // 13 sector { { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, // 13 sector
{ 0, 7, 14, 6, 13, 5, 12, 4, 11, 3, 10, 2, 9, 1, 8, 15 } }; // 16 sector { 0, 7, 14, 6, 13, 5, 12, 4, 11, 3, 10, 2, 9, 1, 8, 15 } }; // 16 sector
public final File file; public final File file;
@ -146,8 +144,7 @@ public class WozFile
{ {
if (info != null) if (info != null)
System.out.println (info); System.out.println (info);
throw new DiskNibbleException ( throw new DiskNibbleException (String.format ("Invalid chunk name character: %02X%n", val));
String.format ("Invalid chunk name character: %02X%n", val));
} }
} }
@ -302,9 +299,9 @@ public class WozFile
String wozBase2 = home + "Dropbox/Examples/woz test images/WOZ 2.0/"; String wozBase2 = home + "Dropbox/Examples/woz test images/WOZ 2.0/";
String wozBase3 = home + "Dropbox/Examples/woz test images/WOZ 2.0/3.5/"; String wozBase3 = home + "Dropbox/Examples/woz test images/WOZ 2.0/3.5/";
File[] files = { new File (home + "code/python/wozardry-2.0/bill.woz"), File[] files = { new File (home + "code/python/wozardry-2.0/bill.woz"),
new File (wozBase2 + "DOS 3.3 System Master.woz"), new File (wozBase2 + "DOS 3.3 System Master.woz"),
new File (wozBase1 + "DOS 3.3 System Master.woz"), new File (wozBase1 + "DOS 3.3 System Master.woz"),
new File (wozBase3 + "Apple IIgs System Disk 1.1.woz") }; new File (wozBase3 + "Apple IIgs System Disk 1.1.woz") };
try try
{ {
new WozFile (files[3]); new WozFile (files[3]);
@ -369,8 +366,7 @@ public class WozFile
String diskTypeText = diskType == 1 ? "5.25" : "3.5"; String diskTypeText = diskType == 1 ? "5.25" : "3.5";
text.append (String.format ("Version ............. %d%n", wozVersion)); text.append (String.format ("Version ............. %d%n", wozVersion));
text.append ( text.append (String.format ("Disk type ........... %d (%s\")%n", diskType, diskTypeText));
String.format ("Disk type ........... %d (%s\")%n", diskType, diskTypeText));
text.append (String.format ("Write protected ..... %d%n", writeProtected)); text.append (String.format ("Write protected ..... %d%n", writeProtected));
text.append (String.format ("Synchronized ........ %d%n", synchronised)); text.append (String.format ("Synchronized ........ %d%n", synchronised));
text.append (String.format ("Cleaned ............. %d%n", cleaned)); text.append (String.format ("Cleaned ............. %d%n", cleaned));
@ -378,9 +374,8 @@ public class WozFile
if (wozVersion > 1) if (wozVersion > 1)
{ {
String bootSectorFormatText = String bootSectorFormatText = bootSectorFormat == 0 ? "Unknown"
bootSectorFormat == 0 ? "Unknown" : bootSectorFormat == 1 ? "16 sector" : bootSectorFormat == 1 ? "16 sector" : bootSectorFormat == 2 ? "13 sector" : "Hybrid";
: bootSectorFormat == 2 ? "13 sector" : "Hybrid";
text.append (String.format ("%nSides ............... %d%n", sides)); text.append (String.format ("%nSides ............... %d%n", sides));
text.append (String.format ("Boot sector format .. %d (%s)%n", bootSectorFormat, text.append (String.format ("Boot sector format .. %d (%s)%n", bootSectorFormat,
@ -468,8 +463,7 @@ public class WozFile
bitCount = val16 (rawBuffer, ptr + DATA_SIZE + 2); bitCount = val16 (rawBuffer, ptr + DATA_SIZE + 2);
if (debug1) if (debug1)
System.out.println ( System.out.println ((String.format ("Bytes: %2d, Bits: %,8d%n%n", bytesUsed, bitCount)));
(String.format ("Bytes: %2d, Bits: %,8d%n%n", bytesUsed, bitCount)));
} }
else else
{ {
@ -612,10 +606,8 @@ public class WozFile
for (Sector sector : sectors) for (Sector sector : sectors)
if (sector.dataOffset > 0) if (sector.dataOffset > 0)
{ {
byte[] decodedBuffer = byte[] decodedBuffer = diskReader.decodeSector (newBuffer, sector.dataOffset + 3);
diskReader.decodeSector (newBuffer, sector.dataOffset + 3); int ptr = SECTOR_SIZE * (sector.trackNo * diskSectors + interleave[ndx][sector.sectorNo]);
int ptr = SECTOR_SIZE
* (sector.trackNo * diskSectors + interleave[ndx][sector.sectorNo]);
System.arraycopy (decodedBuffer, 0, diskBuffer, ptr, decodedBuffer.length); System.arraycopy (decodedBuffer, 0, diskBuffer, ptr, decodedBuffer.length);
} }
} }
@ -627,8 +619,7 @@ public class WozFile
{ {
StringBuilder text = new StringBuilder (); StringBuilder text = new StringBuilder ();
if (info.wozVersion == 1) if (info.wozVersion == 1)
text.append ( text.append (String.format ("WOZ1: Bytes: %2d, Bits: %,8d%n%n", bytesUsed, bitCount));
String.format ("WOZ1: Bytes: %2d, Bits: %,8d%n%n", bytesUsed, bitCount));
else else
text.append (String.format ("WOZ2: Start: %4d, Blocks: %2d, Bits: %,8d%n%n", text.append (String.format ("WOZ2: Start: %4d, Blocks: %2d, Bits: %,8d%n%n",
startingBlock, blockCount, bitCount)); startingBlock, blockCount, bitCount));
@ -728,9 +719,8 @@ public class WozFile
String fld = info.diskType == 1 ? "Vol" : info.diskType == 2 ? "Sde" : "???"; String fld = info.diskType == 1 ? "Vol" : info.diskType == 2 ? "Sde" : "???";
String dataOffsetText = dataOffset < 0 ? "" : String.format ("%04X", dataOffset); String dataOffsetText = dataOffset < 0 ? "" : String.format ("%04X", dataOffset);
return String.format ( return String.format ("%s: %02X Trk: %02X Sct: %02X Chk: %02X Add: %04X Dat: %s", fld,
"%s: %02X Trk: %02X Sct: %02X Chk: %02X Add: %04X Dat: %s", fld, volume, volume, trackNo, sectorNo, checksum, addressOffset, dataOffsetText);
trackNo, sectorNo, checksum, addressOffset, dataOffsetText);
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//

View File

@ -10,6 +10,7 @@ import com.bytezone.diskbrowser.prodos.write.DiskFullException;
import com.bytezone.diskbrowser.prodos.write.FileAlreadyExistsException; import com.bytezone.diskbrowser.prodos.write.FileAlreadyExistsException;
import com.bytezone.diskbrowser.prodos.write.ProdosDisk; import com.bytezone.diskbrowser.prodos.write.ProdosDisk;
import com.bytezone.diskbrowser.prodos.write.VolumeCatalogFullException; import com.bytezone.diskbrowser.prodos.write.VolumeCatalogFullException;
import com.bytezone.diskbrowser.utilities.Utility;
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
public class Binary2 public class Binary2
@ -19,11 +20,11 @@ public class Binary2
"------------------------------------------------------" "------------------------------------------------------"
+ "-----------------------"; + "-----------------------";
Binary2Header binary2Header; private Binary2Header binary2Header;
byte[] buffer; private byte[] buffer;
List<Binary2Header> headers = new ArrayList<> (); private List<Binary2Header> headers = new ArrayList<> ();
int totalBlocks; private int totalBlocks;
String fileName; private String fileName;
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
public Binary2 (Path path) throws IOException public Binary2 (Path path) throws IOException
@ -43,13 +44,14 @@ public class Binary2
do do
{ {
binary2Header = new Binary2Header (buffer, ptr); binary2Header = new Binary2Header (buffer, ptr);
System.out.println (binary2Header);
headers.add (binary2Header); ptr += ((binary2Header.eof - 1) / 128 + 2) * 128;
if (ptr > buffer.length) // not enough blocks for this file
break;
totalBlocks += binary2Header.totalBlocks; totalBlocks += binary2Header.totalBlocks;
ptr += ((binary2Header.eof - 1) / 128 + 1) * 128 + 128; headers.add (binary2Header);
} while (binary2Header.filesToFollow > 0); } while (binary2Header.filesToFollow > 0);
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
@ -64,9 +66,19 @@ public class Binary2
byte[] dataBuffer = new byte[header.eof]; // this sux byte[] dataBuffer = new byte[header.eof]; // this sux
System.arraycopy (buffer, header.ptr + 128, dataBuffer, 0, dataBuffer.length); System.arraycopy (buffer, header.ptr + 128, dataBuffer, 0, dataBuffer.length);
disk.addFile (header.fileName, header.fileType, header.auxType, header.created, if (header.compressed && dataBuffer[0] == 0x76 && dataBuffer[1] == (byte) 0xFF)
header.modified, dataBuffer, header.eof); {
String name = Utility.getCString (dataBuffer, 4);
Squeeze squeeze = new Squeeze ();
byte[] tmp = squeeze.unSqueeze (dataBuffer);
disk.addFile (name, header.fileType, header.auxType, header.created,
header.modified, tmp, tmp.length);
}
else
disk.addFile (header.fileName, header.fileType, header.auxType, header.created,
header.modified, dataBuffer, header.eof);
} }
disk.close (); disk.close ();

View File

@ -14,10 +14,9 @@ public class Binary2Header
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
{ {
static DateTimeFormatter formatter = DateTimeFormatter.ofPattern ("dd-LLL-yy HH:mm"); static DateTimeFormatter formatter = DateTimeFormatter.ofPattern ("dd-LLL-yy HH:mm");
static String[] osTypes = static String[] osTypes = { "Prodos", "DOS 3.3", "Reserved", "DOS 3.2 or 3.1", "Pascal",
{ "Prodos", "DOS 3.3", "Reserved", "DOS 3.2 or 3.1", "Pascal", "Macintosh MFS", "Macintosh MFS", "Macintosh HFS", "Lisa", "CPM", "Reserved", "MS-DOS", "High Sierra (CD-ROM)",
"Macintosh HFS", "Lisa", "CPM", "Reserved", "MS-DOS", "High Sierra (CD-ROM)", "ISO 9660 (CD-ROM)", "AppleShare" };
"ISO 9660 (CD-ROM)", "AppleShare" };
int ptr; int ptr;
byte[] buffer; byte[] buffer;
@ -89,8 +88,8 @@ public class Binary2Header
public String getLine () public String getLine ()
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
return String.format (" %-33s %3s $%04X %s unc %7d", fileName, return String.format (" %-33s %3s $%04X %s unc %7d", fileName, fileTypes[fileType],
fileTypes[fileType], auxType, modified.format (formatter), eof); auxType, modified.format (formatter), eof);
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
@ -117,12 +116,13 @@ public class Binary2Header
text.append (String.format ("Prodos storage type ... %02X%n", prodos16storageType)); text.append (String.format ("Prodos storage type ... %02X%n", prodos16storageType));
text.append (String.format ("Prodos total blocks ... %02X%n", prodos16totalBlocks)); text.append (String.format ("Prodos total blocks ... %02X%n", prodos16totalBlocks));
text.append (String.format ("Prodos eof ............ %06X %<,d%n", prodos16eof)); text.append (String.format ("Prodos eof ............ %06X %<,d%n", prodos16eof));
text.append ( text.append (String.format ("Disk space needed ..... %08X %<,d%n", diskSpaceRequired));
String.format ("Disk space needed ..... %08X %<,d%n", diskSpaceRequired)); text.append (String.format ("OS type ............... %02X %s%n", osType, osTypes[osType]));
text.append (
String.format ("OS type ............... %02X %s%n", osType, osTypes[osType]));
text.append (String.format ("Native file type ...... %02X%n", nativeFileType)); text.append (String.format ("Native file type ...... %02X%n", nativeFileType));
text.append (String.format ("Data flags ............ %02X%n", dataFlags)); text.append (String.format ("Data flags ............ %02X%n", dataFlags));
text.append (String.format (" compressed .......... %s%n", compressed));
text.append (String.format (" encrypted ........... %s%n", encrypted));
text.append (String.format (" sparse .............. %s%n", sparsePacked));
text.append (String.format ("Version ............... %02X%n", version)); text.append (String.format ("Version ............... %02X%n", version));
text.append (String.format ("Following files ....... %02X%n", filesToFollow)); text.append (String.format ("Following files ....... %02X%n", filesToFollow));

View File

@ -9,8 +9,7 @@ import com.bytezone.diskbrowser.utilities.Utility;
public class MasterHeader public class MasterHeader
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
{ {
private static final byte[] NuFile = private static final byte[] NuFile = { 0x4E, (byte) 0xF5, 0x46, (byte) 0xE9, 0x6C, (byte) 0xE5 };
{ 0x4E, (byte) 0xF5, 0x46, (byte) 0xE9, 0x6C, (byte) 0xE5 };
private static final byte[] BIN2 = { 0x0A, 0x47, 0x4C }; private static final byte[] BIN2 = { 0x0A, 0x47, 0x4C };
private final int crc; private final int crc;
@ -35,15 +34,6 @@ public class MasterHeader
if (Utility.isMagic (buffer, ptr, NuFile)) if (Utility.isMagic (buffer, ptr, NuFile))
break; break;
// internet.shk has 0x2000 bytes of text at the start
// if (Utility.isMagic (buffer, 0x2000, NuFile))
// {
// System.out.println ("found it");
// ptr = 0x2000;
// bin2 = true;
// break;
// }
if (isBin2 (buffer, ptr)) if (isBin2 (buffer, ptr))
{ {
binary2Header = new Binary2Header (buffer, 0); binary2Header = new Binary2Header (buffer, 0);

View File

@ -40,6 +40,7 @@ public class NuFX
{ {
buffer = Files.readAllBytes (path); buffer = Files.readAllBytes (path);
volumeName = new VolumeName (path.getFileName ().toString ()); volumeName = new VolumeName (path.getFileName ().toString ());
read (buffer); read (buffer);
} }
@ -95,6 +96,7 @@ public class NuFX
if (record.hasDisk ()) if (record.hasDisk ())
++totalDisks; ++totalDisks;
} }
// System.out.println (toString ());
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//

View File

@ -15,13 +15,12 @@ class Record
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
{ {
private static final byte[] NuFX = { 0x4E, (byte) 0xF5, 0x46, (byte) 0xD8 }; private static final byte[] NuFX = { 0x4E, (byte) 0xF5, 0x46, (byte) 0xD8 };
private static String[] fileSystems = private static String[] fileSystems = { "", "ProDOS/SOS", "DOS 3.3", "DOS 3.2",
{ "", "ProDOS/SOS", "DOS 3.3", "DOS 3.2", "Apple II Pascal", "Macintosh HFS", "Apple II Pascal", "Macintosh HFS", "Macintosh MFS", "Lisa File System",
"Macintosh MFS", "Lisa File System", "Apple CP/M", "", "MS-DOS", "High Sierra", "Apple CP/M", "", "MS-DOS", "High Sierra", "ISO 9660", "AppleShare" };
"ISO 9660", "AppleShare" };
private static String[] storage = { "", "Seedling", "Sapling", "Tree", "", "Extended", private static String[] storage = { "", "Seedling", "Sapling", "Tree", "", "Extended",
"", "", "", "", "", "", "", "Subdirectory" }; "", "", "", "", "", "", "", "Subdirectory" };
private static String[] accessChars = { "D", "R", "B", "", "", "I", "W", "R" }; private static String[] accessChars = { "D", "R", "B", "", "", "I", "W", "R" };
private static String threadFormats[] = { "unc", "sq ", "lz1", "lz2", "", "" }; private static String threadFormats[] = { "unc", "sq ", "lz1", "lz2", "", "" };
@ -254,6 +253,13 @@ class Record
return 0; return 0;
} }
// ---------------------------------------------------------------------------------//
String getThreadFormatText ()
// ---------------------------------------------------------------------------------//
{
return threadFormats[getThreadFormat ()];
}
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
int getUncompressedSize () int getUncompressedSize ()
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
@ -283,6 +289,17 @@ class Record
return size; return size;
} }
// ---------------------------------------------------------------------------------//
public float getCompressedPct ()
// ---------------------------------------------------------------------------------//
{
float pct = 100;
if (getUncompressedSize () > 0)
pct = getCompressedSize () * 100 / getUncompressedSize ();
return pct;
}
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
byte[] getData () byte[] getData ()
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
@ -313,9 +330,9 @@ class Record
if (name.length () > 27) if (name.length () > 27)
name = ".." + name.substring (name.length () - 25); name = ".." + name.substring (name.length () - 25);
float pct = 100; // float pct = 100;
if (getUncompressedSize () > 0) // if (getUncompressedSize () > 0)
pct = getCompressedSize () * 100 / getUncompressedSize (); // pct = getCompressedSize () * 100 / getUncompressedSize ();
String lockedFlag = (access | 0xC3) == 1 ? "+" : " "; String lockedFlag = (access | 0xC3) == 1 ? "+" : " ";
String forkedFlag = hasResource () ? "+" : " "; String forkedFlag = hasResource () ? "+" : " ";
@ -323,11 +340,11 @@ class Record
if (hasDisk ()) if (hasDisk ())
return String.format ("%s%-27.27s %-4s %-6s %-15s %s %3.0f%% %7d", lockedFlag, return String.format ("%s%-27.27s %-4s %-6s %-15s %s %3.0f%% %7d", lockedFlag,
name, "Disk", (getUncompressedSize () / 1024) + "k", archived.format2 (), name, "Disk", (getUncompressedSize () / 1024) + "k", archived.format2 (),
threadFormats[getThreadFormat ()], pct, getUncompressedSize ()); getThreadFormatText (), getCompressedPct (), getUncompressedSize ());
return String.format ("%s%-27.27s %s%s $%04X %-15s %s %3.0f%% %7d", lockedFlag, return String.format ("%s%-27.27s %s%s $%04X %-15s %s %3.0f%% %7d", lockedFlag,
name, fileTypes[fileType], forkedFlag, auxType, archived.format2 (), name, fileTypes[fileType], forkedFlag, auxType, archived.format2 (),
threadFormats[getThreadFormat ()], pct, getUncompressedSize ()); getThreadFormatText (), getCompressedPct (), getUncompressedSize ());
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//

View File

@ -0,0 +1,125 @@
package com.bytezone.diskbrowser.nufx;
import com.bytezone.diskbrowser.utilities.FileFormatException;
import com.bytezone.diskbrowser.utilities.Utility;
// see http://fileformats.archiveteam.org/wiki/Squeeze
// see http://fileformats.archiveteam.org/wiki/RLE90
// -----------------------------------------------------------------------------------//
public class Squeeze
// -----------------------------------------------------------------------------------//
{
private static final byte[] Squeeze = { 0x76, (byte) 0xFF };
private static int RLE_DELIMITER = 0x90;
private static int EOF_TOKEN = 0x100;
private int bits;
private int bitPos = 7; // trigger the first read
private int ptr;
private byte[] buffer;
private Node[] nodes;
// ---------------------------------------------------------------------------------//
public byte[] unSqueeze (byte[] buffer)
// ---------------------------------------------------------------------------------//
{
if (!Utility.isMagic (buffer, 0, Squeeze))
throw new FileFormatException ("Not Squeeze format");
byte[] uncompressed = new byte[buffer.length * 3];
int uncPtr = 0;
int fileChecksum = Utility.getShort (buffer, 2);
String fileName = Utility.getCString (buffer, 4);
ptr = fileName.length () + 5;
int nodeCount = Utility.getShort (buffer, ptr);
ptr += 2;
nodes = new Node[nodeCount];
this.buffer = buffer;
for (int i = 0; i < nodes.length; i++)
{
int left = Utility.getSignedShort (buffer, ptr);
int right = Utility.getSignedShort (buffer, ptr + 2);
nodes[i] = new Node (left, right);
ptr += 4;
}
boolean repeating = false;
int lastVal = 0;
int sum = 0;
while (true)
{
int val = decodeSymbol ();
if (val == EOF_TOKEN)
break;
if (repeating)
{
repeating = false;
if (val == 0) // flag indicating a single RLE_DELIMITER
{
lastVal = RLE_DELIMITER;
val = 2;
}
while (--val != 0)
{
sum += lastVal;
uncompressed[uncPtr++] = (byte) lastVal;
}
}
else
{
if (val == RLE_DELIMITER)
repeating = true;
else
{
lastVal = val;
sum += lastVal;
uncompressed[uncPtr++] = (byte) lastVal;
}
}
}
if ((sum & 0xFFFF) != fileChecksum)
System.out.printf ("Checksum mismatch : %04X %04X%n", fileChecksum, sum & 0xFFFF);
byte[] uncompressedBuffer = new byte[uncPtr];
System.arraycopy (uncompressed, 0, uncompressedBuffer, 0, uncompressedBuffer.length);
return uncompressedBuffer;
}
// ---------------------------------------------------------------------------------//
private int decodeSymbol ()
// ---------------------------------------------------------------------------------//
{
int val = 0;
while (true)
{
if (++bitPos > 7)
{
bits = buffer[ptr++];
bitPos = 0;
}
val = (bits & 1) == 0 ? nodes[val].left : nodes[val].right;
bits >>>= 1;
if (val < 0)
return -++val; // increment and make positive
}
}
// ---------------------------------------------------------------------------------//
record Node (int left, int right)
// ---------------------------------------------------------------------------------//
{
};
}

View File

@ -28,4 +28,6 @@ Compress . . . . . . . . . . . | .Z | U | Unix Systems
see also: see also:
http://fileformats.archiveteam.org/wiki/Squeeze http://fileformats.archiveteam.org/wiki/Squeeze
http://fileformats.archiveteam.org/wiki/LBR
http://www.seasip.info/Cpm/ludef5.html

View File

@ -1,5 +1,6 @@
package com.bytezone.diskbrowser.pascal; package com.bytezone.diskbrowser.pascal;
import java.time.LocalDate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.GregorianCalendar; import java.util.GregorianCalendar;
import java.util.List; import java.util.List;
@ -23,6 +24,7 @@ abstract class CatalogEntry implements AppleFileSource
protected int lastBlock; // block AFTER last used block protected int lastBlock; // block AFTER last used block
protected int fileType; protected int fileType;
protected GregorianCalendar date; protected GregorianCalendar date;
protected LocalDate localDate;
protected int bytesUsedInLastBlock; protected int bytesUsedInLastBlock;
protected final List<DiskAddress> blocks = new ArrayList<> (); protected final List<DiskAddress> blocks = new ArrayList<> ();
@ -52,6 +54,7 @@ abstract class CatalogEntry implements AppleFileSource
for (DiskAddress sector : blocks) for (DiskAddress sector : blocks)
if (sector.matches (da)) if (sector.matches (da))
return true; return true;
return false; return false;
} }
@ -85,8 +88,8 @@ abstract class CatalogEntry implements AppleFileSource
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
int size = lastBlock - firstBlock; int size = lastBlock - firstBlock;
String fileTypeText = fileType < 0 || fileType >= parent.fileTypes.length ? "????" String fileTypeText =
: parent.fileTypes[fileType]; fileType < 0 || fileType >= parent.fileTypes.length ? "????" : parent.fileTypes[fileType];
return String.format ("%03d %s %-15s", size, fileTypeText, name); return String.format ("%03d %s %-15s", size, fileTypeText, name);
} }
} }

View File

@ -26,7 +26,7 @@ public class FileEntry extends CatalogEntry
super (parent, buffer); super (parent, buffer);
bytesUsedInLastBlock = Utility.getShort (buffer, 22); bytesUsedInLastBlock = Utility.getShort (buffer, 22);
date = Utility.getPascalDate (buffer, 24); localDate = Utility.getPascalLocalDate (buffer, 24);
int max = Math.min (lastBlock, parent.getDisk ().getTotalBlocks ()); int max = Math.min (lastBlock, parent.getDisk ().getTotalBlocks ());
for (int i = firstBlock; i < max; i++) for (int i = firstBlock; i < max; i++)

View File

@ -1,7 +1,8 @@
package com.bytezone.diskbrowser.pascal; package com.bytezone.diskbrowser.pascal;
import java.text.DateFormat; import java.time.LocalDate;
import java.util.GregorianCalendar; import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.List; import java.util.List;
import com.bytezone.diskbrowser.disk.AbstractSector; import com.bytezone.diskbrowser.disk.AbstractSector;
@ -14,7 +15,8 @@ import com.bytezone.diskbrowser.utilities.Utility;
class PascalCatalogSector extends AbstractSector class PascalCatalogSector extends AbstractSector
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
{ {
private final DateFormat df = DateFormat.getDateInstance (DateFormat.SHORT); // private final DateFormat df = DateFormat.getDateInstance (DateFormat.SHORT);
private final DateTimeFormatter dtf = DateTimeFormatter.ofLocalizedDate (FormatStyle.SHORT);
private static String[] fileTypes = private static String[] fileTypes =
{ "Volume", "Bad", "Code", "Text", "Info", "Data", "Graf", "Foto", "SecureDir" }; { "Volume", "Bad", "Code", "Text", "Info", "Data", "Graf", "Foto", "SecureDir" };
@ -44,8 +46,9 @@ class PascalCatalogSector extends AbstractSector
addTextAndDecimal (text, buffer, 16, 2, "Files on disk"); addTextAndDecimal (text, buffer, 16, 2, "Files on disk");
addTextAndDecimal (text, buffer, 18, 2, "First block of volume"); addTextAndDecimal (text, buffer, 18, 2, "First block of volume");
GregorianCalendar calendar = Utility.getPascalDate (buffer, 20); LocalDate localDate = Utility.getPascalLocalDate (buffer, 20);
String date = calendar == null ? "--" : df.format (calendar.getTime ()); String date = localDate == null ? "--" : localDate.format (dtf);
addText (text, buffer, 20, 2, "Most recent date setting : " + date); addText (text, buffer, 20, 2, "Most recent date setting : " + date);
addTextAndDecimal (text, buffer, 22, 4, "Reserved"); addTextAndDecimal (text, buffer, 22, 4, "Reserved");
@ -71,8 +74,8 @@ class PascalCatalogSector extends AbstractSector
addText (text, buffer, ptr + 18, 4, "File name : " + name); addText (text, buffer, ptr + 18, 4, "File name : " + name);
addTextAndDecimal (text, buffer, ptr + 22, 2, "Bytes in file's last block"); addTextAndDecimal (text, buffer, ptr + 22, 2, "Bytes in file's last block");
calendar = Utility.getPascalDate (buffer, ptr + 24); localDate = Utility.getPascalLocalDate (buffer, ptr + 24);
date = calendar == null ? "--" : df.format (calendar.getTime ()); date = localDate == null ? "--" : localDate.format (dtf);
addText (text, buffer, ptr + 24, 2, "Date : " + date); addText (text, buffer, ptr + 24, 2, "Date : " + date);
ptr += PascalDisk.CATALOG_ENTRY_SIZE; ptr += PascalDisk.CATALOG_ENTRY_SIZE;

View File

@ -66,6 +66,7 @@ class PascalCodeObject implements AppleFileSource
for (DiskAddress sector : blocks) for (DiskAddress sector : blocks)
if (sector.matches (da)) if (sector.matches (da))
return true; return true;
return false; return false;
} }

View File

@ -1,9 +1,10 @@
package com.bytezone.diskbrowser.pascal; package com.bytezone.diskbrowser.pascal;
import java.awt.Color; import java.awt.Color;
import java.text.DateFormat; import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.List; import java.util.List;
import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultMutableTreeNode;
@ -28,7 +29,8 @@ public class PascalDisk extends AbstractFormattedDisk
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
{ {
static final int CATALOG_ENTRY_SIZE = 26; static final int CATALOG_ENTRY_SIZE = 26;
private final DateFormat df = DateFormat.getDateInstance (DateFormat.SHORT); private final DateTimeFormatter dtf =
DateTimeFormatter.ofLocalizedDate (FormatStyle.SHORT);
private final VolumeEntry volumeEntry; private final VolumeEntry volumeEntry;
private final PascalCatalogSector diskCatalogSector; private final PascalCatalogSector diskCatalogSector;
@ -143,14 +145,16 @@ public class PascalDisk extends AbstractFormattedDisk
disk.setInterleave (1); // should only ever be Prodos disk.setInterleave (1); // should only ever be Prodos
if (checkFormat (disk, debug)) if (checkFormat (disk, debug))
return true; return true;
disk.setInterleave (0); // see SANE Disk 2.po disk.setInterleave (0); // see SANE Disk 2.po
if (checkFormat (disk, debug)) if (checkFormat (disk, debug))
return true; return true;
return false; return false;
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
public static boolean checkFormat (AppleDisk disk, boolean debug) private static boolean checkFormat (AppleDisk disk, boolean debug)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
byte[] buffer = disk.readBlock (2); byte[] buffer = disk.readBlock (2);
@ -173,12 +177,12 @@ public class PascalDisk extends AbstractFormattedDisk
if (from != 0 || to != 6) if (from != 0 || to != 6)
{ {
if (debug) if (debug)
System.out.printf ("from: %d, to: %d%n", from, to); System.out.printf ("from: %d to: %d%n", from, to);
return false; // will only work for floppies! return false; // will only work for floppies!
} }
int blocks = Utility.getShort (buffer, 14); int blocks = Utility.getShort (buffer, 14);
if (blocks != 280 && blocks != 1600) if (blocks != 280 && blocks != 1600 && blocks != 2048 && blocks != 1272)
{ {
if (debug) if (debug)
System.out.printf ("Blocks > 280: %d%n", blocks); System.out.printf ("Blocks > 280: %d%n", blocks);
@ -207,18 +211,36 @@ public class PascalDisk extends AbstractFormattedDisk
int firstBlock = Utility.getShort (buffer, ptr); int firstBlock = Utility.getShort (buffer, ptr);
int lastBlock = Utility.getShort (buffer, ptr + 2); int lastBlock = Utility.getShort (buffer, ptr + 2);
int kind = Utility.getShort (buffer, ptr + 4); int kind = Utility.getShort (buffer, ptr + 4);
if (lastBlock < firstBlock) if (lastBlock < firstBlock)
{
if (debug)
System.out.printf (" %d %d lastBlock < firstBlock%n", lastBlock, firstBlock);
return false; return false;
if (kind == 0) }
return false;
// if (kind == 0)
// {
// if (debug)
// System.out.printf (" kind = 0%n");
// return false;
// }
nameLength = buffer[ptr + 6] & 0xFF; nameLength = buffer[ptr + 6] & 0xFF;
if (nameLength < 1 || nameLength > 15) if (nameLength < 1 || nameLength > 15)
{
if (debug)
System.out.printf (" %d nameLength < 1 or > 15%n", nameLength);
return false; return false;
}
int lastByte = Utility.getShort (buffer, ptr + 22); int lastByte = Utility.getShort (buffer, ptr + 22);
GregorianCalendar date = Utility.getPascalDate (buffer, 24); LocalDate localDate = Utility.getPascalLocalDate (buffer, 24);
String dateString = localDate == null ? ""
: localDate.format (DateTimeFormatter.ofLocalizedDate (FormatStyle.SHORT));
if (debug) if (debug)
System.out.printf ("%4d %4d %d %-15s %d %s%n", firstBlock, lastBlock, kind, System.out.printf ("%4d %4d %d %-15s %d %s%n", firstBlock, lastBlock, kind,
new String (buffer, ptr + 7, nameLength), lastByte, date); new String (buffer, ptr + 7, nameLength), lastByte, dateString);
} }
return true; return true;
@ -279,8 +301,10 @@ public class PascalDisk extends AbstractFormattedDisk
String newLine2 = newLine + newLine; String newLine2 = newLine + newLine;
String line = "---- --------------- ---- -------- ------- ---- ---- ----" String line = "---- --------------- ---- -------- ------- ---- ---- ----"
+ newLine; + newLine;
String date = String date =
volumeEntry.date == null ? "--" : df.format (volumeEntry.date.getTime ()); volumeEntry.localDate == null ? "--" : volumeEntry.localDate.format (dtf);
StringBuilder text = new StringBuilder (); StringBuilder text = new StringBuilder ();
text.append ("File : " + getDisplayPath () + newLine2); text.append ("File : " + getDisplayPath () + newLine2);
text.append ("Volume : " + volumeEntry.name + newLine); text.append ("Volume : " + volumeEntry.name + newLine);
@ -295,17 +319,21 @@ public class PascalDisk extends AbstractFormattedDisk
FileEntry ce = (FileEntry) fe; FileEntry ce = (FileEntry) fe;
int size = ce.lastBlock - ce.firstBlock; int size = ce.lastBlock - ce.firstBlock;
usedBlocks += size; usedBlocks += size;
date = ce.date == null ? "--" : df.format (ce.date.getTime ());
date = ce.localDate == null ? "--" : ce.localDate.format (dtf);
int bytes = (size - 1) * 512 + ce.bytesUsedInLastBlock; int bytes = (size - 1) * 512 + ce.bytesUsedInLastBlock;
String fileType = ce.fileType < 0 || ce.fileType >= fileTypes.length ? "????" String fileType = ce.fileType < 0 || ce.fileType >= fileTypes.length ? "????"
: fileTypes[ce.fileType]; : fileTypes[ce.fileType];
text.append (String.format ("%4d %-15s %s %8s %,8d $%03X $%03X $%03X%n", text.append (String.format ("%4d %-15s %-6s %8s %,8d $%03X $%03X $%03X%n",
size, ce.name, fileType, date, bytes, ce.firstBlock, ce.lastBlock, size)); size, ce.name, fileType, date, bytes, ce.firstBlock, ce.lastBlock, size));
} }
text.append (line); text.append (line);
text.append ( text.append (
String.format ("Blocks free : %3d Blocks used : %3d Total blocks : %3d%n", String.format ("Blocks free : %3d Blocks used : %3d Total blocks : %3d%n",
(volumeEntry.totalBlocks - usedBlocks), usedBlocks, volumeEntry.totalBlocks)); (volumeEntry.totalBlocks - usedBlocks), usedBlocks, volumeEntry.totalBlocks));
return new DefaultAppleFileSource (volumeEntry.name, text.toString (), this); return new DefaultAppleFileSource (volumeEntry.name, text.toString (), this);
} }
} }

View File

@ -17,9 +17,9 @@ class VolumeEntry extends CatalogEntry
{ {
super (parent, buffer); super (parent, buffer);
totalBlocks = Utility.getShort (buffer, 14); // 280 totalBlocks = Utility.getShort (buffer, 14); // 280
totalFiles = Utility.getShort (buffer, 16); totalFiles = Utility.getShort (buffer, 16);
date = Utility.getPascalDate (buffer, 20); // 2 bytes localDate = Utility.getPascalLocalDate (buffer, 20); // 2 bytes
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//

View File

@ -16,7 +16,7 @@ abstract class CatalogEntry implements AppleFileSource
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
{ {
static String[] storageTypes = { "Del", "Sdl", "Sap", "Tre", "Pas", "Ext", "", "", "", static String[] storageTypes = { "Del", "Sdl", "Sap", "Tre", "Pas", "Ext", "", "", "",
"", "", "", "", "DIR", "SDH", "VDH" }; "", "", "", "", "DIR", "SDH", "VDH" };
Disk disk; Disk disk;
ProdosDisk parentDisk; ProdosDisk parentDisk;
@ -111,6 +111,7 @@ abstract class CatalogEntry implements AppleFileSource
StringBuilder text = new StringBuilder (); StringBuilder text = new StringBuilder ();
text.append (String.format ("Name .......... %s%n", name)); text.append (String.format ("Name .......... %s%n", name));
text.append (String.format ("Access ........ %02X%n", access));
text.append (String.format ("Storage type... %02X%n", storageType)); text.append (String.format ("Storage type... %02X%n", storageType));
text.append (String.format ("Created ....... %s%n", text.append (String.format ("Created ....... %s%n",
created == null ? "" : created.format (ProdosDisk.df))); created == null ? "" : created.format (ProdosDisk.df)));

View File

@ -29,6 +29,7 @@ import com.bytezone.diskbrowser.applefile.MerlinSource;
import com.bytezone.diskbrowser.applefile.ObjectModule; import com.bytezone.diskbrowser.applefile.ObjectModule;
import com.bytezone.diskbrowser.applefile.OriginalHiResImage; import com.bytezone.diskbrowser.applefile.OriginalHiResImage;
import com.bytezone.diskbrowser.applefile.PascalArea; import com.bytezone.diskbrowser.applefile.PascalArea;
import com.bytezone.diskbrowser.applefile.PascalCode;
import com.bytezone.diskbrowser.applefile.ProdosDirectory; import com.bytezone.diskbrowser.applefile.ProdosDirectory;
import com.bytezone.diskbrowser.applefile.QuickDrawFont; import com.bytezone.diskbrowser.applefile.QuickDrawFont;
import com.bytezone.diskbrowser.applefile.SHRPictureFile1; import com.bytezone.diskbrowser.applefile.SHRPictureFile1;
@ -142,7 +143,8 @@ class FileEntry extends CatalogEntry implements ProdosConstants
{ {
int storageType = buffer2[i] & 0x0F; int storageType = buffer2[i] & 0x0F;
int keyBlock = Utility.getShort (buffer2, i + 1); int keyBlock = Utility.getShort (buffer2, i + 1);
int eof = Utility.readTriple (buffer2, i + 3); int size = Utility.getShort (buffer2, i + 3);
int eof = Utility.readTriple (buffer2, i + 5);
if (i < 256) if (i < 256)
addDataBlocks (storageType, keyBlock, dataBlocks); addDataBlocks (storageType, keyBlock, dataBlocks);
@ -161,40 +163,40 @@ class FileEntry extends CatalogEntry implements ProdosConstants
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
DiskAddress emptyDiskAddress = disk.getDiskAddress (0); DiskAddress emptyDiskAddress = disk.getDiskAddress (0);
List<Integer> blocks = new ArrayList<> (); List<Integer> blockNos = new ArrayList<> ();
switch (storageType) switch (storageType)
{ {
case SEEDLING: case SEEDLING:
if (isValid (keyPtr)) if (isValid (keyPtr))
blocks.add (keyPtr); blockNos.add (keyPtr);
break; break;
case SAPLING: case SAPLING:
if (isValid (keyPtr)) if (isValid (keyPtr))
blocks.addAll (readIndex (keyPtr)); blockNos.addAll (readIndex (keyPtr));
break; break;
case TREE: case TREE:
if (isValid (keyPtr)) if (isValid (keyPtr))
for (Integer indexBlock : readMasterIndex (keyPtr)) for (Integer indexBlock : readMasterIndex (keyPtr))
if (isValid (indexBlock)) if (isValid (indexBlock))
blocks.addAll (readIndex (indexBlock)); blockNos.addAll (readIndex (indexBlock));
break; break;
} }
// remove trailing empty blocks // remove trailing empty blocks
while (blocks.size () > 0 && blocks.get (blocks.size () - 1) == 0) while (blockNos.size () > 0 && blockNos.get (blockNos.size () - 1) == 0)
blocks.remove (blocks.size () - 1); blockNos.remove (blockNos.size () - 1);
for (Integer block : blocks) for (Integer blockNo : blockNos)
{ {
if (block == 0) if (blockNo == 0)
dataBlocks.add (emptyDiskAddress); dataBlocks.add (emptyDiskAddress);
else else
{ {
parentDisk.setSectorType (block, parentDisk.dataSector); parentDisk.setSectorType (blockNo, parentDisk.dataSector);
dataBlocks.add (disk.getDiskAddress (block)); dataBlocks.add (disk.getDiskAddress (blockNo));
} }
} }
} }
@ -539,9 +541,16 @@ class FileEntry extends CatalogEntry implements ProdosConstants
file = new DefaultAppleFile (name, exactBuffer); file = new DefaultAppleFile (name, exactBuffer);
break; break;
case FILE_TYPE_PCD:
// case FILE_TYPE_PDA:
file = new PascalCode (name, exactBuffer, 0);
break;
case FILE_TYPE_NON: case FILE_TYPE_NON:
if (name.endsWith (".TIFF") && HiResImage.isTiff (exactBuffer)) if (name.endsWith (".TIFF") && HiResImage.isTiff (exactBuffer))
file = new OriginalHiResImage (name, exactBuffer, auxType); file = new OriginalHiResImage (name, exactBuffer, auxType);
else if (name.endsWith (".JAVA"))
file = new BasicTextFile (name, exactBuffer, auxType, endOfFile);
else else
file = new DefaultAppleFile (name, exactBuffer); file = new DefaultAppleFile (name, exactBuffer);
break; break;

View File

@ -7,6 +7,7 @@ import java.time.format.DateTimeFormatter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Locale;
import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.DefaultTreeModel;
@ -31,7 +32,8 @@ public class ProdosDisk extends AbstractFormattedDisk
{ {
static ProdosPreferences prodosPreferences; // set by MenuHandler static ProdosPreferences prodosPreferences; // set by MenuHandler
static final DateTimeFormatter df = DateTimeFormatter.ofPattern ("d-LLL-yy"); private static Locale US = Locale.US; // to force 3 character months
static final DateTimeFormatter df = DateTimeFormatter.ofPattern ("d-LLL-yy", US);
static final DateTimeFormatter tf = DateTimeFormatter.ofPattern ("H:mm"); static final DateTimeFormatter tf = DateTimeFormatter.ofPattern ("H:mm");
final SectorType dosSector = new SectorType ("Bootstrap Loader", Color.lightGray); final SectorType dosSector = new SectorType ("Bootstrap Loader", Color.lightGray);

View File

@ -5,6 +5,10 @@ import static com.bytezone.diskbrowser.prodos.ProdosConstants.SAPLING;
import static com.bytezone.diskbrowser.prodos.ProdosConstants.SEEDLING; import static com.bytezone.diskbrowser.prodos.ProdosConstants.SEEDLING;
import static com.bytezone.diskbrowser.prodos.ProdosConstants.TREE; import static com.bytezone.diskbrowser.prodos.ProdosConstants.TREE;
// Assumptions:
// - file does not already exist
// - disk is not interleaved
// - blocks are 512 contiguous bytes
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
public class FileWriter public class FileWriter
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
@ -37,8 +41,7 @@ public class FileWriter
while (dataPtr < this.eof) while (dataPtr < this.eof)
{ {
int actualBlockNo = allocateNextBlock (); int actualBlockNo = register (dataPtr / BLOCK_SIZE);
map (dataPtr / BLOCK_SIZE, actualBlockNo);
int bufferPtr = actualBlockNo * BLOCK_SIZE; int bufferPtr = actualBlockNo * BLOCK_SIZE;
int transfer = Math.min (remaining, BLOCK_SIZE); int transfer = Math.min (remaining, BLOCK_SIZE);
@ -53,8 +56,7 @@ public class FileWriter
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
void writeRecord (int recordNo, byte[] dataBuffer, int recordLength) void writeRecord (int recordNo, byte[] dataBuffer, int recordLength) throws DiskFullException
throws DiskFullException
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
assert recordLength > 0; assert recordLength > 0;
@ -98,33 +100,23 @@ public class FileWriter
private int getActualBlockNo (int logicalBlockNo) throws DiskFullException private int getActualBlockNo (int logicalBlockNo) throws DiskFullException
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
int actualBlockNo = 0;
switch (storageType) switch (storageType)
{ {
case TREE: case TREE:
actualBlockNo = masterIndexBlock.get (logicalBlockNo / 0x100) return masterIndexBlock.get (logicalBlockNo / 0x100).getPosition (logicalBlockNo % 0x100);
.getPosition (logicalBlockNo % 0x100);
break;
case SAPLING: case SAPLING:
if (logicalBlockNo < 0x100) if (logicalBlockNo < 0x100)
actualBlockNo = indexBlock.getPosition (logicalBlockNo); return indexBlock.getPosition (logicalBlockNo);
break; break;
case SEEDLING: case SEEDLING:
if (logicalBlockNo == 0) if (logicalBlockNo == 0)
actualBlockNo = keyPointer; return keyPointer;
break; break;
} }
if (actualBlockNo == 0) return register (logicalBlockNo);
{
actualBlockNo = allocateNextBlock ();
map (logicalBlockNo, actualBlockNo);
}
return actualBlockNo;
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
@ -138,14 +130,17 @@ public class FileWriter
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
private void map (int logicalBlockNo, int actualBlockNo) throws DiskFullException private int register (int logicalBlockNo) throws DiskFullException
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
int nextBlockNo = allocateNextBlock ();
if (logicalBlockNo >= 0x100) // potential TREE if (logicalBlockNo >= 0x100) // potential TREE
{ {
if (storageType != TREE) if (storageType != TREE)
{ {
masterIndexBlock = new MasterIndexBlock (allocateNextBlock ()); masterIndexBlock = new MasterIndexBlock (nextBlockNo);
nextBlockNo = allocateNextBlock ();
if (storageType == SAPLING) // sapling -> tree if (storageType == SAPLING) // sapling -> tree
{ {
@ -153,7 +148,9 @@ public class FileWriter
} }
else if (storageType == SEEDLING) // seedling -> sapling -> tree else if (storageType == SEEDLING) // seedling -> sapling -> tree
{ {
indexBlock = new IndexBlock (allocateNextBlock ()); indexBlock = new IndexBlock (nextBlockNo);
nextBlockNo = allocateNextBlock ();
indexBlock.setPosition (0, keyPointer); indexBlock.setPosition (0, keyPointer);
masterIndexBlock.set (0, indexBlock); masterIndexBlock.set (0, indexBlock);
} }
@ -163,48 +160,51 @@ public class FileWriter
indexBlock = null; indexBlock = null;
} }
getIndexBlock (logicalBlockNo / 0x100).setPosition (logicalBlockNo % 0x100, getIndexBlock (logicalBlockNo / 0x100).setPosition (logicalBlockNo % 0x100, nextBlockNo);
actualBlockNo);
} }
else if (logicalBlockNo > 0) // potential SAPLING else if (logicalBlockNo > 0) // potential SAPLING
{ {
if (storageType == TREE) // already a tree if (storageType == TREE) // already a tree
{ {
getIndexBlock (0).setPosition (logicalBlockNo, actualBlockNo); getIndexBlock (0).setPosition (logicalBlockNo, nextBlockNo);
} }
else if (storageType == SAPLING) // already a sapling else if (storageType == SAPLING) // already a sapling
{ {
indexBlock.setPosition (logicalBlockNo, actualBlockNo); indexBlock.setPosition (logicalBlockNo, nextBlockNo);
} }
else // new file or already a seedling else // new file or already a seedling
{ {
indexBlock = new IndexBlock (allocateNextBlock ()); indexBlock = new IndexBlock (nextBlockNo);
nextBlockNo = allocateNextBlock ();
if (storageType == SEEDLING) // seedling -> sapling if (storageType == SEEDLING) // seedling -> sapling
indexBlock.setPosition (0, keyPointer); indexBlock.setPosition (0, keyPointer);
keyPointer = indexBlock.blockNo; keyPointer = indexBlock.blockNo;
storageType = SAPLING; storageType = SAPLING;
indexBlock.setPosition (logicalBlockNo, actualBlockNo); indexBlock.setPosition (logicalBlockNo, nextBlockNo);
} }
} }
else if (logicalBlockNo == 0) // potential SEEDLING else if (logicalBlockNo == 0) // potential SEEDLING
{ {
if (storageType == TREE) // already a tree if (storageType == TREE) // already a tree
{ {
getIndexBlock (0).setPosition (0, actualBlockNo); getIndexBlock (0).setPosition (0, nextBlockNo);
} }
else if (storageType == SAPLING) // already a sapling else if (storageType == SAPLING) // already a sapling
{ {
indexBlock.setPosition (0, actualBlockNo); indexBlock.setPosition (0, nextBlockNo);
} }
else else
{ {
keyPointer = actualBlockNo; keyPointer = nextBlockNo;
storageType = SEEDLING; storageType = SEEDLING;
} }
} }
else else
System.out.println ("Error: " + logicalBlockNo); System.out.println ("Error: " + logicalBlockNo);
return nextBlockNo;
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//

View File

@ -1,5 +1,6 @@
package com.bytezone.diskbrowser.utilities; package com.bytezone.diskbrowser.utilities;
import java.time.DateTimeException;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
@ -7,12 +8,11 @@ import java.time.format.DateTimeFormatter;
public class DateTime public class DateTime
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
{ {
private static String[] months = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", private static String[] months =
"Aug", "Sep", "Oct", "Nov", "Dec" }; { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
private static String[] days = { "", "Sunday", "Monday", "Tuesday", "Wednesday", private static String[] days =
"Thursday", "Friday", "Saturday" }; { "", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
private static final DateTimeFormatter dtf = private static final DateTimeFormatter dtf = DateTimeFormatter.ofPattern ("dd-LLL-yy HH:mm");
DateTimeFormatter.ofPattern ("dd-LLL-yy HH:mm");
private final int second; private final int second;
private final int minute; private final int minute;
@ -40,8 +40,8 @@ public class DateTime
public String format () public String format ()
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
return String.format ("%02d:%02d:%02d %s %d %s %d", hour, minute, second, return String.format ("%02d:%02d:%02d %s %d %s %d", hour, minute, second, days[weekDay], day,
days[weekDay], day, months[month], year); months[month], year);
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
@ -56,10 +56,15 @@ public class DateTime
public LocalDateTime getLocalDateTime () public LocalDateTime getLocalDateTime ()
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
int adjustedYear = year + (year > 70 ? 1900 : 2000); try
if (day < 0 || day > 30) {
int adjustedYear = year + (year > 70 ? 1900 : 2000);
return LocalDateTime.of (adjustedYear, month + 1, day + 1, hour, minute);
}
catch (DateTimeException e)
{
return null; return null;
return LocalDateTime.of (adjustedYear, month + 1, day + 1, hour, minute); }
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
@ -67,8 +72,7 @@ public class DateTime
public String toString () public String toString ()
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
return "DateTime [second=" + second + ", minute=" + minute + ", hour=" + hour return "DateTime [second=" + second + ", minute=" + minute + ", hour=" + hour + ", year=" + year
+ ", year=" + year + ", day=" + day + ", month=" + month + ", weekDay=" + weekDay + ", day=" + day + ", month=" + month + ", weekDay=" + weekDay + "]";
+ "]";
} }
} }

View File

@ -17,6 +17,7 @@ public abstract class DefaultAction extends AbstractAction
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
super (text); super (text);
this.baseURL = null; this.baseURL = null;
putValue (Action.SHORT_DESCRIPTION, tip); putValue (Action.SHORT_DESCRIPTION, tip);
} }
@ -26,6 +27,7 @@ public abstract class DefaultAction extends AbstractAction
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
super (text); super (text);
this.baseURL = baseURL; this.baseURL = baseURL;
putValue (Action.SHORT_DESCRIPTION, tip); putValue (Action.SHORT_DESCRIPTION, tip);
} }
@ -39,6 +41,7 @@ public abstract class DefaultAction extends AbstractAction
System.out.println ("Base URL not set"); System.out.println ("Base URL not set");
return; return;
} }
URL url = this.getClass ().getResource (baseURL + iconName); URL url = this.getClass ().getResource (baseURL + iconName);
if (url != null) if (url != null)
putValue (iconType, new ImageIcon (url)); putValue (iconType, new ImageIcon (url));

View File

@ -9,9 +9,9 @@ import java.io.IOException;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.MathContext; import java.math.MathContext;
import java.time.DateTimeException; import java.time.DateTimeException;
import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Arrays; import java.util.Arrays;
import java.util.GregorianCalendar;
import java.util.List; import java.util.List;
import java.util.zip.CRC32; import java.util.zip.CRC32;
import java.util.zip.Checksum; import java.util.zip.Checksum;
@ -41,13 +41,12 @@ public final class Utility
private static MathContext mathContext8 = new MathContext (15); private static MathContext mathContext8 = new MathContext (15);
private static final List<String> suffixes = Arrays.asList ("po", "dsk", "do", "hdv", private static final List<String> suffixes = Arrays.asList ("po", "dsk", "do", "hdv",
"2mg", "d13", "sdk", "shk", "bxy", "bny", "woz", "img", "dimg"); "2mg", "d13", "sdk", "shk", "bxy", "bny", "bqy", "woz", "img", "dimg");
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
private Utility () private Utility ()
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
@ -199,7 +198,7 @@ public final class Utility
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
public static int signedShort (byte[] buffer, int ptr) public static int getSignedShort (byte[] buffer, int ptr)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
try try
@ -230,7 +229,6 @@ public final class Utility
public static LocalDateTime getAppleDate (byte[] buffer, int offset) public static LocalDateTime getAppleDate (byte[] buffer, int offset)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
// int yymmdd = readShort (buffer, offset);
int yymmdd = getShort (buffer, offset); int yymmdd = getShort (buffer, offset);
if (yymmdd != 0) if (yymmdd != 0)
{ {
@ -432,11 +430,14 @@ public final class Utility
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
public static GregorianCalendar getPascalDate (byte[] buffer, int offset) public static LocalDate getPascalLocalDate (byte[] buffer, int offset)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
int date = Utility.getShort (buffer, offset); int date = Utility.getShort (buffer, offset);
if (date == 0)
return null;
int month = date & 0x0F; int month = date & 0x0F;
int day = (date & 0x1F0) >>> 4; int day = (date & 0x1F0) >>> 4;
int year = (date & 0xFE00) >>> 9; int year = (date & 0xFE00) >>> 9;
@ -446,7 +447,38 @@ public final class Utility
else else
year += 1900; year += 1900;
return new GregorianCalendar (year, month - 1, day); try
{
return LocalDate.of (year, month, day);
}
catch (DateTimeException e)
{
return null;
}
}
// ---------------------------------------------------------------------------------//
public static String getCString (byte[] buffer, int offset)
// ---------------------------------------------------------------------------------//
{
int length = 0;
int ptr = offset;
while (buffer[ptr++] != 0)
++length;
return new String (buffer, offset, length);
}
// ---------------------------------------------------------------------------------//
public static int getWizLong (byte[] buffer, int offset)
// ---------------------------------------------------------------------------------//
{
int low = Utility.getShort (buffer, offset);
int mid = Utility.getShort (buffer, offset + 2);
int high = Utility.getShort (buffer, offset + 4);
return high * 100000000 + mid * 10000 + low;
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
@ -491,12 +523,13 @@ public final class Utility
int[] val = new int[6]; int[] val = new int[6];
for (int i = 0; i < 6; i++) for (int i = 0; i < 6; i++)
val[i] = Integer.parseInt (String.format ("%02X", buffer[ptr + i] & 0xFF)); val[i] = Integer.parseInt (String.format ("%02X", buffer[ptr + i] & 0xFF));
// val[i] = buffer[ptr + i] & 0xFF;
LocalDateTime date = LocalDateTime date =
LocalDateTime.of (val[3] + 2000, val[5], val[4], val[2], val[1], val[0]); LocalDateTime.of (val[3] + 2000, val[5], val[4], val[2], val[1], val[0]);
return date; return date;
} }
catch (DateTimeException | NumberFormatException e) catch (DateTimeException e)
{ {
return null; return null;
} }
@ -536,6 +569,23 @@ public final class Utility
return suffixes.contains (getSuffix (filename)); return suffixes.contains (getSuffix (filename));
} }
// ---------------------------------------------------------------------------------//
public static String getShortPath (String path)
// ---------------------------------------------------------------------------------//
{
String home = System.getProperty ("user.home");
if (path.startsWith (home))
path = "~" + path.substring (home.length ());
else if (path.startsWith ("/Volumes/"))
{
int pos = path.indexOf (home);
if (pos > 0)
path = "~" + path.substring (home.length () + pos);
}
return path;
}
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
public static void reverse (byte[] buffer) public static void reverse (byte[] buffer)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
@ -665,41 +715,42 @@ public final class Utility
return ~crc; // one's complement return ~crc; // one's complement
} }
static int[] crc32_tab = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, static int[] crc32_tab = { //
0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd,
0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d,
0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac,
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab,
0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb,
0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce,
0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409,
0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739,
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0,
0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8,
0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703,
0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7,
0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6,
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d,
0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5,
0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d }; 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d };
} }

406
src/com/bytezone/diskbrowser/wizardry/Character.java Executable file → Normal file
View File

@ -1,23 +1,14 @@
package com.bytezone.diskbrowser.wizardry; package com.bytezone.diskbrowser.wizardry;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import com.bytezone.diskbrowser.applefile.AbstractFile; import com.bytezone.diskbrowser.applefile.AbstractFile;
import com.bytezone.diskbrowser.utilities.Utility; import com.bytezone.diskbrowser.utilities.Utility;
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
class Character extends AbstractFile public abstract class Character extends AbstractFile
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
{ {
private final Attributes attributes; static int MAGE_SPELLS = 0;
private final Statistics stats; static int PRIEST_SPELLS = 1;
int scenario;
private final Collection<Spell> spellBook = new ArrayList<> ();
private final Collection<Baggage> baggageList = new ArrayList<> ();
static String[] races = { "No race", "Human", "Elf", "Dwarf", "Gnome", "Hobbit" }; static String[] races = { "No race", "Human", "Elf", "Dwarf", "Gnome", "Hobbit" };
static String[] alignments = { "Unalign", "Good", "Neutral", "Evil" }; static String[] alignments = { "Unalign", "Good", "Neutral", "Evil" };
@ -25,342 +16,107 @@ class Character extends AbstractFile
{ "Fighter", "Mage", "Priest", "Thief", "Bishop", "Samurai", "Lord", "Ninja" }; { "Fighter", "Mage", "Priest", "Thief", "Bishop", "Samurai", "Lord", "Ninja" };
static String[] statuses = static String[] statuses =
{ "OK", "Afraid", "Asleep", "Paralyze", "Stoned", "Dead", "Ashes", "Lost" }; { "OK", "Afraid", "Asleep", "Paralyze", "Stoned", "Dead", "Ashes", "Lost" };
static char[] awardsText = ">!$#&*<?BCPKODG@".toCharArray ();
// ---------------------------------------------------------------------------------// int scenario;
Character (String name, byte[] buffer, int scenario)
// ---------------------------------------------------------------------------------// public boolean inMaze;
public int hpLeft;
public int hpMax;
public int armourClass;
public final int[] attributes = new int[6]; // 0:18
public final int[] saveVs = new int[5]; // 0:31
public int characterLevel;
public int possessionsCount;
public boolean mysteryBit; // first bit in spellsKnown
public final boolean[] spellsKnown = new boolean[50];
public final int[][] spellAllowance = new int[2][7];
public enum Race
{ {
super (name, buffer); NORACE, HUMAN, ELF, DWARF, GNOME, HOBBIT
this.scenario = scenario; }
attributes = new Attributes (); public enum Alignment
stats = new Statistics (); {
UNALIGN, GOOD, NEUTRAL, EVIL
}
stats.race = races[buffer[34] & 0xFF]; public enum CharacterStatus
stats.typeInt = buffer[36] & 0xFF; {
stats.type = types[stats.typeInt]; OK, AFRAID, ASLEEP, PLYZE, STONED, DEAD, ASHES, LOST
stats.ageInWeeks = Utility.getShort (buffer, 38); }
stats.statusValue = buffer[40];
stats.status = statuses[stats.statusValue];
stats.alignment = alignments[buffer[42] & 0xFF];
stats.gold = Utility.getShort (buffer, 52) + Utility.getShort (buffer, 54) * 10000; public enum CharacterClass
stats.experience = {
Utility.getShort (buffer, 124) + Utility.getShort (buffer, 126) * 10000; FIGHTER, MAGE, PRIEST, THIEF, BISHOP, SAMURAI, LORD, NINJA
stats.level = Utility.getShort (buffer, 132);
stats.hitsLeft = Utility.getShort (buffer, 134);
stats.hitsMax = Utility.getShort (buffer, 136);
stats.armourClass = buffer[176];
attributes.strength = (buffer[44] & 0xFF) % 16;
if (attributes.strength < 3)
attributes.strength += 16;
attributes.array[0] = attributes.strength;
int i1 = (buffer[44] & 0xFF) / 16;
int i2 = (buffer[45] & 0xFF) % 4;
attributes.intelligence = i1 / 2 + i2 * 8;
attributes.array[1] = attributes.intelligence;
attributes.piety = (buffer[45] & 0xFF) / 4;
attributes.array[2] = attributes.piety;
attributes.vitality = (buffer[46] & 0xFF) % 16;
if (attributes.vitality < 3)
attributes.vitality += 16;
attributes.array[3] = attributes.vitality;
int a1 = (buffer[46] & 0xFF) / 16;
int a2 = (buffer[47] & 0xFF) % 4;
attributes.agility = a1 / 2 + a2 * 8;
attributes.array[4] = attributes.agility;
attributes.luck = (buffer[47] & 0xFF) / 4;
attributes.array[5] = attributes.luck;
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
public void linkItems (List<Item> itemList) Character (String name, byte[] buffer)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
boolean equipped; super (name, buffer);
boolean identified; }
int totItems = buffer[58];
stats.assetValue = 0;
for (int ptr = 60; totItems > 0; ptr += 8, totItems--) // ---------------------------------------------------------------------------------//
void get3x5Bits (int[] attributes, int ptr, int value)
// ---------------------------------------------------------------------------------//
{
attributes[ptr] = value & 0x001F;
attributes[ptr + 1] = (value & 0x03E0) >>> 5;
attributes[ptr + 2] = (value & 0x7C00) >>> 10;
}
// ---------------------------------------------------------------------------------//
void get2x5Bits (int[] attributes, int ptr, int value)
// ---------------------------------------------------------------------------------//
{
attributes[ptr] = value & 0x001F;
attributes[ptr + 1] = (value & 0x03E0) >>> 5;
}
// ---------------------------------------------------------------------------------//
protected void checkKnownSpells (byte[] buffer, int ptr)
// ---------------------------------------------------------------------------------//
{
for (int i = 0; i < 7; i++)
{ {
int itemID = buffer[ptr + 6] & 0xFF; spellAllowance[MAGE_SPELLS][i] = Utility.getShort (buffer, ptr + 8 + i * 2);
if (scenario == 3) spellAllowance[PRIEST_SPELLS][i] = Utility.getShort (buffer, ptr + 22 + i * 2);
itemID = (itemID + 24) % 256; }
if (itemID >= 0 && itemID < itemList.size ())
int bit = 1; // skip first bit
int val = buffer[ptr];
mysteryBit = (val & 0x01) == 1;
for (int i = 0; i < spellsKnown.length; i++)
{
if (bit == 8)
{ {
Item item = itemList.get (itemID); val = buffer[++ptr];
equipped = (buffer[ptr] == 1); bit = 0;
identified = (buffer[ptr + 4] == 1);
baggageList.add (new Baggage (item, equipped, identified));
stats.assetValue += item.getCost ();
item.partyOwns++;
} }
else spellsKnown[i] = ((val >>> bit++) & 0x01) != 0;
System.out.println (getName () + " ItemID : " + itemID + " is outside range 0:"
+ (itemList.size () - 1));
} }
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
public void linkSpells (List<Spell> spellList) public String getAwardString ()
// ---------------------------------------------------------------------------------//
{
for (int i = 138; i < 145; i++)
for (int bit = 0; bit < 8; bit++)
if (((buffer[i] >>> bit) & 1) == 1)
{
int index = (i - 138) * 8 + bit;
if (index > 0 && index <= spellList.size ())
spellBook.add (spellList.get (index - 1));
else
System.out.println ("LinkSpell: " + getName () + " SpellID : " + index
+ " is outside range 1:" + spellList.size ());
}
}
// ---------------------------------------------------------------------------------//
@Override
public String getText ()
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
StringBuilder text = new StringBuilder (); StringBuilder text = new StringBuilder ();
text.append ("Character name ..... " + getName ()); int awards = Utility.getShort (buffer, 206);
text.append ("\n\nRace ............... " + stats.race);
text.append ("\nType ............... " + stats.type);
text.append ("\nAlignment .......... " + stats.alignment);
text.append ("\nStatus ............. " + stats.status);
// text.append ("\nType ............... " + stats.typeInt);
// text.append ("\nStatus ............. " + stats.statusValue);
text.append ("\nGold ............... " + String.format ("%,d", stats.gold));
text.append ("\nExperience ......... " + String.format ("%,d", stats.experience));
text.append ("\nNext level ......... " + String.format ("%,d", stats.nextLevel));
text.append ("\nLevel .............. " + stats.level);
text.append ("\nAge in weeks ....... "
+ String.format ("%,d (%d)", stats.ageInWeeks, (stats.ageInWeeks / 52)));
text.append ("\nHit points left .... " + stats.hitsLeft);
text.append ("\nMaximum hits ....... " + stats.hitsMax);
text.append ("\nArmour class ....... " + stats.armourClass);
text.append ("\nAsset value ........ " + String.format ("%,d", stats.assetValue));
text.append ("\nAwards ............. " + isWinner ());
text.append ("\nOut ................ " + isOut ());
text.append ("\n\nStrength ........... " + attributes.strength);
text.append ("\nIntelligence ....... " + attributes.intelligence);
text.append ("\nPiety .............. " + attributes.piety);
text.append ("\nVitality ........... " + attributes.vitality);
text.append ("\nAgility ............ " + attributes.agility);
text.append ("\nLuck ............... " + attributes.luck);
int[] spellPoints = getMageSpellPoints (); for (int i = 0; i < 16; i++)
text.append ("\n\nMage spell points .."); {
for (int i = 0; i < spellPoints.length; i++) if ((awards & 0x01) != 0)
text.append (" " + spellPoints[i]); text.append (awardsText[i]);
awards >>>= 1;
spellPoints = getPriestSpellPoints (); }
text.append ("\nPriest spell points ");
for (int i = 0; i < spellPoints.length; i++)
text.append (" " + spellPoints[i]);
text.append ("\n\nSpells :");
for (Spell s : spellBook)
text.append ("\n" + s);
text.append ("\n\nItems :");
for (Baggage b : baggageList)
text.append ("\n" + b);
return text.toString (); return text.toString ();
} }
}
// ---------------------------------------------------------------------------------//
public void linkExperience (ExperienceLevel exp)
// ---------------------------------------------------------------------------------//
{
stats.nextLevel = exp.getExperiencePoints (stats.level);
}
// ---------------------------------------------------------------------------------//
public int[] getMageSpellPoints ()
// ---------------------------------------------------------------------------------//
{
int[] spells = new int[7];
for (int i = 0; i < 7; i++)
spells[i] = buffer[146 + i * 2];
return spells;
}
// ---------------------------------------------------------------------------------//
public int[] getPriestSpellPoints ()
// ---------------------------------------------------------------------------------//
{
int[] spells = new int[7];
for (int i = 0; i < 7; i++)
spells[i] = buffer[160 + i * 2];
return spells;
}
// ---------------------------------------------------------------------------------//
public Long getNextLevel ()
// ---------------------------------------------------------------------------------//
{
return stats.nextLevel;
}
// this is temporary until I have more data
// ---------------------------------------------------------------------------------//
public String isWinner ()
// ---------------------------------------------------------------------------------//
{
int v1 = buffer[206];
int v2 = buffer[207];
if (v1 == 0x01)
return ">";
if (v1 == 0x00 && v2 == 0x00)
return "";
if (v1 == 0x00 && v2 == 0x20)
return "D";
if (v1 == 0x20 && v2 == 0x20)
return "*D";
if (v1 == 0x21 && v2 == 0x60)
return ">*DG";
if (v1 == 0x21 && v2 == 0x28)
return ">*KD";
return "Unknown : " + v1 + " " + v2;
}
// ---------------------------------------------------------------------------------//
public boolean isOut ()
// ---------------------------------------------------------------------------------//
{
return (buffer[32] == 1);
}
// ---------------------------------------------------------------------------------//
public String getType ()
// ---------------------------------------------------------------------------------//
{
return stats.type;
}
// ---------------------------------------------------------------------------------//
public String getRace ()
// ---------------------------------------------------------------------------------//
{
return stats.race;
}
// ---------------------------------------------------------------------------------//
public String getAlignment ()
// ---------------------------------------------------------------------------------//
{
return stats.alignment;
}
// ---------------------------------------------------------------------------------//
public Attributes getAttributes ()
// ---------------------------------------------------------------------------------//
{
return attributes;
}
// ---------------------------------------------------------------------------------//
public Statistics getStatistics ()
// ---------------------------------------------------------------------------------//
{
return stats;
}
// ---------------------------------------------------------------------------------//
public Iterator<Baggage> getBaggage ()
// ---------------------------------------------------------------------------------//
{
return baggageList.iterator ();
}
// ---------------------------------------------------------------------------------//
public Iterator<Spell> getSpells ()
// ---------------------------------------------------------------------------------//
{
return spellBook.iterator ();
}
// ---------------------------------------------------------------------------------//
@Override
public String toString ()
// ---------------------------------------------------------------------------------//
{
return getName ();
}
// ---------------------------------------------------------------------------------//
public class Baggage
// ---------------------------------------------------------------------------------//
{
public Item item;
public boolean equipped;
public boolean identified;
public Baggage (Item item, boolean equipped, boolean identified)
{
this.item = item;
this.equipped = equipped;
this.identified = identified;
}
@Override
public String toString ()
{
return String.format ("%s%-15s (%d)", equipped ? "*" : " ", item.getName (),
item.getCost ());
}
}
// ---------------------------------------------------------------------------------//
public class Statistics implements Cloneable
// ---------------------------------------------------------------------------------//
{
public String race;
public String type;
public String alignment;
public String status;
public int typeInt;
public int statusValue;
public int gold;
public int experience;
public long nextLevel;
public int level;
public int ageInWeeks;
public int hitsLeft;
public int hitsMax;
public int armourClass;
public int assetValue;
}
public class Attributes
{
public int strength;
public int intelligence;
public int piety;
public int vitality;
public int agility;
public int luck;
public int[] array;
public Attributes ()
{
array = new int[6];
}
}
}

View File

@ -0,0 +1,40 @@
package com.bytezone.diskbrowser.wizardry;
import java.util.ArrayList;
import java.util.List;
// -----------------------------------------------------------------------------------//
public class CharacterParty
// -----------------------------------------------------------------------------------//
{
List<CharacterV4> characters = new ArrayList<> ();
String slogan = "";
// ---------------------------------------------------------------------------------//
void add (CharacterV4 character)
// ---------------------------------------------------------------------------------//
{
characters.add (character);
slogan += character.getPartialSlogan ();
character.setParty (this);
}
// ---------------------------------------------------------------------------------//
@Override
public String toString ()
// ---------------------------------------------------------------------------------//
{
StringBuilder text = new StringBuilder ();
text.append (slogan.replace ("\\", " - "));
text.append ("\n\n");
for (CharacterV4 character : characters)
text.append (String.format ("%3d %-15s %s %3d %3d %17s %13s %13s%n", character.id,
character.getName (), character.getTypeString (), character.armourClass, character.hpLeft,
character.getAttributeString (), character.getSpellsString (CharacterV4.MAGE_SPELLS),
character.getSpellsString (CharacterV4.PRIEST_SPELLS)));
return text.toString ();
}
}

View File

@ -0,0 +1,252 @@
package com.bytezone.diskbrowser.wizardry;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.bytezone.diskbrowser.utilities.Utility;
// -----------------------------------------------------------------------------------//
class CharacterV1 extends Character
// -----------------------------------------------------------------------------------//
{
private String race;
private String type;
private String alignment;
private String status;
public int typeInt;
public int statusInt;
public long gold;
public int experience;
public long nextLevel;
public int ageInWeeks;
public int assetValue;
// int[] mageSpells = new int[7];
// int[] priestSpells = new int[7];
private final List<Spell> spellBook = new ArrayList<> ();
private final List<Possession> possessions = new ArrayList<> ();
// ---------------------------------------------------------------------------------//
CharacterV1 (String name, byte[] buffer, int scenario)
// ---------------------------------------------------------------------------------//
{
super (name, buffer);
this.scenario = scenario;
inMaze = Utility.getShort (buffer, 32) != 0;
race = races[buffer[34] & 0xFF];
typeInt = buffer[36] & 0xFF;
type = types[typeInt];
ageInWeeks = Utility.getShort (buffer, 38);
statusInt = buffer[40];
status = statuses[statusInt];
alignment = alignments[buffer[42] & 0xFF];
get3x5Bits (attributes, 0, Utility.getShort (buffer, 44));
get3x5Bits (attributes, 3, Utility.getShort (buffer, 46));
get3x5Bits (saveVs, 0, Utility.getShort (buffer, 48));
get2x5Bits (saveVs, 3, Utility.getShort (buffer, 50));
gold = Utility.getWizLong (buffer, 52);
possessionsCount = Utility.getShort (buffer, 58);
for (int i = 0; i < possessionsCount; i++)
{
boolean equipped = Utility.getShort (buffer, 60 + i * 8) == 1;
boolean cursed = Utility.getShort (buffer, 62 + i * 8) == 1;
boolean identified = Utility.getShort (buffer, 64 + i * 8) == 1;
int itemId = Utility.getShort (buffer, 66 + i * 8);
if (scenario == 3 && itemId >= 1000)
itemId -= 1000; // why?
possessions.add (new Possession (itemId, equipped, cursed, identified));
}
experience = Utility.getWizLong (buffer, 124);
characterLevel = Utility.getShort (buffer, 132);
hpLeft = Utility.getShort (buffer, 134);
hpMax = Utility.getShort (buffer, 136);
checkKnownSpells (buffer, 138);
armourClass = buffer[176];
}
// ---------------------------------------------------------------------------------//
public void link (List<ItemV1> itemList, List<Spell> spellList,
List<ExperienceLevel> experienceLevels)
// ---------------------------------------------------------------------------------//
{
for (Possession baggage : possessions)
{
baggage.item = itemList.get (baggage.itemId);
assetValue += baggage.item.getCost ();
}
for (int i = 0; i < spellsKnown.length; i++)
if (spellsKnown[i])
spellBook.add (spellList.get (i));
nextLevel = experienceLevels.get (typeInt).getExperiencePoints (characterLevel + 1);
}
// ---------------------------------------------------------------------------------//
@Override
public String getText ()
// ---------------------------------------------------------------------------------//
{
StringBuilder text = new StringBuilder ();
text.append (String.format ("Character name ..... %s%n", getName ()));
text.append ("\nRace ............... " + race);
text.append ("\nType ............... " + type);
text.append ("\nAlignment .......... " + alignment);
text.append ("\nStatus ............. " + status);
text.append ("\nGold ............... " + String.format ("%,d", gold));
text.append ("\nExperience ......... " + String.format ("%,d", experience));
text.append ("\nNext level ......... " + String.format ("%,d", nextLevel));
text.append ("\nLevel .............. " + characterLevel);
text.append (
"\nAge in weeks ....... " + String.format ("%,d (%d)", ageInWeeks, (ageInWeeks / 52)));
text.append ("\nHit points left .... " + hpLeft);
text.append ("\nMaximum hits ....... " + hpMax);
text.append ("\nArmour class ....... " + armourClass);
text.append ("\nAsset value ........ " + String.format ("%,d", assetValue));
text.append ("\nAwards ............. " + getAwardString ());
text.append ("\nOut ................ " + isOut ());
text.append ("\n\nStrength ........... " + attributes[0]);
text.append ("\nIntelligence ....... " + attributes[1]);
text.append ("\nPiety .............. " + attributes[2]);
text.append ("\nVitality ........... " + attributes[3]);
text.append ("\nAgility ............ " + attributes[4]);
text.append ("\nLuck ............... " + attributes[5]);
text.append ("\n\nMage spell points ..");
for (int i = 0; i < spellAllowance[MAGE_SPELLS].length; i++)
text.append (" " + spellAllowance[MAGE_SPELLS][i]);
text.append ("\nPriest spell points ");
for (int i = 0; i < spellAllowance[PRIEST_SPELLS].length; i++)
text.append (" " + spellAllowance[PRIEST_SPELLS][i]);
text.append ("\n\nSpells :");
for (Spell s : spellBook)
text.append ("\n" + s);
text.append ("\n\nItems :");
for (Possession b : possessions)
text.append ("\n" + b);
return text.toString ();
}
// ---------------------------------------------------------------------------------//
public Long getNextLevel ()
// ---------------------------------------------------------------------------------//
{
return nextLevel;
}
// ---------------------------------------------------------------------------------//
public boolean isOut ()
// ---------------------------------------------------------------------------------//
{
return inMaze;
}
// ---------------------------------------------------------------------------------//
public String getType ()
// ---------------------------------------------------------------------------------//
{
return type;
}
// ---------------------------------------------------------------------------------//
public String getStatus ()
// ---------------------------------------------------------------------------------//
{
return status;
}
// ---------------------------------------------------------------------------------//
public String getRace ()
// ---------------------------------------------------------------------------------//
{
return race;
}
// ---------------------------------------------------------------------------------//
public String getAlignment ()
// ---------------------------------------------------------------------------------//
{
return alignment;
}
// ---------------------------------------------------------------------------------//
int[] getAttributes ()
// ---------------------------------------------------------------------------------//
{
return attributes;
}
// ---------------------------------------------------------------------------------//
public Iterator<Possession> getBaggage ()
// ---------------------------------------------------------------------------------//
{
return possessions.iterator ();
}
// ---------------------------------------------------------------------------------//
public Iterator<Spell> getSpells ()
// ---------------------------------------------------------------------------------//
{
return spellBook.iterator ();
}
// ---------------------------------------------------------------------------------//
@Override
public String toString ()
// ---------------------------------------------------------------------------------//
{
return getName ();
}
// ---------------------------------------------------------------------------------//
public class Possession
// ---------------------------------------------------------------------------------//
{
public ItemV1 item;
int itemId;
public boolean cursed;
public boolean equipped;
public boolean identified;
public Possession (int itemId, boolean equipped, boolean cursed, boolean identified)
{
this.itemId = itemId;
this.equipped = equipped;
this.identified = identified;
this.cursed = cursed;
}
@Override
public String toString ()
{
return String.format ("%s%-15s %,10d", equipped ? "*" : " ", item.getName (),
item.getCost ());
}
}
}

View File

@ -0,0 +1,223 @@
package com.bytezone.diskbrowser.wizardry;
import java.util.ArrayList;
import java.util.List;
import com.bytezone.diskbrowser.utilities.HexFormatter;
import com.bytezone.diskbrowser.utilities.Utility;
// -----------------------------------------------------------------------------------//
public class CharacterV4 extends Character
// -----------------------------------------------------------------------------------//
{
private static int MAX_POSSESSIONS = 8;
private static int MAX_SPELLS = 50;
static int MAGE_SPELLS = 0;
static int PRIEST_SPELLS = 1;
int id;
int nextCharacterId;
CharacterParty party;
String partialSlogan;
public final Race race;
public final CharacterClass characterClass;
public final int age;
public final CharacterStatus status;
public final Alignment alignment;
public final long gold;
public final List<Integer> possessionIds = new ArrayList<> (MAX_POSSESSIONS);
public final List<ItemV4> possessions = new ArrayList<> (MAX_POSSESSIONS);
public final long experience;
public final int maxlevac; // max level armour class?
public final int hpCalCmd;
public final int healPts;
public final boolean crithitm;
public final int swingCount;
public final Dice hpdamrc; // +184
int unknown1;
int unknown2;
int unknown3;
int unknown4;
int unknown5;
// ---------------------------------------------------------------------------------//
CharacterV4 (String name, byte[] buffer, int id)
// ---------------------------------------------------------------------------------//
{
super (name, buffer);
this.id = id;
scenario = 4;
partialSlogan = buffer[17] == 0 ? "" : HexFormatter.getPascalString (buffer, 17);
inMaze = Utility.getShort (buffer, 33) != 0;
race = Race.values ()[Utility.getShort (buffer, 35)];
characterClass = CharacterClass.values ()[Utility.getShort (buffer, 37)];
age = 0;
armourClass = Utility.getSignedShort (buffer, 39);
status = CharacterStatus.values ()[Utility.getShort (buffer, 41)];
alignment = Alignment.values ()[Utility.getShort (buffer, 43)];
get3x5Bits (attributes, 0, Utility.getShort (buffer, 45));
get3x5Bits (attributes, 3, Utility.getShort (buffer, 47));
gold = 0;
unknown1 = Utility.getShort (buffer, 49); // was saveVs (4 bytes)
unknown2 = Utility.getShort (buffer, 51);
unknown3 = Utility.getShort (buffer, 53); // was gold (6 bytes)
unknown4 = Utility.getShort (buffer, 55);
unknown5 = Utility.getShort (buffer, 57);
possessionsCount = Utility.getShort (buffer, 59);
for (int i = 0; i < possessionsCount; i++)
{
// boolean equipped = Utility.getShort (buffer, 61 + i * 8) == 1;
// boolean cursed = Utility.getShort (buffer, 63 + i * 8) == 1;
// boolean identified = Utility.getShort (buffer, 65 + i * 8) == 1;
int itemNo = Utility.getShort (buffer, 67 + i * 8);
// Possession p = new Possession (itemNo, equipped, cursed, identified);
possessionIds.add (itemNo);
}
experience = 0;
nextCharacterId = Utility.getShort (buffer, 125);
maxlevac = Utility.getShort (buffer, 131);
characterLevel = Utility.getShort (buffer, 133);
hpLeft = Utility.getShort (buffer, 135);
hpMax = Utility.getShort (buffer, 137);
checkKnownSpells (buffer, 139);
hpCalCmd = Utility.getSignedShort (buffer, 175);
// armourClass = Utility.getSignedShort (buffer, 177); // see offset 39
healPts = Utility.getShort (buffer, 179);
crithitm = Utility.getShort (buffer, 181) == 1;
swingCount = Utility.getShort (buffer, 183);
hpdamrc = new Dice (buffer, 185);
}
// ---------------------------------------------------------------------------------//
void addPossessions (List<ItemV4> items)
// ---------------------------------------------------------------------------------//
{
for (int itemId : possessionIds)
{
possessions.add (items.get (itemId));
}
}
// ---------------------------------------------------------------------------------//
void setParty (CharacterParty party)
// ---------------------------------------------------------------------------------//
{
this.party = party;
}
// ---------------------------------------------------------------------------------//
boolean isInParty ()
// ---------------------------------------------------------------------------------//
{
return party != null;
}
// ---------------------------------------------------------------------------------//
String getPartialSlogan ()
// ---------------------------------------------------------------------------------//
{
// return buffer[17] == 0 ? "" : HexFormatter.getPascalString (buffer, 17);
return partialSlogan;
}
// ---------------------------------------------------------------------------------//
String getAttributeString ()
// ---------------------------------------------------------------------------------//
{
StringBuilder text = new StringBuilder ();
for (int i = 0; i < attributes.length; i++)
text.append (String.format ("%02d/", attributes[i]));
text.deleteCharAt (text.length () - 1);
return text.toString ();
}
// ---------------------------------------------------------------------------------//
String getSpellsString (int which)
// ---------------------------------------------------------------------------------//
{
StringBuilder text = new StringBuilder ();
int total = 0;
for (int i = 0; i < spellAllowance[which].length; i++)
total += spellAllowance[which][i];
if (total == 0)
return "";
for (int i = 0; i < spellAllowance[which].length; i++)
text.append (String.format ("%d/", spellAllowance[which][i]));
text.deleteCharAt (text.length () - 1);
return text.toString ();
}
// ---------------------------------------------------------------------------------//
String getTypeString ()
// ---------------------------------------------------------------------------------//
{
return String.format ("%1.1s-%3.3s", alignment, characterClass);
}
// ---------------------------------------------------------------------------------//
@Override
public String getText ()
// ---------------------------------------------------------------------------------//
{
StringBuilder text = new StringBuilder ();
text.append (String.format ("Id ................ %d%n", id));
text.append (String.format ("Name .............. %s%n", name));
text.append (String.format ("Race .............. %s%n", race));
text.append (String.format ("Character class ... %s%n", characterClass));
text.append (String.format ("Alignment ......... %s%n", alignment));
text.append (String.format ("Status ............ %s%n", status));
text.append (String.format ("Level ? ........... %d%n", characterLevel));
text.append (String.format ("Hit points ........ %d/%d%n", hpLeft, hpMax));
text.append (String.format ("Armour class ...... %d%n", armourClass));
text.append (String.format ("Attributes ........ %s%n", getAttributeString ()));
text.append (String.format ("Mage spells ....... %s%n", getSpellsString (MAGE_SPELLS)));
text.append (String.format ("Priest spells ..... %s%n", getSpellsString (PRIEST_SPELLS)));
if (possessionsCount > 0)
{
text.append ("\nPossessions:\n");
for (ItemV4 item : possessions)
text.append (" " + item + "\n");
}
if (!party.slogan.isEmpty () || party.characters.size () > 1)
{
for (int i = possessionsCount; i < 9; i++)
text.append ("\n");
text.append (party);
}
// text.append ("\n\n");
// text.append (HexFormatter.format (buffer, 1, buffer[0] & 0xFF));
return text.toString ();
}
}

View File

@ -3,7 +3,7 @@ package com.bytezone.diskbrowser.wizardry;
import com.bytezone.diskbrowser.utilities.HexFormatter; import com.bytezone.diskbrowser.utilities.HexFormatter;
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
class CodedMessage extends Message class CodedMessage extends MessageV1
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
{ {
public static int codeOffset = 185; public static int codeOffset = 185;
@ -20,12 +20,12 @@ class CodedMessage extends Message
protected String getLine (int offset) protected String getLine (int offset)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
int length = buffer[offset] & 0xFF; int length = buffer[offset++] & 0xFF;
byte[] translation = new byte[length]; byte[] translation = new byte[length];
codeOffset--; codeOffset--;
for (int j = 0; j < length; j++) for (int j = 0; j < length; j++)
{ {
translation[j] = buffer[offset + 1 + j]; translation[j] = buffer[offset + j];
translation[j] -= codeOffset - j * 3; translation[j] -= codeOffset - j * 3;
} }
return HexFormatter.getString (translation, 0, length); return HexFormatter.getString (translation, 0, length);

View File

@ -22,9 +22,8 @@ class ExperienceLevel extends AbstractFile
if (buffer[ptr] == 0) if (buffer[ptr] == 0)
break; break;
long points = long points = Utility.getShort (buffer, ptr) + Utility.getShort (buffer, ptr + 2) * 10000
Utility.getShort (buffer, ptr) + Utility.getShort (buffer, ptr + 2) * 10000 + Utility.getShort (buffer, ptr + 4) * 100000000L;
+ Utility.getShort (buffer, ptr + 4) * 100000000L;
expLevels[seq++] = points; expLevels[seq++] = points;
} }
} }
@ -33,9 +32,9 @@ class ExperienceLevel extends AbstractFile
long getExperiencePoints (int level) long getExperiencePoints (int level)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
if (level < 13) if (level == 0)
return expLevels[level]; return expLevels[0];
return (level - 12) * expLevels[0] + expLevels[12]; return level < 13 ? expLevels[level - 1] : (level - 13) * expLevels[0] + expLevels[12];
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
@ -43,9 +42,13 @@ class ExperienceLevel extends AbstractFile
public String getText () public String getText ()
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
StringBuilder line = new StringBuilder (); StringBuilder line = new StringBuilder (name + "\n\nLevel Points Needed\n");
for (long exp : expLevels)
line.append (exp + "\n"); for (int i = 2; i <= 26; i++)
line.append (String.format (" %2d %,13d%n", i, getExperiencePoints (i)));
line.append (String.format ("%n %,13d+", expLevels[0]));
return line.toString (); return line.toString ();
} }
} }

View File

@ -17,11 +17,10 @@ import com.bytezone.diskbrowser.utilities.Utility;
class Header class Header
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
{ {
static String[] typeText = { "header", "maze", "monsters", "rewards", "items", static String[] typeText =
"characters", "images", "char levels" }; { "header", "maze", "monsters", "rewards", "items", "characters", "images", "char levels" };
static String[] scenarioNames = static String[] scenarioNames = { "PROVING GROUNDS OF THE MAD OVERLORD!",
{ "PROVING GROUNDS OF THE MAD OVERLORD!", "THE KNIGHT OF DIAMONDS", "THE KNIGHT OF DIAMONDS", "THE LEGACY OF LLYLGAMYN", "THE RETURN OF WERDNA" };
"THE LEGACY OF LLYLGAMYN", "THE RETURN OF WERDNA" };
static final int MAZE_AREA = 1; static final int MAZE_AREA = 1;
static final int MONSTER_AREA = 2; static final int MONSTER_AREA = 2;
@ -74,8 +73,7 @@ class Header
ptr += 10; ptr += 10;
} }
DefaultAppleFileSource dafs = DefaultAppleFileSource dafs = new DefaultAppleFileSource ("Header", text.toString (), owner);
new DefaultAppleFileSource ("Header", text.toString (), owner);
dafs.setSectors (data.get (0).sectors); dafs.setSectors (data.get (0).sectors);
DefaultMutableTreeNode headerNode = new DefaultMutableTreeNode (dafs); DefaultMutableTreeNode headerNode = new DefaultMutableTreeNode (dafs);
dataNode.add (headerNode); dataNode.add (headerNode);
@ -103,6 +101,13 @@ class Header
} }
} }
// ---------------------------------------------------------------------------------//
ScenarioData get (int index)
// ---------------------------------------------------------------------------------//
{
return data.get (index);
}
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
private void linkText (String title, DiskAddress da, DefaultMutableTreeNode headerNode) private void linkText (String title, DiskAddress da, DefaultMutableTreeNode headerNode)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
@ -128,8 +133,7 @@ class Header
ptr += 2; ptr += 2;
} }
DefaultAppleFileSource dafs = DefaultAppleFileSource dafs = new DefaultAppleFileSource (title, text.toString (), owner);
new DefaultAppleFileSource (title, text.toString (), owner);
dafs.setSectors (blocks); dafs.setSectors (blocks);
DefaultMutableTreeNode node = new DefaultMutableTreeNode (dafs); DefaultMutableTreeNode node = new DefaultMutableTreeNode (dafs);
node.setAllowsChildren (false); node.setAllowsChildren (false);
@ -137,8 +141,7 @@ class Header
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
private void linkPictures (String title, DiskAddress da, private void linkPictures (String title, DiskAddress da, DefaultMutableTreeNode headerNode)
DefaultMutableTreeNode headerNode)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
List<DiskAddress> blocks = new ArrayList<> (); List<DiskAddress> blocks = new ArrayList<> ();
@ -155,8 +158,7 @@ class Header
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
private void linkSpells (String title, DiskAddress da, private void linkSpells (String title, DiskAddress da, DefaultMutableTreeNode headerNode)
DefaultMutableTreeNode headerNode)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
List<DiskAddress> blocks = new ArrayList<> (); List<DiskAddress> blocks = new ArrayList<> ();
@ -180,8 +182,7 @@ class Header
list.append (" " + s + "\n"); list.append (" " + s + "\n");
} }
DefaultAppleFileSource dafs = DefaultAppleFileSource dafs = new DefaultAppleFileSource (title, list.toString (), owner);
new DefaultAppleFileSource (title, list.toString (), owner);
dafs.setSectors (blocks); dafs.setSectors (blocks);
DefaultMutableTreeNode node = new DefaultMutableTreeNode (dafs); DefaultMutableTreeNode node = new DefaultMutableTreeNode (dafs);
node.setAllowsChildren (false); node.setAllowsChildren (false);
@ -224,8 +225,8 @@ class Header
{ {
int dunno; int dunno;
int total; int total;
int totalBlocks; int totalBlocks; // size in blocks
int dataOffset; int dataOffset; // first block
int type; int type;
List<DiskAddress> sectors; List<DiskAddress> sectors;

View File

@ -1,5 +1,8 @@
package com.bytezone.diskbrowser.wizardry; package com.bytezone.diskbrowser.wizardry;
import java.util.ArrayList;
import java.util.List;
import com.bytezone.diskbrowser.applefile.AbstractFile; import com.bytezone.diskbrowser.applefile.AbstractFile;
// Based on a pascal routine by Tom Ewers // Based on a pascal routine by Tom Ewers
@ -28,19 +31,73 @@ class Huffman extends AbstractFile
super (name, buffer); super (name, buffer);
} }
// ---------------------------------------------------------------------------------//
byte[] decodeMessageOld (byte[] buffer, int offset, int length)
// ---------------------------------------------------------------------------------//
{
this.message = buffer;
List<Byte> 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;
}
// ---------------------------------------------------------------------------------//
byte[] decodeMessage (byte[] buffer, int offset)
// ---------------------------------------------------------------------------------//
{
this.message = buffer;
depth = 0;
msgPtr = offset;
currentByte = 0;
int size = (getChar () & 0xFF) + 1;
byte[] returnBuffer = new byte[size];
returnBuffer[0] = (byte) size;
int ptr = 1;
while (ptr < size)
returnBuffer[ptr++] = getChar ();
return returnBuffer;
}
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
String decodeMessage (byte[] message) String decodeMessage (byte[] message)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
this.message = message; this.message = message;
depth = 0; depth = 0;
msgPtr = 0; msgPtr = 0;
currentByte = 0; currentByte = 0;
int len = getChar (); int len = getChar () & 0xFF;
StringBuilder text = new StringBuilder (); StringBuilder text = new StringBuilder ();
for (int i = 0; i < len; i++) 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 (); return text.toString ();
} }
@ -57,7 +114,7 @@ class Huffman extends AbstractFile
currentByte = message[msgPtr++]; // ...get a new byte currentByte = message[msgPtr++]; // ...get a new byte
int currentBit = currentByte & 0x01; // extract the next bit to process int currentBit = currentByte & 0x01; // extract the next bit to process
currentByte >>= 1; // and remove it from the current byte currentByte >>>= 1; // and remove it from the current byte
// use currentBit to determine whether to use the left or right node // use currentBit to determine whether to use the left or right node
byte nodeValue = buffer[treePtr + offset[currentBit]]; byte nodeValue = buffer[treePtr + offset[currentBit]];
@ -82,6 +139,7 @@ class Huffman extends AbstractFile
walk (0, "", text); walk (0, "", text);
bufferContents = text.toString (); bufferContents = text.toString ();
} }
return bufferContents; return bufferContents;
} }

View File

@ -13,8 +13,8 @@ class Image extends AbstractImage
{ {
super (name, buffer); super (name, buffer);
if (buffer[0] == -61 && buffer[1] == -115) // if (buffer[0] == -61 && buffer[1] == -115)
fixSlime (buffer); // fixSlime (buffer);
image = new BufferedImage (70, 50, BufferedImage.TYPE_BYTE_GRAY); // width/height image = new BufferedImage (70, 50, BufferedImage.TYPE_BYTE_GRAY); // width/height
DataBuffer db = image.getRaster ().getDataBuffer (); DataBuffer db = image.getRaster ().getDataBuffer ();
@ -30,8 +30,10 @@ class Image extends AbstractImage
element += 7 - m; element += 7 - m;
break; break;
} }
if ((bits & 1) == 1) if ((bits & 1) == 1)
db.setElem (element, 255); db.setElem (element, 255);
bits >>= 1; bits >>= 1;
element++; element++;
} }
@ -44,6 +46,7 @@ class Image extends AbstractImage
{ {
for (int i = 0; i < 208; i++) for (int i = 0; i < 208; i++)
buffer[i] = 0; buffer[i] = 0;
buffer[124] = -108; buffer[124] = -108;
buffer[134] = -43; buffer[134] = -43;
buffer[135] = -128; buffer[135] = -128;

207
src/com/bytezone/diskbrowser/wizardry/Item.java Executable file → Normal file
View File

@ -1,36 +1,53 @@
package com.bytezone.diskbrowser.wizardry; package com.bytezone.diskbrowser.wizardry;
import com.bytezone.diskbrowser.applefile.AbstractFile; import com.bytezone.diskbrowser.applefile.AbstractFile;
import com.bytezone.diskbrowser.utilities.HexFormatter;
import com.bytezone.diskbrowser.utilities.Utility;
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
class Item extends AbstractFile implements Comparable<Item> public class Item extends AbstractFile
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
{ {
public final int itemID; int itemId;
private final int type;
private final long cost;
public int partyOwns;
String genericName; String genericName;
static int counter = 0; protected long price;
public final Dice damage; public Dice wephpdam;
public final int armourClass; public int armourClass;
public final int speed; public int xtraSwing;
boolean cursed;
int changeTo;
int changeChance;
int special;
int boltac;
int spellPwr;
int classUseFlags;
int healPts;
int flags1;
int flags2;
int flags3;
int wephitmd;
boolean crithitm;
ObjectType type;
Alignment alignment;
Item changeToItem;
Spell spell;
String spellName;
public enum Alignment
{
UNALIGN, GOOD, NEUTRAL, EVIL
}
public enum ObjectType
{
WEAPON, ARMOR, SHIELD, HELMET, GAUNTLET, SPECIAL, MISC
}
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
Item (String name, byte[] buffer) Item (String name, byte[] buffer)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
super (name, buffer); super (name, buffer);
itemID = counter++;
type = buffer[32];
cost = Utility.getShort (buffer, 44) + Utility.getShort (buffer, 46) * 10000
+ Utility.getShort (buffer, 48) * 100000000L;
genericName = HexFormatter.getPascalString (buffer, 16);
damage = new Dice (buffer, 66);
armourClass = buffer[62];
speed = buffer[72];
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
@ -40,125 +57,39 @@ class Item extends AbstractFile implements Comparable<Item>
{ {
StringBuilder text = new StringBuilder (); StringBuilder text = new StringBuilder ();
text.append ("Name ......... : " + getName ()); text.append (String.format ("ID ............... %s%n%n", itemId));
// int length = HexFormatter.intValue (buffer[16]); text.append (String.format ("Name ............. %s%n", name));
text.append ("\nGeneric name . : " + genericName); text.append (String.format ("Generic name ..... %s%n", genericName));
text.append ("\nType ......... : " + type);
text.append ("\nCost ......... : " + cost); text.append (String.format ("Cost ............. %,d%n", price));
text.append ("\nArmour class . : " + armourClass); text.append (String.format ("Damage ........... %s%n", wephpdam));
text.append ("\nDamage ....... : " + damage); text.append (String.format ("Hit mod .......... %d%n", wephitmd));
text.append ("\nSpeed ........ : " + speed); text.append (String.format ("Critical hit ..... %s%n", crithitm));
text.append ("\nCursed? ...... : " + isCursed ());
int stock = getStockOnHand (); text.append (String.format ("Type ............. %s%n", type));
text.append ("\nStock on hand : " + stock); text.append (String.format ("Alignment ........ %s%n", alignment));
if (stock < 0) text.append (String.format ("Armour class ..... %d%n", armourClass));
text.append (" (always in stock)"); text.append (String.format ("Speed ............ %d%n", xtraSwing));
text.append (String.format ("Cursed? .......... %s%n", cursed));
String changeItemName = changeToItem == null ? "" : changeToItem.getName ();
text.append (String.format ("Decay odds ....... %d%%%n", changeChance));
text.append (String.format ("Decay to ......... %s%n", changeItemName));
text.append (String.format ("Special .......... %d%n", special));
text.append (String.format ("Boltac ........... %d%n", boltac));
String spellName = spell == null ? "" : spell.getName ();
if (this.spellName != null)
spellName = this.spellName;
text.append (String.format ("Spell ............ %s%n", spellName));
text.append (String.format ("Heal ............. %d%n", healPts));
text.append (String.format ("Class use ........ %d%n", classUseFlags));
text.append (String.format ("Flags ............ %d%n", flags1));
text.append (String.format ("Flags2 ........... %d%n", flags2));
text.append (String.format ("Flags3 ........... %d%n", flags3));
return text.toString (); return text.toString ();
} }
}
// ---------------------------------------------------------------------------------//
public int getType ()
// ---------------------------------------------------------------------------------//
{
return type;
}
// public int getArmourClass ()
// {
// return buffer[62];
// }
// public int getSpeed ()
// {
// return HexFormatter.intValue (buffer[72]);
// }
// ---------------------------------------------------------------------------------//
public long getCost ()
// ---------------------------------------------------------------------------------//
{
return cost;
}
// ---------------------------------------------------------------------------------//
public boolean isCursed ()
// ---------------------------------------------------------------------------------//
{
return buffer[36] != 0;
}
// ---------------------------------------------------------------------------------//
public int getStockOnHand ()
// ---------------------------------------------------------------------------------//
{
if (buffer[50] == -1 && buffer[51] == -1)
return -1;
return Utility.getShort (buffer, 50);
}
// ---------------------------------------------------------------------------------//
public boolean canUse (int type2)
// ---------------------------------------------------------------------------------//
{
int users = buffer[54] & 0xFF;
return ((users >>> type2) & 1) == 1;
}
// ---------------------------------------------------------------------------------//
@Override
public String toString ()
// ---------------------------------------------------------------------------------//
{
StringBuilder line = new StringBuilder ();
line.append (String.format ("%-16s", getName ()));
if (buffer[36] == -1)
line.append ("(c) ");
else
line.append (" ");
line.append (String.format ("%02X ", buffer[62]));
line.append (String.format ("%02X ", buffer[34]));
line.append (String.format ("%02X %02X", buffer[50], buffer[51]));
// if (buffer[50] == -1 && buffer[51] == -1)
// line.append ("* ");
// else
// line.append (HexFormatter.intValue (buffer[50], buffer[51]) + " ");
for (int i = 38; i < 44; i++)
line.append (HexFormatter.format2 (buffer[i]) + " ");
for (int i = 48; i < 50; i++)
line.append (HexFormatter.format2 (buffer[i]) + " ");
for (int i = 52; i < 62; i++)
line.append (HexFormatter.format2 (buffer[i]) + " ");
// for (int i = 64; i < 78; i++)
// line.append (HexFormatter.format2 (buffer[i]) + " ");
return line.toString ();
}
// ---------------------------------------------------------------------------------//
public String getDump (int block)
// ---------------------------------------------------------------------------------//
{
StringBuilder line =
new StringBuilder (String.format ("%3d %-16s", itemID, getName ()));
int lo = block == 0 ? 32 : block == 1 ? 46 : 70;
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]));
return line.toString ();
}
// ---------------------------------------------------------------------------------//
@Override
public int compareTo (Item otherItem)
// ---------------------------------------------------------------------------------//
{
Item item = otherItem;
return this.type - item.type;
}
}

View File

@ -0,0 +1,156 @@
package com.bytezone.diskbrowser.wizardry;
import java.util.List;
import com.bytezone.diskbrowser.utilities.HexFormatter;
import com.bytezone.diskbrowser.utilities.Utility;
// -----------------------------------------------------------------------------------//
class ItemV1 extends Item // implements Comparable<ItemV1>
// -----------------------------------------------------------------------------------//
{
// public int partyOwns;
// static int counter = 0;
// ---------------------------------------------------------------------------------//
ItemV1 (int itemId, String name, byte[] buffer)
// ---------------------------------------------------------------------------------//
{
super (name, buffer);
// itemId = counter++;
this.itemId = itemId;
genericName = HexFormatter.getPascalString (buffer, 16);
type = ObjectType.values ()[buffer[32]];
alignment = Alignment.values ()[buffer[34]];
cursed = Utility.getSignedShort (buffer, 36) == -1;
special = Utility.getSignedShort (buffer, 38);
changeTo = Utility.getShort (buffer, 40); // decay #
changeChance = Utility.getShort (buffer, 42);
price = Utility.getWizLong (buffer, 44);
boltac = Utility.getSignedShort (buffer, 50);
spellPwr = Utility.getShort (buffer, 52);
classUseFlags = Utility.getShort (buffer, 54); // 8 flags
healPts = Utility.getSignedShort (buffer, 56);
flags2 = Utility.getShort (buffer, 58); // 16 flags
flags3 = Utility.getShort (buffer, 60); // 16 flags
armourClass = Utility.getSignedShort (buffer, 62);
wephitmd = Utility.getSignedShort (buffer, 64);
wephpdam = new Dice (buffer, 66); // Dice
xtraSwing = Utility.getShort (buffer, 72);
crithitm = Utility.getShort (buffer, 74) == 1; // boolean
flags1 = Utility.getShort (buffer, 76); // 14 flags
}
// ---------------------------------------------------------------------------------//
void link (List<ItemV1> items, List<Spell> spells)
// ---------------------------------------------------------------------------------//
{
if (changeChance > 0)
changeToItem = items.get (changeTo);
if (spellPwr > 0)
spell = spells.get (spellPwr - 1);
}
// ---------------------------------------------------------------------------------//
@Override
public String getText ()
// ---------------------------------------------------------------------------------//
{
StringBuilder text = new StringBuilder (super.getText ());
// int stock = getStockOnHand ();
// text.append ("\nStock on hand : " + stock);
// if (stock < 0)
// text.append (" (always in stock)");
return text.toString ();
}
// ---------------------------------------------------------------------------------//
public long getCost ()
// ---------------------------------------------------------------------------------//
{
return price;
}
// ---------------------------------------------------------------------------------//
public int getStockOnHand ()
// ---------------------------------------------------------------------------------//
{
// if (buffer[50] == -1 && buffer[51] == -1)
// return -1;
//
// return Utility.getShort (buffer, 50);
return boltac;
}
// ---------------------------------------------------------------------------------//
public boolean canUse (int type2)
// ---------------------------------------------------------------------------------//
{
int users = buffer[54] & 0xFF;
return ((users >>> type2) & 1) == 1;
}
// ---------------------------------------------------------------------------------//
@Override
public String toString ()
// ---------------------------------------------------------------------------------//
{
StringBuilder line = new StringBuilder ();
line.append (String.format ("%-16s", getName ()));
if (buffer[36] == -1)
line.append ("(c) ");
else
line.append (" ");
line.append (String.format ("%02X ", buffer[62]));
line.append (String.format ("%02X ", buffer[34]));
line.append (String.format ("%02X %02X", buffer[50], buffer[51]));
// if (buffer[50] == -1 && buffer[51] == -1)
// line.append ("* ");
// else
// line.append (HexFormatter.intValue (buffer[50], buffer[51]) + " ");
for (int i = 38; i < 44; i++)
line.append (HexFormatter.format2 (buffer[i]) + " ");
for (int i = 48; i < 50; i++)
line.append (HexFormatter.format2 (buffer[i]) + " ");
for (int i = 52; i < 62; i++)
line.append (HexFormatter.format2 (buffer[i]) + " ");
// for (int i = 64; i < 78; i++)
// line.append (HexFormatter.format2 (buffer[i]) + " ");
return line.toString ();
}
// ---------------------------------------------------------------------------------//
public String getDump (int block)
// ---------------------------------------------------------------------------------//
{
StringBuilder line = new StringBuilder (String.format ("%3d %-16s", itemId, getName ()));
int lo = block == 0 ? 32 : block == 1 ? 56 : 80;
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]));
return line.toString ();
}
// ---------------------------------------------------------------------------------//
// @Override
// public int compareTo (ItemV1 otherItem)
// // ---------------------------------------------------------------------------------//
// {
// ItemV1 item = otherItem;
// return this.type - item.type;
// }
}

View File

@ -0,0 +1,76 @@
package com.bytezone.diskbrowser.wizardry;
import java.util.List;
import com.bytezone.diskbrowser.utilities.Utility;
// -----------------------------------------------------------------------------------//
public class ItemV4 extends Item
// -----------------------------------------------------------------------------------//
{
// ---------------------------------------------------------------------------------//
ItemV4 (String[] names, byte[] buffer, int id)
// ---------------------------------------------------------------------------------//
{
super (names[1], buffer);
itemId = id;
name = names[1];
genericName = names[0];
type = ObjectType.values ()[buffer[1]];
alignment = Alignment.values ()[buffer[3]];
cursed = Utility.getSignedShort (buffer, 5) == -1;
special = Utility.getSignedShort (buffer, 7);
changeTo = Utility.getShort (buffer, 9); // decay #
changeChance = Utility.getShort (buffer, 11);
price = Utility.getWizLong (buffer, 13);
boltac = Utility.getSignedShort (buffer, 19);
spellPwr = Utility.getShort (buffer, 21);
classUseFlags = Utility.getShort (buffer, 23); // 8 flags
healPts = Utility.getSignedShort (buffer, 25);
flags2 = Utility.getShort (buffer, 27); // 16 flags
flags3 = Utility.getShort (buffer, 29); // 16 flags
armourClass = Utility.getSignedShort (buffer, 31);
wephitmd = Utility.getSignedShort (buffer, 33);
wephpdam = new Dice (buffer, 35);
xtraSwing = Utility.getShort (buffer, 41);
crithitm = Utility.getShort (buffer, 43) == 1; // boolean
flags1 = Utility.getShort (buffer, 45); // 14 flags
}
// ---------------------------------------------------------------------------------//
void link (List<ItemV4> items, List<String> spellNames)
// ---------------------------------------------------------------------------------//
{
if (changeChance > 0)
changeToItem = items.get (changeTo);
if (spellPwr > 0)
spellName = spellNames.get (spellPwr);
}
// ---------------------------------------------------------------------------------//
@Override
public String getText ()
// ---------------------------------------------------------------------------------//
{
StringBuilder text = new StringBuilder (super.getText ());
// text.append ("\n\n");
// text.append (HexFormatter.format (buffer));
return text.toString ();
}
// ---------------------------------------------------------------------------------//
@Override
public String toString ()
// ---------------------------------------------------------------------------------//
{
return name;
}
}

View File

@ -11,7 +11,9 @@ import com.bytezone.diskbrowser.utilities.HexFormatter;
class MazeCell class MazeCell
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
{ {
static Dimension cellSize = new Dimension (22, 22); // size in pixels static final Dimension cellSize = new Dimension (22, 22); // size in pixels
static final Color SECRET_DOOR = Color.RED;
static final Color DOOR = Color.GREEN;
boolean northWall; boolean northWall;
boolean southWall; boolean southWall;
@ -47,10 +49,10 @@ class MazeCell
MazeAddress address; MazeAddress address;
MazeAddress addressTo; // if teleport/stairs/chute MazeAddress addressTo; // if teleport/stairs/chute
public Message message; public MessageV1 message;
public List<Monster> monsters; public List<MonsterV1> monsters;
public Item itemRequired; public ItemV1 itemRequired;
public Item itemObtained; public ItemV1 itemObtained;
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
MazeCell (MazeAddress address) MazeCell (MazeAddress address)
@ -64,7 +66,7 @@ class MazeCell
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
g.setColor (Color.BLACK); g.setColor (Color.BLACK);
g.fillRect (x, y, 22, 22); g.fillRect (x, y, cellSize.width, cellSize.height);
g.setColor (Color.WHITE); g.setColor (Color.WHITE);
@ -77,7 +79,7 @@ class MazeCell
if (southWall) if (southWall)
drawSouth (g, x, y); drawSouth (g, x, y);
g.setColor (Color.RED); g.setColor (DOOR);
if (westDoor) if (westDoor)
drawWest (g, x, y); drawWest (g, x, y);
@ -88,7 +90,7 @@ class MazeCell
if (southDoor) if (southDoor)
drawSouth (g, x, y); drawSouth (g, x, y);
g.setColor (Color.GREEN); g.setColor (SECRET_DOOR);
if (westDoor && westWall) if (westDoor && westWall)
drawWest (g, x, y); drawWest (g, x, y);
@ -144,8 +146,7 @@ class MazeCell
void drawEast (Graphics2D g, int x, int y) void drawEast (Graphics2D g, int x, int y)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
g.drawLine (x + cellSize.width - 1, y + 1, x + cellSize.width - 1, g.drawLine (x + cellSize.width - 1, y + 1, x + cellSize.width - 1, y + cellSize.height - 1);
y + cellSize.height - 1);
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
@ -159,8 +160,7 @@ class MazeCell
void drawSouth (Graphics2D g, int x, int y) void drawSouth (Graphics2D g, int x, int y)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
g.drawLine (x + 1, y + cellSize.height - 1, x + cellSize.width - 1, g.drawLine (x + 1, y + cellSize.height - 1, x + cellSize.width - 1, y + cellSize.height - 1);
y + cellSize.height - 1);
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
@ -324,8 +324,8 @@ class MazeCell
sign.append ("castle&nbsp;"); sign.append ("castle&nbsp;");
else else
{ {
sign.append ("L" + addressTo.level + " " + addressTo.row + "N " + addressTo.column sign.append (
+ "E&nbsp;"); "L" + addressTo.level + " " + addressTo.row + "N " + addressTo.column + "E&nbsp;");
} }
} }
if (pit) if (pit)
@ -345,12 +345,12 @@ class MazeCell
sign.append ("&nbsp;Monster&nbsp;"); sign.append ("&nbsp;Monster&nbsp;");
else else
{ {
Monster monster = monsters.get (monsterID); MonsterV1 monster = monsters.get (monsterID);
sign.append ("&nbsp;<b>" + monster.getRealName () + "&nbsp;</b>"); sign.append ("&nbsp;<b>" + monster.getName () + "&nbsp;</b>");
while (monster.partnerOdds == 100) while (monster.partnerOdds == 100)
{ {
monster = monsters.get (monster.partnerID); monster = monsters.get (monster.partnerID);
sign.append ("<br>&nbsp;<b>" + monster.getRealName () + "&nbsp;</b>"); sign.append ("<br>&nbsp;<b>" + monster.getName () + "&nbsp;</b>");
} }
} }
if (itemRequired != null) if (itemRequired != null)

View File

@ -38,8 +38,7 @@ class MazeGridV5 extends AbstractFile
for (int col = 0; col < 8; col++) for (int col = 0; col < 8; col++)
grid[row][col] = getLayout (i, row, col); grid[row][col] = getLayout (i, row, col);
MazeGrid mazeGrid = MazeGrid mazeGrid = new MazeGrid (grid, buffer[528 + i] & 0xFF, buffer[512 + i] & 0xFF);
new MazeGrid (grid, buffer[528 + i] & 0xFF, buffer[512 + i] & 0xFF);
grids.add (mazeGrid); grids.add (mazeGrid);
minX = Math.min (minX, mazeGrid.xOffset); minX = Math.min (minX, mazeGrid.xOffset);
@ -60,11 +59,10 @@ class MazeGridV5 extends AbstractFile
int gridWidth = (maxX - minX + 8) * cellSize.width; int gridWidth = (maxX - minX + 8) * cellSize.width;
int gridHeight = (maxY - minY + 7) * cellSize.height; int gridHeight = (maxY - minY + 7) * cellSize.height;
image = new BufferedImage (gridWidth + 1, gridHeight + fudge, image =
BufferedImage.TYPE_USHORT_555_RGB); new BufferedImage (gridWidth + 1, gridHeight + fudge, BufferedImage.TYPE_USHORT_555_RGB);
Graphics2D g = image.createGraphics (); Graphics2D g = image.createGraphics ();
g.setRenderingHint (RenderingHints.KEY_ANTIALIASING, g.setRenderingHint (RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor (Color.LIGHT_GRAY); g.setColor (Color.LIGHT_GRAY);
g.fillRect (0, 0, gridWidth + 1, gridHeight + fudge); g.fillRect (0, 0, gridWidth + 1, gridHeight + fudge);
@ -183,8 +181,7 @@ class MazeGridV5 extends AbstractFile
{ {
List<String> messages = messageBlock.getMessageLines (msg); List<String> messages = messageBlock.getMessageLines (msg);
if (messages.size () > 0) if (messages.size () > 0)
text.append ( text.append (String.format ("%n%4d %02X %04X %s%n", i, i, msg, messages.get (0)));
String.format ("%n%4d %02X %04X %s%n", i, i, msg, messages.get (0)));
else else
text.append (String.format ("Message not found: %04X%n", msg)); text.append (String.format ("Message not found: %04X%n", msg));

View File

@ -12,13 +12,21 @@ import com.bytezone.diskbrowser.utilities.HexFormatter;
import com.bytezone.diskbrowser.utilities.Utility; import com.bytezone.diskbrowser.utilities.Utility;
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
class MazeLevel extends AbstractFile public class MazeLevel extends AbstractFile
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
{ {
private static final int AUX0 = 768;
private static final int AUX1 = 800;
private static final int AUX2 = 832;
private static final String[] squareType =
{ "Normal", "Stairs", "Pit", "Chute", "Spinner", "Darkness", "Teleport", "Ouch", "Elevator",
"Rock/Water", "Fizzle", "Message/Item", "Monster" };
public final int level; public final int level;
private List<Message> messages; private List<MessageV1> messages;
private List<Monster> monsters; private List<MonsterV1> monsters;
private List<Item> items; private List<ItemV1> items;
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
public MazeLevel (byte[] buffer, int level) public MazeLevel (byte[] buffer, int level)
@ -30,110 +38,63 @@ class MazeLevel extends AbstractFile
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
@Override @Override
public String getHexDump () public String getText ()
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
StringBuilder text = new StringBuilder (); StringBuilder text = new StringBuilder ();
text.append ("West walls/doors\n\n"); text.append ("West walls/doors\n\n");
text.append (HexFormatter.format (buffer, 0, 120)); text.append (HexFormatter.format (buffer, 0, 120, true, 0));
addWalls (text, 0); addWalls (text, 0);
text.append ("\nSouth walls/doors\n\n"); text.append ("\nSouth walls/doors\n\n");
text.append (HexFormatter.format (buffer, 120, 120)); text.append (HexFormatter.format (buffer, 120, 120, true, 120));
addWalls (text, 120); addWalls (text, 120);
text.append ("\nEast walls/doors\n\n"); text.append ("\nEast walls/doors\n\n");
text.append (HexFormatter.format (buffer, 240, 120)); text.append (HexFormatter.format (buffer, 240, 120, true, 240));
addWalls (text, 240); addWalls (text, 240);
text.append ("\nNorth walls/doors\n\n"); text.append ("\nNorth walls/doors\n\n");
text.append (HexFormatter.format (buffer, 360, 120)); text.append (HexFormatter.format (buffer, 360, 120, true, 360));
addWalls (text, 360); addWalls (text, 360);
text.append ("\nEncounters\n\n"); text.append ("\nFIGHTS\n\n");
text.append (HexFormatter.format (buffer, 480, 80)); text.append (HexFormatter.format (buffer, 480, 80, true, 480));
addEncounters (text, 480); addEncounters (text, 480);
text.append ("\nExtras\n\n"); text.append ("\nSQREXTRA\n\n");
text.append (HexFormatter.format (buffer, 560, 200)); text.append (HexFormatter.format (buffer, 560, 200, true, 560));
addExtras (text, 560); addExtras (text, 560);
text.append ("\nIndex\n\n"); text.append ("\nSQRTYPE\n\n");
text.append ( text.append (String.format ("%04X: %s%n", 760, HexFormatter.getHexString (buffer, 760, 8)));
String.format ("%04X: %s%n", 760, HexFormatter.getHexString (buffer, 760, 8)));
text.append ("\nTable\n\n"); text.append ("\nAUX0\n\n");
text.append (HexFormatter.format (buffer, 768, 96)); text.append (HexFormatter.format (buffer, AUX0, 32, true, AUX0));
text.append ("\n");
text.append ("\n\n 0 1 2 3 4 5 6 7 8 9 A B C D E F\n"); text.append ("\nAUX1\n\n");
text.append (String.format ("%04X: ", 760)); text.append (HexFormatter.format (buffer, AUX1, 32, true, AUX1));
for (int i = 0; i < 8; i++) text.append ("\n");
{
int val = buffer[760 + i] & 0xFF;
text.append (String.format ("%X:%X ", val % 16, val / 16));
}
String[] extras = text.append ("\nAUX2\n\n");
{ "", "Stairs", "Pit", "Chute", "Spinner", "Darkness", "Teleport", "Ouch", text.append (HexFormatter.format (buffer, AUX2, 32, true, AUX2));
"Elevator", "Rock/Water", "Fizzle", "Message/Item", "Monster" }; text.append ("\n");
List<MazeAddress> messageList = new ArrayList<> (); List<MazeAddress> messageList = new ArrayList<> ();
List<MazeAddress> monsterList = new ArrayList<> (); List<MazeAddress> monsterList = new ArrayList<> ();
text.append ("\n\nValue Index Contains Table\n"); addTable (text, messageList, monsterList);
for (int j = 0; j < 16; j++)
{
String extraText = "";
int val = buffer[760 + j / 2] & 0xFF;
String extra = (j % 2) == 0 ? extras[val % 16] : extras[val / 16];
MazeAddress address = getAddress (j);
int cellFlag = (j % 2) == 0 ? val % 16 : val / 16;
if (cellFlag == 11)
{
extraText = "Msg:" + String.format ("%04X ", address.row);
messageList.add (address); // to print at the end
int messageType = address.column; text.append ("\n\nENMYCALC\n\n");
if (messageType == 2) text.append (HexFormatter.format (buffer, 864, buffer.length - 864, true, 864));
{ addEnmyCalc (text, 864);
extraText += "Obtained: ";
if (items != null)
extraText += items.get (address.level).getName ();
}
if (messageType == 5) text.append ("\n\n");
{
extraText += "Requires: ";
if (items != null)
extraText += items.get (address.level).getName ();
}
if (messageType == 4)
{
extraText += "Unknown";
}
}
if (cellFlag == 12)
{
monsterList.add (address);
extraText = "Encounter: ";
if (monsters != null)
extraText += monsters.get (address.column).realName;
}
text.append (String.format (" %X --> %X %-15s %04X %04X %04X %s%n", j,
cellFlag, extra, address.level, address.row, address.column, extraText));
}
text.append ("\n\nRest\n\n");
text.append (HexFormatter.format (buffer, 864, buffer.length - 864));
text.append ("\n");
for (MazeAddress address : messageList) for (MazeAddress address : messageList)
{ {
Message message = getMessage (address.row); MessageV1 message = getMessage (address.row);
if (message != null) if (message != null)
{ {
text.append (String.format ("%nMessage: %04X (%d)%n", address.row, address.row)); text.append (String.format ("%nMessage: %04X (%d)%n", address.row, address.row));
@ -144,7 +105,7 @@ class MazeLevel extends AbstractFile
for (MazeAddress address : monsterList) for (MazeAddress address : monsterList)
{ {
Monster monster = getMonster (address.column); MonsterV1 monster = getMonster (address.column);
if (monster != null) if (monster != null)
{ {
text.append (String.format ("%nMonster: %04X%n", address.column)); text.append (String.format ("%nMonster: %04X%n", address.column));
@ -161,9 +122,27 @@ class MazeLevel extends AbstractFile
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
text.append ("\n\n"); text.append ("\n\n");
for (int i = 0; i < 20; i++)
text.append (String.format (" Col %2d: %s%n", i, for (int col = 0; col < 20; col++)
HexFormatter.getHexString (buffer, ptr + i * 6, 6))); {
text.append (
String.format (" Col %2d : %s : ", col, HexFormatter.getHexString (buffer, ptr, 6)));
for (int i = 0; i < 5; i++)
{
int val = buffer[ptr++] & 0xFF;
for (int j = 0; j < 4; j++)
{
int wall = (val & 0x03); // right to left ordering
text.append (String.format ("%d ", wall));
val >>>= 2;
}
}
// assert buffer[ptr] == 0;
ptr++; // skip last byte
text.append ("\n");
}
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
@ -173,25 +152,15 @@ class MazeLevel extends AbstractFile
text.append ("\n\n"); text.append ("\n\n");
for (int i = 0; i < 20; i++) for (int i = 0; i < 20; i++)
{ {
text.append (String.format (" Col %2d: %s ", i, text.append (
HexFormatter.getHexString (buffer, ptr + i * 4, 4))); String.format (" Col %2d: %s ", i, HexFormatter.getHexString (buffer, ptr + i * 4, 4)));
StringBuilder bitString = new StringBuilder (); int val = Utility.readTriple (buffer, ptr + i * 4);
for (int j = 2; j >= 0; j--) for (int j = 0; j < 20; j++)
{ {
byte b = buffer[ptr + i * 4 + j]; text.append ((val & 0x01) == 0 ? " " : " 1");
String s = ("0000000" + Integer.toBinaryString (0xFF & b)) val >>>= 1;
.replaceAll (".*(.{8})$", "$1");
bitString.append (s);
// text.append (s);
// text.append (" ");
} }
String bitsReversed = bitString.reverse ().toString ();
bitsReversed = bitsReversed.replace ("1", " 1");
bitsReversed = bitsReversed.replace ("0", " ");
text.append (bitsReversed.substring (0, 40));
text.append (" : ");
text.append (bitsReversed.substring (40));
text.append ("\n"); text.append ("\n");
} }
} }
@ -206,15 +175,125 @@ class MazeLevel extends AbstractFile
text.append (String.format (" Col %2d: ", i)); text.append (String.format (" Col %2d: ", i));
for (int j = 0; j < 10; j++) for (int j = 0; j < 10; j++)
{ {
int val = buffer[ptr + i * 10 + j] & 0xFF; int val = buffer[ptr++] & 0xFF;
int left = val / 16; // 0:F int left = (val & 0xF0) >> 4;
int right = val % 16; // 0:F int right = (val & 0x0F);
text.append (String.format ("%X:%X ", right, left)); String sLeft = left == 0 ? " " : String.format ("%X", left);
String sRight = right == 0 ? " " : String.format ("%X", right);
text.append (String.format ("%s %s ", sRight, sLeft));
} }
text.append ("\n"); text.append ("\n");
} }
} }
// ---------------------------------------------------------------------------------//
private void addTable (StringBuilder text, List<MazeAddress> messageList,
List<MazeAddress> monsterList)
// ---------------------------------------------------------------------------------//
{
if (monsters == null)
{
System.out.println ("monsters is null");
return;
}
text.append ("\n\nSQREXTRA SQRTYPE TSQUARE AUX0 AUX1 AUX2\n");
for (int j = 0; j < 16; j++)
{
String extraText = "";
int val = buffer[760 + j / 2] & 0xFF;
String extra = (j % 2) == 0 ? squareType[val % 16] : squareType[val / 16];
MazeAddress address = getAddress (j);
int cellFlag = (j % 2) == 0 ? val % 16 : val / 16;
if (cellFlag == 11)
{
extraText = "Msg:" + String.format ("%04X ", address.row);
messageList.add (address); // to print at the end
int messageType = address.column; // AUX3
if (messageType == 2)
{
extraText += "Obtained: ";
if (items != null)
extraText += items.get (address.level).getName ();
}
if (messageType == 4)
{
if (address.level < monsters.size ())
extraText += monsters.get (address.level).getName ();
else
extraText += "Obtained: " + items.get ((address.level - 64536) * -1).getName ();
}
if (messageType == 5)
{
extraText += "Requires: ";
if (items != null)
extraText += items.get (address.level).getName ();
}
}
if (cellFlag == 12)
{
monsterList.add (address);
extraText = "Encounter: ";
if (monsters != null)
extraText += monsters.get (address.column).getName ();
}
text.append (String.format (" %X --> %X %-15s %04X %04X %04X %s%n", j,
cellFlag, extra, address.level, address.row, address.column, extraText));
}
}
// ---------------------------------------------------------------------------------//
private void addEnmyCalc (StringBuilder text, int ptr)
// ---------------------------------------------------------------------------------//
{
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)));
ptr += 2;
text.append (String.format ("MULTWORS %04X %04X %04X%n", Utility.getShort (buffer, ptr),
Utility.getShort (buffer, ptr + 10), Utility.getShort (buffer, ptr + 20)));
ptr += 2;
text.append (String.format ("WORSE01 %04X %04X %04X%n", Utility.getShort (buffer, ptr),
Utility.getShort (buffer, ptr + 10), Utility.getShort (buffer, ptr + 20)));
ptr += 2;
text.append (String.format ("RANGE0N %04X %04X %04X%n", Utility.getShort (buffer, ptr),
Utility.getShort (buffer, ptr + 10), Utility.getShort (buffer, ptr + 20)));
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");
MonsterV1 monster = monsters == null ? null : monsters.get (id);
text.append (String.format ("%3d %-16s %n", id, monster));
}
}
}
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
@Override @Override
public BufferedImage getImage () public BufferedImage getImage ()
@ -224,8 +303,7 @@ class MazeLevel extends AbstractFile
image = new BufferedImage (20 * cellSize.width + 1, 20 * cellSize.height + 1, image = new BufferedImage (20 * cellSize.width + 1, 20 * cellSize.height + 1,
BufferedImage.TYPE_USHORT_555_RGB); BufferedImage.TYPE_USHORT_555_RGB);
Graphics2D g = image.createGraphics (); Graphics2D g = image.createGraphics ();
g.setRenderingHint (RenderingHints.KEY_ANTIALIASING, g.setRenderingHint (RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
RenderingHints.VALUE_ANTIALIAS_ON);
for (int row = 0; row < 20; row++) for (int row = 0; row < 20; row++)
for (int column = 0; column < 20; column++) for (int column = 0; column < 20; column++)
@ -235,25 +313,26 @@ class MazeLevel extends AbstractFile
int y = image.getHeight () - (row + 1) * cellSize.height - 1; int y = image.getHeight () - (row + 1) * cellSize.height - 1;
cell.draw (g, x, y); cell.draw (g, x, y);
} }
return image; return image;
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
public void setMessages (List<Message> messages) public void setMessages (List<MessageV1> messages)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
this.messages = messages; this.messages = messages;
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
public void setMonsters (List<Monster> monsters) public void setMonsters (List<MonsterV1> monsters)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
this.monsters = monsters; this.monsters = monsters;
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
public void setItems (List<Item> items) public void setItems (List<ItemV1> items)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
this.items = items; this.items = items;
@ -274,9 +353,9 @@ class MazeLevel extends AbstractFile
int offset = column * BYTES_PER_COL + row / CELLS_PER_BYTE; int offset = column * BYTES_PER_COL + row / CELLS_PER_BYTE;
int value = buffer[offset] & 0xFF; int value = buffer[offset] & 0xFF;
value >>>= (row % CELLS_PER_BYTE) * BITS_PER_ROW; // push 0, 2, 4, 6 bits value >>>= (row % CELLS_PER_BYTE) * BITS_PER_ROW; // shift 0, 2, 4, 6 bits
cell.westWall = ((value & 1) == 1); // use rightmost bit cell.westWall = ((value & 1) == 1); // use rightmost bit
value >>>= 1; // push 1 bit value >>>= 1; // shift 1 bit
cell.westDoor = ((value & 1) == 1); // use rightmost bit cell.westDoor = ((value & 1) == 1); // use rightmost bit
value = buffer[offset + 120] & 0xFF; value = buffer[offset + 120] & 0xFF;
@ -321,106 +400,95 @@ class MazeLevel extends AbstractFile
case 0: // normal case 0: // normal
break; break;
case 1: case 1: // stairs
cell.stairs = true; cell.stairs = true;
cell.addressTo = getAddress (b); cell.addressTo = getAddress (b);
break; break;
case 2: case 2: // pit
cell.pit = true; cell.pit = true;
break; break;
case 3: case 3: // chute
cell.chute = true; cell.chute = true;
cell.addressTo = getAddress (b); cell.addressTo = getAddress (b);
break; break;
case 4: case 4: // spinner
cell.spinner = true; cell.spinner = true;
break; break;
case 5: case 5: // dark
cell.darkness = true; cell.darkness = true;
break; break;
case 6: case 6: // transfer
cell.teleport = true; cell.teleport = true;
cell.addressTo = getAddress (b); cell.addressTo = getAddress (b);
break; break;
case 7: // ouchy case 7: // ouchy
cell.unknown = cellFlag; cell.unknown = cellFlag;
break; break;
case 8: // buttonz case 8: // buttonz
cell.elevator = true; cell.elevator = true;
MazeAddress elevatorAddress = getAddress (b); MazeAddress elevatorAddress = getAddress (b);
cell.elevatorTo = elevatorAddress.row; cell.elevatorTo = elevatorAddress.row;
// HexFormatter.intValue (buffer[800 + b * 2], buffer[801 + b * 2]);
cell.elevatorFrom = elevatorAddress.column; cell.elevatorFrom = elevatorAddress.column;
// HexFormatter.intValue (buffer[832 + b * 2], buffer[833 + b * 2]);
break; break;
case 9: // rock/water case 9: // rock/water
cell.rock = true; cell.rock = true;
break; break;
case 10: // fizzle case 10: // fizzle
cell.spellsBlocked = true; cell.spellsBlocked = true;
break; break;
case 11: // screen message case 11: // screen message
MazeAddress messageAddress = getAddress (b); MazeAddress messageAddress = getAddress (b);
// int messageNum = HexFormatter.intValue (buffer[800 + b * 2], buffer[801 + b * 2]); MessageV1 m = getMessage (messageAddress.row);
Message m = getMessage (messageAddress.row);
if (m != null) if (m != null)
cell.message = m; cell.message = m;
cell.messageType = messageAddress.column; cell.messageType = messageAddress.column;
// HexFormatter.intValue (buffer[832 + b * 2], buffer[833 + b * 2]);
int itemID = -1; switch (cell.messageType)
if (cell.messageType == 2 && items != null) // obtain Item
{ {
// itemID = HexFormatter.intValue (buffer[768 + b * 2], buffer[769 + b * 2]); case 2: // obtain Item
itemID = messageAddress.level; if (items != null)
cell.itemObtained = items.get (itemID); cell.itemObtained = items.get (messageAddress.level);
break;
case 4:
int itemID = messageAddress.level;
if (itemID <= 100)
{
cell.monsterID = itemID;
cell.monsters = monsters;
}
else
{
int val = (itemID - 64536) * -1;
// this gives Index error: 20410, Size 104 in Wizardry_III/legacy2.dsk
if (items != null && val < items.size ())
cell.itemObtained = items.get (val); // check this
if (cell.itemObtained == null)
System.out.printf ("Item %d (%d) not found on level %d%n", val, value, level);
}
break;
case 5: // requires Item
if (items != null)
cell.itemRequired = items.get (messageAddress.level);
break;
} }
if (cell.messageType == 5 && items != null) // requires Item
{
// itemID = HexFormatter.intValue (buffer[768 + b * 2], buffer[769 + b * 2]);
itemID = messageAddress.level;
cell.itemRequired = items.get (itemID);
}
if (cell.messageType == 4)
{
// value = HexFormatter.intValue (buffer[768 + b * 2], buffer[769 + b * 2]);
itemID = messageAddress.level;
if (value <= 100)
{
cell.monsterID = value;
cell.monsters = monsters;
}
else
{
int val = (value - 64536) * -1;
System.out.println ("Value : " + val);
// this gives Index error: 20410, Size 104 in Wizardry_III/legacy2.dsk
if (items != null && val < items.size ())
cell.itemObtained = items.get (val); // check this
if (cell.itemObtained == null)
System.out.printf ("Item %d not found%n", val);
}
}
break; break;
case 12: // encounter case 12: // encounter
MazeAddress monsterAddress = getAddress (b); MazeAddress monsterAddress = getAddress (b);
// cell.monsterID = HexFormatter.intValue (buffer[832 + b * 2], buffer[833 + b * 2]);
cell.monsterID = monsterAddress.column; cell.monsterID = monsterAddress.column;
cell.monsters = monsters; cell.monsters = monsters;
break; break;
@ -438,19 +506,20 @@ class MazeLevel extends AbstractFile
private MazeAddress getAddress (int b) // 0:F private MazeAddress getAddress (int b) // 0:F
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
int x = b * 2; // converts AUX1, AUX2, AUX3 into a MazeAddress (level, row, column)
return new MazeAddress (Utility.getShort (buffer, 768 + x), b *= 2;
Utility.getShort (buffer, 800 + x), Utility.getShort (buffer, 832 + x)); return new MazeAddress (Utility.getShort (buffer, 768 + b), Utility.getShort (buffer, 800 + b),
Utility.getShort (buffer, 832 + b));
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
private Message getMessage (int messageNo) private MessageV1 getMessage (int messageNo)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
if (messages == null) if (messages == null)
return null; return null;
for (Message m : messages) for (MessageV1 m : messages)
if (m.match (messageNo)) if (m.match (messageNo))
return m; return m;
@ -458,13 +527,13 @@ class MazeLevel extends AbstractFile
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
private Monster getMonster (int monsterNo) private MonsterV1 getMonster (int monsterNo)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
if (monsters == null) if (monsters == null)
return null; return null;
for (Monster m : monsters) for (MonsterV1 m : monsters)
if (m.match (monsterNo)) if (m.match (monsterNo))
return m; return m;

View File

@ -33,14 +33,27 @@ class MessageBlock extends AbstractFile implements Iterable<MessageDataBlock>
int firstMessageNo = Utility.getShort (buffer, ptr + i * 2); int firstMessageNo = Utility.getShort (buffer, ptr + i * 2);
byte[] data = new byte[512]; byte[] data = new byte[512];
System.arraycopy (buffer, i * 512, data, 0, data.length); System.arraycopy (buffer, i * 512, data, 0, data.length);
MessageDataBlock messageDataBlock = new MessageDataBlock ( MessageDataBlock messageDataBlock =
" Message " + firstMessageNo, data, firstMessageNo, huffman); new MessageDataBlock (" Message " + firstMessageNo, data, firstMessageNo, huffman);
messageDataBlocks.add (messageDataBlock); messageDataBlocks.add (messageDataBlock);
} }
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
public String getMessageText (int messageNo) public byte[] getMessage (int messageNo)
// ---------------------------------------------------------------------------------//
{
for (int i = 0; i < messageDataBlocks.size (); i++)
{
MessageDataBlock messageDataBlock = messageDataBlocks.get (i);
if (messageDataBlock.firstMessageNo > messageNo)
return messageDataBlocks.get (i - 1).getMessage (messageNo);
}
return null;
}
// ---------------------------------------------------------------------------------//
public String getMessageLine (int messageNo)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
for (int i = 0; i < messageDataBlocks.size (); i++) for (int i = 0; i < messageDataBlocks.size (); i++)
@ -80,38 +93,25 @@ class MessageBlock extends AbstractFile implements Iterable<MessageDataBlock>
return lines; return lines;
} }
// ---------------------------------------------------------------------------------//
public byte[] getMessage (int messageNo)
// ---------------------------------------------------------------------------------//
{
for (int i = 0; i < messageDataBlocks.size (); i++)
{
MessageDataBlock messageDataBlock = messageDataBlocks.get (i);
if (messageDataBlock.firstMessageNo > messageNo)
return messageDataBlocks.get (i - 1).getMessage (messageNo);
}
return null;
}
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
@Override @Override
public String getText () public String getText ()
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
if (text != null) if (text == null)
return text;
StringBuilder text = new StringBuilder ();
for (MessageDataBlock mdb : messageDataBlocks)
{ {
text.append (mdb); StringBuilder sb = new StringBuilder ();
text.append ("\n");
for (MessageDataBlock mdb : messageDataBlocks)
{
sb.append (mdb);
sb.append ("\n");
}
text = sb.toString ();
} }
this.text = text.toString (); return text;
return this.text;
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//

View File

@ -6,7 +6,7 @@ import java.util.List;
import com.bytezone.diskbrowser.applefile.AbstractFile; import com.bytezone.diskbrowser.applefile.AbstractFile;
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
abstract class Message extends AbstractFile abstract class MessageV1 extends AbstractFile
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
{ {
private static int nextId = 0; private static int nextId = 0;
@ -16,7 +16,7 @@ abstract class Message extends AbstractFile
List<String> lines = new ArrayList<> (); List<String> lines = new ArrayList<> ();
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
Message (byte[] buffer) MessageV1 (byte[] buffer)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
super ("Message " + nextId, buffer); super ("Message " + nextId, buffer);
@ -68,11 +68,13 @@ abstract class Message extends AbstractFile
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
StringBuilder message = new StringBuilder (); StringBuilder message = new StringBuilder ();
for (String line : lines) for (String line : lines)
message.append ("&nbsp;" + line + "&nbsp;<br>"); message.append ("&nbsp;" + line + "&nbsp;<br>");
if (message.length () > 0) if (message.length () > 0)
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
message.deleteCharAt (message.length () - 1); // remove <br> tag message.deleteCharAt (message.length () - 1); // remove <br> tag
return message.toString (); return message.toString ();
} }

286
src/com/bytezone/diskbrowser/wizardry/Monster.java Executable file → Normal file
View File

@ -1,105 +1,47 @@
package com.bytezone.diskbrowser.wizardry; package com.bytezone.diskbrowser.wizardry;
import java.awt.image.BufferedImage;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import com.bytezone.diskbrowser.applefile.AbstractFile; import com.bytezone.diskbrowser.applefile.AbstractFile;
import com.bytezone.diskbrowser.utilities.HexFormatter;
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
class Monster extends AbstractFile public abstract class Monster extends AbstractFile
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
{ {
public final String genericName; public static final String[] monsterClass = { "Fighter", "Mage", "Priest", "Thief", "Midget",
public final String realName; "Giant", "Mythical", "Dragon", "Animal", "Were", "Undead", "Demon", "Insect", "Enchanted" };
public final int monsterID; protected final String[] breathValues =
List<Monster> monsters; { "None", "Fire", "Frost", "Poison", "Level drain", "Stoning", "Magic" };
Reward goldReward;
Reward chestReward;
public final int type; public int monsterID;
public final int imageID;
int rewardTable1; public String genericName;
int rewardTable2; public String genericNamePlural;
public final int partnerID; public String namePlural;
public final int partnerOdds;
public final int armourClass; public Dice groupSize;
public final int speed; public Dice hitPoints;
public final int mageSpellLevel; int type;
public final int priestSpellLevel; public int armourClass;
int levelDrain; public int recsn;
int bonus1;
int bonus2;
int bonus3;
int resistance;
int abilities;
public final Dice groupSize, hitPoints;
List<Dice> damage = new ArrayList<> (); List<Dice> damage = new ArrayList<> ();
static int counter = 0; public int mageSpellLevel;
static boolean debug = true; public int priestSpellLevel;
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 = int levelDrain;
{ "Fighter", "Mage", "Priest", "Thief", "Midget", "Giant", "Mythical", "Dragon", int healPts;
"Animal", "Were", "Undead", "Demon", "Insect", "Enchanted" }; int breathe;
int unaffect;
private static int[] experience = { // int resistance;
55, 235, 415, 230, 380, 620, 840, 520, 550, 350, // 00-09 int abilities;
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, 1120, 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, 1900 // 90-100
};
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
Monster (String name, byte[] buffer, List<Reward> rewards, List<Monster> monsters) Monster (String name, byte[] buffer)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
super (name, buffer); super (name, buffer);
realName = name;
genericName = HexFormatter.getPascalString (buffer, 0);
this.monsterID = counter++;
this.monsters = monsters;
goldReward = rewards.get (buffer[136]);
chestReward = rewards.get (buffer[138]);
goldReward.addMonster (this, 0);
chestReward.addMonster (this, 1);
imageID = buffer[64];
type = buffer[78];
armourClass = buffer[80];
speed = buffer[82];
levelDrain = buffer[132];
bonus1 = buffer[134];
rewardTable1 = buffer[136];
rewardTable2 = buffer[138];
partnerID = buffer[140];
partnerOdds = buffer[142];
mageSpellLevel = buffer[144];
priestSpellLevel = buffer[146];
bonus2 = buffer[150];
bonus3 = buffer[152];
resistance = buffer[154];
abilities = buffer[156];
groupSize = new Dice (buffer, 66);
hitPoints = new Dice (buffer, 72);
for (int i = 0, ptr = 84; i < 8; i++, ptr += 6)
{
if (buffer[ptr] == 0)
break;
damage.add (new Dice (buffer, ptr));
}
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
@ -109,175 +51,51 @@ class Monster extends AbstractFile
{ {
StringBuilder text = new StringBuilder (); StringBuilder text = new StringBuilder ();
// these values definitely affect the damage a monster does (when breathing?) text.append (String.format ("ID .............. %d%n%n", monsterID));
int exp2 = ((buffer[72] & 0xFF) * (buffer[74] & 0xFF) - 1) * 20; text.append (String.format ("Name ............ %s%n", name));
int exp3 = weight2[speed]; // 1-6 text.append (String.format ("Name plural ..... %s%n", namePlural));
int exp4 = (10 - armourClass) * 40; text.append (String.format ("Generic name .... %s%n", genericName));
int exp5 = getBonus (35, mageSpellLevel); text.append (String.format ("Generic name pl . %s%n%n", genericNamePlural));
int exp6 = getBonus (35, priestSpellLevel);
int exp10 = getBonus (200, levelDrain);
int exp8 = getBonus (90, bonus1);
int exp7 = weight1[bonus3 / 10] * 80;
int exp11 = bonus2 > 0 ? exp2 + 20 : 0;
int exp12 = getBonus (35, Integer.bitCount (resistance & 0x7E));
int exp9 = getBonus (40, Integer.bitCount (abilities & 0x7F));
text.append ("ID .............. " + monsterID); text.append (String.format ("Type ............ %2d %s%n", type, monsterClass[type]));
text.append ("\nMonster name .... " + realName); text.append (String.format ("Armour class .... %d%n", armourClass));
text.append ("\nGeneric name .... " + genericName); text.append (String.format ("Group size ...... %s%n", groupSize));
text.append (String.format ("Hit points ...... %s%n%n", hitPoints));
text.append ("\n\nImage ID ........ " + imageID); text.append (String.format ("# damage ........ %d%n", recsn));
text.append ("\nGroup size ...... " + groupSize); text.append (String.format ("Damage .......... %s%n%n", getDamage ()));
text.append ("\nHit points ...... " + hitPoints);
if (debug)
text.append (" " + exp2);
text.append ("\n\nMonster class ... " + type + " " + monsterClass[type]); text.append (String.format ("Mage level ...... %d%n", mageSpellLevel));
text.append ("\nArmour class .... " + armourClass); text.append (String.format ("Priest level .... %d%n%n", priestSpellLevel));
if (debug)
text.append (" " + exp4);
text.append ("\nSpeed ........... " + speed);
if (debug)
text.append (" " + exp3);
text.append ("\n\nDamage .......... " + getDamage ()); text.append (String.format ("Level drain ..... %d%n", levelDrain));
text.append (String.format ("Heal pts ........ %d%n", healPts));
text.append (String.format ("Breathe ......... %d %s%n", breathe, breathValues[breathe]));
text.append (String.format ("Magic resist .... %d%% %n%n", unaffect));
text.append ("\n\nLevel drain ..... " + levelDrain); text.append (
if (debug) String.format ("Resistance ...... %s%n", String.format ("%3d %<02X", resistance)));
text.append (" " + exp10); text.append (String.format ("Abilities ....... %s%n", String.format ("%3d %<02X", abilities)));
text.append ("\nExtra hit pts? .. " + bonus1);
if (debug)
text.append (" " + exp8);
text.append ("\n\nPartner ID ...... " + partnerID);
if (partnerOdds > 0)
text.append (" " + monsters.get (partnerID).getName ());
text.append ("\nPartner odds .... " + partnerOdds + "%");
text.append ("\n\nMage level ...... " + mageSpellLevel);
if (debug)
text.append (" " + exp5);
text.append ("\nPriest level .... " + priestSpellLevel);
if (debug)
text.append (" " + exp6);
text.append ("\n\nExperience bonus " + bonus2);
if (debug)
text.append (" " + exp11);
text.append ("\nExperience bonus " + bonus3);
if (debug)
text.append (" " + exp7);
text.append ("\n\nResistance ...... " + String.format ("%02X", resistance));
if (debug)
text.append (" " + exp12);
text.append ("\nAbilities ....... " + String.format ("%02X", abilities));
if (debug)
text.append (" " + exp9);
text.append ("\n\nExperience ...... " + (exp2 + exp3 + exp4 + exp5 + exp6 + exp7
+ exp8 + exp9 + exp10 + exp11 + exp12));
text.append ("\n\n===== Gold reward ======");
// text.append ("\nTable ........... " + rewardTable1);
text.append ("\n" + goldReward.getText (false));
text.append ("===== Chest reward =====");
// text.append ("\nTable ........... " + rewardTable2);
text.append ("\n" + chestReward.getText (false));
while (text.charAt (text.length () - 1) == 10)
text.deleteCharAt (text.length () - 1);
return text.toString (); return text.toString ();
} }
// ---------------------------------------------------------------------------------//
public int getExperience ()
// ---------------------------------------------------------------------------------//
{
// these values definitely affect the damage a monster does (when breathing?)
int exp2 = ((buffer[72] & 0xFF) * (buffer[74] & 0xFF) - 1) * 20;
int exp3 = weight2[speed];
int exp4 = (10 - armourClass) * 40;
int exp5 = getBonus (35, mageSpellLevel);
int exp6 = getBonus (35, priestSpellLevel);
int exp10 = getBonus (200, levelDrain);
int exp8 = getBonus (90, bonus1);
int exp7 = weight1[bonus3 / 10] * 80;
int exp11 = bonus2 > 0 ? exp2 + 20 : 0;
int exp12 = getBonus (35, Integer.bitCount (resistance & 0x7E));
int exp9 = getBonus (40, Integer.bitCount (abilities & 0x7F));
return exp2 + exp3 + exp4 + exp5 + exp6 + exp7 + exp8 + exp9 + exp10 + exp11 + exp12;
}
// ---------------------------------------------------------------------------------//
private int getBonus (int base, int value)
// ---------------------------------------------------------------------------------//
{
return base * pwr[value];
}
// ---------------------------------------------------------------------------------//
public void setImage (BufferedImage image)
// ---------------------------------------------------------------------------------//
{
this.image = image;
}
// ---------------------------------------------------------------------------------//
@Override
public String getName ()
// ---------------------------------------------------------------------------------//
{
return realName;
}
// ---------------------------------------------------------------------------------//
public String getRealName ()
// ---------------------------------------------------------------------------------//
{
return realName;
}
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
public String getDamage () public String getDamage ()
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
StringBuilder text = new StringBuilder (); StringBuilder text = new StringBuilder ();
for (Dice d : damage) for (Dice d : damage)
text.append (d + ", "); text.append (d + ", ");
text.deleteCharAt (text.length () - 1);
text.deleteCharAt (text.length () - 1);
return text.toString ();
}
// ---------------------------------------------------------------------------------// if (text.length () > 0)
public String getDump (int block)
// ---------------------------------------------------------------------------------//
{
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 (); text.deleteCharAt (text.length () - 1);
line.append (String.format (" %,6d", exp)); text.deleteCharAt (text.length () - 1);
if (exp != experience[monsterID])
line.append (String.format (" %,6d", experience[monsterID]));
} }
return line.toString ();
}
// ---------------------------------------------------------------------------------// return text.toString ();
public boolean match (int monsterID)
// ---------------------------------------------------------------------------------//
{
return this.monsterID == monsterID;
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
@ -285,6 +103,6 @@ class Monster extends AbstractFile
public String toString () public String toString ()
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
return realName; return name;
} }
} }

View File

@ -0,0 +1,221 @@
package com.bytezone.diskbrowser.wizardry;
import java.util.List;
import com.bytezone.diskbrowser.utilities.HexFormatter;
import com.bytezone.diskbrowser.utilities.Utility;
// -----------------------------------------------------------------------------------//
class MonsterV1 extends Monster
// -----------------------------------------------------------------------------------//
{
int scenarioId;
List<MonsterV1> monsters;
Reward goldReward;
Reward chestReward;
final int imageID;
public final int partnerID;
public final int partnerOdds;
public final int armourClass;
int experiencePoints;
int unique;
// static int counter = 0;
// Scenario #1 values
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
};
// ---------------------------------------------------------------------------------//
MonsterV1 (int id, String name, byte[] buffer, List<Reward> rewards, List<MonsterV1> monsters,
int scenarioId)
// ---------------------------------------------------------------------------------//
{
super (name, buffer);
this.scenarioId = scenarioId;
genericName = HexFormatter.getPascalString (buffer, 0);
genericNamePlural = HexFormatter.getPascalString (buffer, 16);
namePlural = HexFormatter.getPascalString (buffer, 48);
// this.monsterID = counter++;
this.monsterID = id;
this.monsters = monsters;
imageID = buffer[64];
groupSize = new Dice (buffer, 66);
hitPoints = new Dice (buffer, 72);
type = buffer[78];
armourClass = buffer[80];
recsn = buffer[82]; // number of dice
for (int i = 0, ptr = 84; i < 7; i++, ptr += 6)
{
if (buffer[ptr] == 0)
break;
damage.add (new Dice (buffer, ptr));
}
experiencePoints = Utility.getWizLong (buffer, 126);
levelDrain = buffer[132];
healPts = buffer[134];
goldReward = rewards.get (buffer[136]);
chestReward = rewards.get (buffer[138]);
partnerID = buffer[140];
partnerOdds = buffer[142];
mageSpellLevel = buffer[144];
priestSpellLevel = buffer[146];
unique = buffer[148];
breathe = buffer[150];
unaffect = buffer[152];
resistance = buffer[154]; // bit flags
abilities = buffer[156]; // bit flags
goldReward.addMonster (this, 0);
chestReward.addMonster (this, 1);
}
// ---------------------------------------------------------------------------------//
@Override
public String getText ()
// ---------------------------------------------------------------------------------//
{
StringBuilder text = new StringBuilder (super.getText ());
int totalExperience = scenarioId == 1 ? getExperience () : experiencePoints;
text.append ("\nImage ID ........ " + imageID);
text.append ("\n\nPartner ID ...... " + partnerID);
if (partnerOdds > 0)
text.append (" " + monsters.get (partnerID).getName ());
text.append ("\nPartner odds .... " + partnerOdds + "%");
text.append ("\n\nUnique .......... " + unique);
text.append (String.format ("%n%nExperience ...... %-,7d", totalExperience));
text.append (String.format ("%n%n===== Gold reward %2d ======", goldReward.id));
// text.append ("\nTable ........... " + rewardTable1);
text.append ("\n" + goldReward.getText (false));
text.append (String.format ("===== Chest reward %2d =====", chestReward.id));
// text.append ("\nTable ........... " + rewardTable2);
text.append ("\n" + chestReward.getText (false));
while (text.charAt (text.length () - 1) == 10)
text.deleteCharAt (text.length () - 1);
return text.toString ();
}
// ---------------------------------------------------------------------------------//
private int getExperience ()
// ---------------------------------------------------------------------------------//
{
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 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)); // 6 bits
int expFlags2 = getBonus (40, Integer.bitCount (abilities & 0x7F)); // 7 bits
return expHitPoints + expAc + expMage + expPriest + expDrain + expHeal + expDamage + expUnaffect
+ expFlags1 + expFlags2;
}
// ---------------------------------------------------------------------------------//
private int getBonus (int base, int multiplier)
// ---------------------------------------------------------------------------------//
{
if (multiplier == 0)
return 0;
int total = base;
while (multiplier > 1)
{
int part = total % 10000; // get the last 4 digits
multiplier--;
total += total; // double the value
if (part >= 5000) // mimics the wizardry bug
total += 10000; // yay, free points
}
return total;
}
// ---------------------------------------------------------------------------------//
// public void setImage (BufferedImage image)
// // ---------------------------------------------------------------------------------//
// {
// this.image = image;
// }
// ---------------------------------------------------------------------------------//
@Override
public String getName ()
// ---------------------------------------------------------------------------------//
{
return name;
}
// ---------------------------------------------------------------------------------//
public String getDump (int block)
// ---------------------------------------------------------------------------------//
{
StringBuilder line = new StringBuilder (String.format ("%3d %-16s", monsterID, name));
// int lo = block == 0 ? 64 : block == 1 ? 88 : block == 2 ? 112 : 136;
int lo = 64 + block * 24;
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)
if (scenarioId == 1)
{
int exp = getExperience ();
line.append (String.format (" %,6d %,6d", exp, exp - experience[monsterID]));
}
else
line.append (String.format (" %,6d", experiencePoints));
return line.toString ();
}
// ---------------------------------------------------------------------------------//
boolean match (int monsterID)
// ---------------------------------------------------------------------------------//
{
return this.monsterID == monsterID;
}
}

View File

@ -0,0 +1,44 @@
package com.bytezone.diskbrowser.wizardry;
import com.bytezone.diskbrowser.utilities.Utility;
// -----------------------------------------------------------------------------------//
public class MonsterV4 extends Monster
// -----------------------------------------------------------------------------------//
{
// ---------------------------------------------------------------------------------//
MonsterV4 (String[] names, byte[] buffer, int id)
// ---------------------------------------------------------------------------------//
{
super (names[2], buffer);
this.monsterID = id;
genericName = names[0];
genericNamePlural = names[1];
namePlural = names[3];
groupSize = new Dice (buffer, 1);
hitPoints = new Dice (buffer, 7);
type = Utility.getShort (buffer, 13);
armourClass = Utility.getSignedShort (buffer, 15);
recsn = buffer[17]; // number of dice
for (int i = 0, ptr = 19; i < 7; i++, ptr += 6)
{
if (buffer[ptr] == 0)
break;
damage.add (new Dice (buffer, ptr));
}
levelDrain = Utility.getShort (buffer, 61);
healPts = Utility.getShort (buffer, 63);
mageSpellLevel = Utility.getShort (buffer, 65);
priestSpellLevel = Utility.getShort (buffer, 67);
breathe = Utility.getShort (buffer, 69);
unaffect = Utility.getShort (buffer, 71);
resistance = Utility.getShort (buffer, 73); // bit flags
abilities = Utility.getShort (buffer, 75); // bit flags
}
}

View File

@ -3,7 +3,7 @@ package com.bytezone.diskbrowser.wizardry;
import com.bytezone.diskbrowser.utilities.HexFormatter; import com.bytezone.diskbrowser.utilities.HexFormatter;
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
class PlainMessage extends Message class PlainMessage extends MessageV1
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
{ {
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//

View File

@ -25,7 +25,7 @@ public class Relocator extends AbstractFile
{ {
super (name, buffer); super (name, buffer);
checkByte = Utility.getShort (buffer, 0); checkByte = Utility.getShort (buffer, 0); // no of blocks?
int ptr = 2; // skip checkByte int ptr = 2; // skip checkByte
@ -38,22 +38,24 @@ public class Relocator extends AbstractFile
for (DiskRecord diskRecord : diskRecords) for (DiskRecord diskRecord : diskRecords)
for (DiskSegment diskSegment : diskRecord.diskSegments) for (DiskSegment diskSegment : diskRecord.diskSegments)
addLogicalBlock ((byte) diskRecord.diskNumber, diskSegment); {
} int lo = diskSegment.logicalBlock;
int hi = lo + diskSegment.segmentLength;
// ---------------------------------------------------------------------------------// for (int i = lo, count = 0; i < hi; i++, count++)
private void addLogicalBlock (byte disk, DiskSegment diskSegment) if (diskBlocks[i] == 0) // doesn't matter either way
// ---------------------------------------------------------------------------------// {
{ if (diskBlocks[i] != 0 && false)
int lo = diskSegment.logicalBlock; {
int hi = diskSegment.logicalBlock + diskSegment.segmentLength; System.out.print ("was: ");
System.out.printf ("diskBlocks[%d] = %d%n", i, diskBlocks[i]);
for (int i = lo, count = 0; i < hi; i++, count++) System.out.print ("now: ");
// if (diskBlocks[i] == 0) // doesn't matter either way System.out.printf ("diskBlocks[%d] = %d%n", i, diskRecord.diskNumber);
{ }
diskBlocks[i] = disk; diskBlocks[i] = diskRecord.diskNumber;
diskOffsets[i] = diskSegment.physicalBlock + count; diskOffsets[i] = diskSegment.physicalBlock + count;
} }
}
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
@ -61,10 +63,6 @@ public class Relocator extends AbstractFile
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
AppleDisk master = (AppleDisk) dataDisks[0]; AppleDisk master = (AppleDisk) dataDisks[0];
// byte[] key1 = { 0x55, 0x55, 0x15, 0x55 };
// byte[] key2 = { 0x00, 0x00, 0x01, 0x41 };
// byte[] key3 = { 0x01, 0x00, 0x01, 0x41 };
// byte[] key4 = { 0x00, 0x00, 0x15, 0x55 };
for (int logicalBlock = 0; logicalBlock < diskBlocks.length; logicalBlock++) for (int logicalBlock = 0; logicalBlock < diskBlocks.length; logicalBlock++)
{ {
@ -75,13 +73,6 @@ public class Relocator extends AbstractFile
byte[] temp = disk.readBlock (diskOffsets[logicalBlock]); byte[] temp = disk.readBlock (diskOffsets[logicalBlock]);
DiskAddress da = master.getDiskAddress (logicalBlock); DiskAddress da = master.getDiskAddress (logicalBlock);
master.writeBlock (da, temp); master.writeBlock (da, temp);
// if (da.getBlock () == 0x126)
// System.out.println (HexFormatter.format (buffer));
// if (Utility.find (temp, key1))
// if (Utility.find (temp, key2))
// if (Utility.find (temp, key3))
// if (Utility.find (temp, key4))
// System.out.println (da);
} }
} }
} }
@ -109,14 +100,15 @@ public class Relocator extends AbstractFile
int first = 0; int first = 0;
int lastDisk = diskBlocks[0]; int lastDisk = diskBlocks[0];
int lastOffset = diskOffsets[0]; int lastOffset = diskOffsets[0];
for (int i = 0; i < diskBlocks.length; i++) for (int i = 0; i < diskBlocks.length; i++)
{ {
if (diskBlocks[i] != lastDisk || diskOffsets[i] != lastOffset + i - first) if (diskBlocks[i] != lastDisk || diskOffsets[i] != lastOffset + i - first)
{ {
int size = i - first; int size = i - first;
if (lastDisk > 0) if (lastDisk > 0)
lines.add (String.format ("%03X - %03X %03X %d %03X - %03X", first, lines.add (String.format ("%03X - %03X %03X %d %03X - %03X", first, i - 1, size,
i - 1, size, lastDisk, lastOffset, lastOffset + size - 1)); lastDisk, lastOffset, lastOffset + size - 1));
else else
lines.add (String.format ("%03X - %03X %03X", first, i - 1, size)); lines.add (String.format ("%03X - %03X %03X", first, i - 1, size));
@ -130,8 +122,8 @@ public class Relocator extends AbstractFile
{ {
int max = diskBlocks.length; int max = diskBlocks.length;
int size = max - first; int size = max - first;
lines.add (String.format ("%03X - %03X %03X %d %03X - %03X", first, max - 1, lines.add (String.format ("%03X - %03X %03X %d %03X - %03X", first, max - 1, size,
size, lastDisk, lastOffset, lastOffset + size - 1)); lastDisk, lastOffset, lastOffset + size - 1));
} }
for (int i = lines.size () - 1; i >= 0; i--) for (int i = lines.size () - 1; i >= 0; i--)
@ -142,20 +134,23 @@ public class Relocator extends AbstractFile
lines.remove (i); lines.remove (i);
} }
text.append (String.format (" %s %s%n %s %s%n", heading, heading, text.append (String.format (" %s %s%n %s %s%n", heading, heading, underline,
underline, underline)); underline));
int offset = (lines.size () + 1) / 2; int offset = (lines.size () + 1) / 2;
// boolean oddLines = lines.size () % 2 == 1;
int pairs = lines.size () / 2; int pairs = lines.size () / 2;
for (int i = 0; i < pairs; i++) for (int i = 0; i < pairs; i++)
{ text.append (String.format (" %-35s %s%n", lines.get (i), lines.get (i + offset)));
text.append (
String.format (" %-35s %s%n", lines.get (i), lines.get (i + offset)));
}
if (offset != pairs) if (offset != pairs)
text.append (String.format (" %s%n", lines.get (pairs))); text.append (String.format (" %s%n", lines.get (pairs)));
// show gaps
if (false)
for (int i = 0; i < 0x22C; i++)
if (diskBlocks[i] == 0)
text.append (String.format ("%04X %3d %3d%n", i, diskBlocks[i], diskOffsets[i]));
return text.toString (); return text.toString ();
} }
@ -165,12 +160,13 @@ public class Relocator extends AbstractFile
{ {
int diskNumber; int diskNumber;
int totDiskSegments; int totDiskSegments;
List<DiskSegment> diskSegments = new ArrayList<> (); List<DiskSegment> diskSegments;
public DiskRecord (byte[] buffer, int ptr) public DiskRecord (byte[] buffer, int ptr)
{ {
diskNumber = Utility.getShort (buffer, ptr); diskNumber = Utility.getShort (buffer, ptr);
totDiskSegments = Utility.intValue (buffer[ptr + 2], buffer[ptr + 4]); totDiskSegments = Utility.getShort (buffer, ptr + 2);
diskSegments = new ArrayList<> (totDiskSegments);
ptr += 4; ptr += 4;
for (int i = 0; i < totDiskSegments; i++) for (int i = 0; i < totDiskSegments; i++)
@ -192,22 +188,22 @@ public class Relocator extends AbstractFile
text.append (String.format ("Disk number.... %04X%n", diskNumber)); text.append (String.format ("Disk number.... %04X%n", diskNumber));
text.append (String.format ("Segments....... %04X%n%n", totDiskSegments)); text.append (String.format ("Segments....... %04X%n%n", totDiskSegments));
text.append (String.format (" Seg Skip Size Logical Physical%n")); text.append (String.format (" Seg Physical Logical Size Gap%n"));
text.append (String.format (" --- ---- ---- ----------- -----------%n")); text.append (String.format (" --- ----------- ----------- ---- ----%n"));
int count = 1; int count = 1;
int last = 0; int last = 0;
int skip = 0; int skip = 0;
for (DiskSegment segment : diskSegments) for (DiskSegment diskSegment : diskSegments)
{ {
if (segment.logicalBlock > last) if (diskSegment.logicalBlock > last)
{ {
int end = segment.logicalBlock - 1; int end = diskSegment.logicalBlock - 1;
skip = end - last + 1; skip = end - last + 1;
} }
last = segment.logicalBlock + segment.segmentLength; last = diskSegment.logicalBlock + diskSegment.segmentLength;
text.append (String.format (" %02X %04X %s %n", count++, skip, segment)); text.append (String.format (" %02X %s %04X%n", count++, diskSegment, skip));
} }
return text.toString (); return text.toString ();
@ -232,9 +228,9 @@ public class Relocator extends AbstractFile
@Override @Override
public String toString () public String toString ()
{ {
return String.format (" %04X %04X - %04X %04X - %04X", segmentLength, return String.format (" %04X - %04X %04X - %04X %04X", physicalBlock,
logicalBlock, (logicalBlock + segmentLength - 1), physicalBlock, (physicalBlock + segmentLength - 1), logicalBlock, (logicalBlock + segmentLength - 1),
(physicalBlock + segmentLength - 1)); segmentLength);
} }
} }
} }

View File

@ -11,20 +11,24 @@ class Reward extends AbstractFile
{ {
static String[] types = { "gold", "item" }; static String[] types = { "gold", "item" };
static final int SEGMENT_LENGTH = 18; static final int SEGMENT_LENGTH = 18;
int id; int id;
int totalElements; int totalElements;
List<RewardElement> elements; List<RewardElement> elements;
List<Item> items; List<ItemV1> items;
List<Monster> goldMonsters = new ArrayList<> (); List<MonsterV1> goldMonsters = new ArrayList<> ();
List<Monster> chestMonsters = new ArrayList<> (); List<MonsterV1> chestMonsters = new ArrayList<> ();
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
Reward (String name, byte[] buffer, int id, List<Item> items) Reward (String name, byte[] buffer, int id, List<ItemV1> items)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
super (name, buffer); super (name, buffer);
this.id = id; this.id = id;
this.items = items; this.items = items;
totalElements = buffer[4]; totalElements = buffer[4];
elements = new ArrayList<> (totalElements); elements = new ArrayList<> (totalElements);
@ -37,13 +41,13 @@ class Reward extends AbstractFile
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
public void addMonster (Monster monster, int location) public void addMonster (MonsterV1 monster, int location)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
if (location == 0) if (location == 0)
goldMonsters.add (monster); goldMonsters.add (monster);
else else
chestMonsters.add (monster); chestMonsters.add (monster); // lair
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
@ -67,14 +71,14 @@ class Reward extends AbstractFile
if (goldMonsters.size () > 0) if (goldMonsters.size () > 0)
{ {
text.append ("Without chest:\n\n"); text.append ("Without chest:\n\n");
for (Monster m : goldMonsters) for (MonsterV1 m : goldMonsters)
text.append (" " + m + "\n"); text.append (" " + m + "\n");
text.append ("\n"); text.append ("\n");
} }
if (chestMonsters.size () > 0) if (chestMonsters.size () > 0)
{ {
text.append ("With chest:\n\n"); text.append ("With chest:\n\n");
for (Monster m : chestMonsters) for (MonsterV1 m : chestMonsters)
text.append (" " + m + "\n"); text.append (" " + m + "\n");
} }
} }
@ -107,6 +111,7 @@ class Reward extends AbstractFile
public RewardElement (byte[] buffer) public RewardElement (byte[] buffer)
{ {
this.buffer = buffer; this.buffer = buffer;
type = buffer[8]; type = buffer[8];
odds = buffer[6]; odds = buffer[6];
} }
@ -130,21 +135,24 @@ class Reward extends AbstractFile
case 0: case 0:
text.append ("Gold ............ " + buffer[10] + "d" + buffer[12] + "\n"); text.append ("Gold ............ " + buffer[10] + "d" + buffer[12] + "\n");
break; break;
case 1: case 1:
int lo = buffer[10] & 0xFF; int lo = buffer[10] & 0xFF;
int qty = buffer[16] & 0xFF; int qty = buffer[16] & 0xFF;
boolean title = true; boolean title = true;
String[] lineItem = new String[4]; String[] lineItem = new String[4];
for (int i = lo, max = lo + qty; i <= max; i += lineItem.length) for (int i = lo, max = lo + qty; i <= max; i += lineItem.length)
{ {
String lineTitle = title ? "Items ..........." : ""; String lineTitle = title ? "Items ..........." : "";
title = false; title = false;
for (int j = 0; j < lineItem.length; j++) for (int j = 0; j < lineItem.length; j++)
lineItem[j] = i + j <= max ? items.get (i + j).getName () : ""; lineItem[j] = i + j < items.size () ? items.get (i + j).getName () : "";
text.append (String.format ("%-17s %-16s %-16s %-16s %-16s%n", lineTitle, text.append (String.format ("%-17s %-16s %-16s %-16s %-16s%n", lineTitle, lineItem[0],
lineItem[0], lineItem[1], lineItem[2], lineItem[3])); lineItem[1], lineItem[2], lineItem[3]));
} }
break; break;
default: default:
System.out.println ("Unknown reward type " + type); System.out.println ("Unknown reward type " + type);
} }

View File

@ -12,6 +12,7 @@ class Spell extends AbstractFile
private String translation; private String translation;
private SpellTarget target; private SpellTarget target;
private String description; private String description;
private int value;
public enum SpellType public enum SpellType
{ {
@ -35,11 +36,11 @@ class Spell extends AbstractFile
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
super (spellName, buffer); super (spellName, buffer);
this.spellType = type; this.spellType = type;
this.level = level; this.level = level;
if (lastSpellFound + 1 < spellNames.length if (lastSpellFound + 1 < spellNames.length && spellName.equals (spellNames[lastSpellFound + 1]))
&& spellName.equals (spellNames[lastSpellFound + 1]))
setSpell (++lastSpellFound); setSpell (++lastSpellFound);
else else
{ {
@ -61,11 +62,11 @@ class Spell extends AbstractFile
this.description = descriptions[spellNo]; this.description = descriptions[spellNo];
this.whenCast = when[spellNo]; this.whenCast = when[spellNo];
this.target = affects[spellNo]; this.target = affects[spellNo];
value = spellValue[spellNo];
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
public static Spell getSpell (String spellName, SpellType type, int level, public static Spell getSpell (String spellName, SpellType type, int level, byte[] buffer)
byte[] buffer)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
return new Spell (spellName, type, level, buffer); return new Spell (spellName, type, level, buffer);
@ -76,7 +77,7 @@ class Spell extends AbstractFile
public String getName () public String getName ()
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
return getName (); return name;
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
@ -191,89 +192,75 @@ class Spell extends AbstractFile
public String toString () public String toString ()
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
StringBuilder text = new StringBuilder (getName ()); return String.format ("%-16s %-6s %d %-20s %-20s %-20s", getName (), spellType, level,
while (text.length () < 14) translation, getArea (), getWhenCast ());
text.append (" ");
if (spellType == SpellType.PRIEST)
text.append ("P");
else
text.append ("M");
text.append (level);
while (text.length () < 20)
text.append (" ");
text.append (translation);
while (text.length () < 40)
text.append (" ");
text.append (getArea ());
while (text.length () < 60)
text.append (" ");
text.append (getWhenCast ());
return text.toString ();
} }
private static String[] spellNames = { "KALKI", "DIOS", "BADIOS", "MILWA", "PORFIC", private static String[] spellNames = { "KALKI", "DIOS", "BADIOS", "MILWA", "PORFIC", "MATU",
"MATU", "CALFO", "MANIFO", "MONTINO", "LOMILWA", "DIALKO", "LATUMAPIC", "BAMATU", "CALFO", "MANIFO", "MONTINO", "LOMILWA", "DIALKO", "LATUMAPIC", "BAMATU", "DIAL", "BADIAL",
"DIAL", "BADIAL", "LATUMOFIS", "MAPORFIC", "DIALMA", "BADIALMA", "LITOKAN", "KANDI", "LATUMOFIS", "MAPORFIC", "DIALMA", "BADIALMA", "LITOKAN", "KANDI", "DI", "BADI", "LORTO",
"DI", "BADI", "LORTO", "MADI", "MABADI", "LOKTOFEIT", "MALIKTO", "KADORTO", "MADI", "MABADI", "LOKTOFEIT", "MALIKTO", "KADORTO",
"HALITO", "MOGREF", "KATINO", "DUMAPIC", "DILTO", "SOPIC", "MAHALITO", "MOLITO", "HALITO", "MOGREF", "KATINO", "DUMAPIC", "DILTO", "SOPIC", "MAHALITO", "MOLITO", "MORLIS",
"MORLIS", "DALTO", "LAHALITO", "MAMORLIS", "MAKANITO", "MADALTO", "LAKANITO", "DALTO", "LAHALITO", "MAMORLIS", "MAKANITO", "MADALTO", "LAKANITO", "ZILWAN", "MASOPIC",
"ZILWAN", "MASOPIC", "HAMAN", "MALOR", "MAHAMAN", "TILTOWAIT" }; "HAMAN", "MALOR", "MAHAMAN", "TILTOWAIT" };
private static String[] translations = { "Blessings", "Heal", "Harm", "Light", "Shield", private static String[] translations = { "Blessings", "Heal", "Harm", "Light", "Shield",
"Blessing & zeal", "X-ray vision", "Statue", "Still air", "More light", "Blessing & zeal", "X-ray vision", "Statue", "Still air", "More light", "Softness/supple",
"Softness/supple", "Identification", "Prayer", "Heal (more)", "Hurt (more)", "Identification", "Prayer", "Heal (more)", "Hurt (more)", "Cure poison", "Shield (big)",
"Cure poison", "Shield (big)", "Heal (greatly)", "Hurt (greatly)", "Flame tower", "Heal (greatly)", "Hurt (greatly)", "Flame tower", "Location", "Life", "Death", "Blades",
"Location", "Life", "Death", "Blades", "Healing", "Harm (incredibly)", "Recall", "Healing", "Harm (incredibly)", "Recall", "The Word of Death", "Resurrection",
"The Word of Death", "Resurrection",
"Little Fire", "Body Iron", "Bad Air", "Clarity", "Darkness", "Glass", "Big fire", "Little Fire", "Body Iron", "Bad Air", "Clarity", "Darkness", "Glass", "Big fire",
"Spark storm", "Fear", "Blizzard blast", "Flame storm", "Terror", "Deadly air", "Spark storm", "Fear", "Blizzard blast", "Flame storm", "Terror", "Deadly air", "Frost",
"Frost", "Suffocation", "Dispell", "Big glass", "Change", "Apport", "Great change", "Suffocation", "Dispell", "Big glass", "Change", "Apport", "Great change",
"(untranslatable)" }; "(untranslatable)" };
private static SpellThrown[] when = { SpellThrown.COMBAT, SpellThrown.ANY_TIME, private static SpellThrown[] when = { SpellThrown.COMBAT, SpellThrown.ANY_TIME,
SpellThrown.COMBAT, SpellThrown.ANY_TIME, SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.ANY_TIME, SpellThrown.COMBAT, SpellThrown.COMBAT,
SpellThrown.LOOTING, SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.ANY_TIME, SpellThrown.LOOTING, SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.ANY_TIME,
SpellThrown.ANY_TIME, SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.ANY_TIME, SpellThrown.ANY_TIME, SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.ANY_TIME,
SpellThrown.COMBAT, SpellThrown.ANY_TIME, SpellThrown.ANY_TIME, SpellThrown.COMBAT, SpellThrown.ANY_TIME, SpellThrown.ANY_TIME, SpellThrown.ANY_TIME,
SpellThrown.ANY_TIME, SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.CAMP, SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.CAMP, SpellThrown.CAMP,
SpellThrown.CAMP, SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.ANY_TIME, SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.ANY_TIME, SpellThrown.COMBAT,
SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.ANY_TIME, SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.ANY_TIME,
SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.CAMP, SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.CAMP,
SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.COMBAT,
SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.COMBAT,
SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.COMBAT,
SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.COMBAT_OR_CAMP, SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.COMBAT_OR_CAMP, SpellThrown.COMBAT,
SpellThrown.COMBAT, SpellThrown.COMBAT, }; SpellThrown.COMBAT, };
private static SpellTarget[] affects = { SpellTarget.PARTY, SpellTarget.PERSON, private static SpellTarget[] affects = { SpellTarget.PARTY, SpellTarget.PERSON,
SpellTarget.MONSTER, SpellTarget.PARTY, SpellTarget.CASTER, SpellTarget.PARTY, SpellTarget.MONSTER, SpellTarget.PARTY, SpellTarget.CASTER, SpellTarget.PARTY,
SpellTarget.CASTER, SpellTarget.MONSTER_GROUP, SpellTarget.MONSTER_GROUP, SpellTarget.CASTER, SpellTarget.MONSTER_GROUP, SpellTarget.MONSTER_GROUP, SpellTarget.PARTY,
SpellTarget.PARTY, SpellTarget.PERSON, SpellTarget.PARTY, SpellTarget.PARTY, SpellTarget.PERSON, SpellTarget.PARTY, SpellTarget.PARTY, SpellTarget.PERSON,
SpellTarget.PERSON, SpellTarget.MONSTER, SpellTarget.PERSON, SpellTarget.PARTY, SpellTarget.MONSTER, SpellTarget.PERSON, SpellTarget.PARTY, SpellTarget.PERSON,
SpellTarget.PERSON, SpellTarget.MONSTER, SpellTarget.PARTY, SpellTarget.PERSON, SpellTarget.MONSTER, SpellTarget.PARTY, SpellTarget.PERSON, SpellTarget.PERSON,
SpellTarget.PERSON, SpellTarget.MONSTER, SpellTarget.MONSTER_GROUP, SpellTarget.MONSTER, SpellTarget.MONSTER_GROUP, SpellTarget.PERSON, SpellTarget.MONSTER,
SpellTarget.PERSON, SpellTarget.MONSTER, SpellTarget.PARTY, SpellTarget.PARTY, SpellTarget.MONSTER_GROUP, SpellTarget.PERSON,
SpellTarget.MONSTER_GROUP, SpellTarget.PERSON,
SpellTarget.MONSTER, SpellTarget.CASTER, SpellTarget.MONSTER_GROUP, SpellTarget.MONSTER, SpellTarget.CASTER, SpellTarget.MONSTER_GROUP, SpellTarget.NONE,
SpellTarget.NONE, SpellTarget.MONSTER_GROUP, SpellTarget.CASTER, SpellTarget.MONSTER_GROUP, SpellTarget.CASTER, SpellTarget.MONSTER_GROUP,
SpellTarget.MONSTER_GROUP, SpellTarget.MONSTER_GROUP, SpellTarget.MONSTER_GROUP, SpellTarget.MONSTER_GROUP, SpellTarget.MONSTER_GROUP, SpellTarget.MONSTER_GROUP,
SpellTarget.MONSTER_GROUP, SpellTarget.MONSTER_GROUP, SpellTarget.ALL_MONSTERS, SpellTarget.MONSTER_GROUP, SpellTarget.ALL_MONSTERS, SpellTarget.ALL_MONSTERS,
SpellTarget.ALL_MONSTERS, SpellTarget.MONSTER_GROUP, SpellTarget.MONSTER_GROUP, SpellTarget.MONSTER_GROUP, SpellTarget.MONSTER_GROUP, SpellTarget.MONSTER, SpellTarget.PARTY,
SpellTarget.MONSTER, SpellTarget.PARTY, SpellTarget.VARIABLE, SpellTarget.PARTY, SpellTarget.VARIABLE, SpellTarget.PARTY, SpellTarget.PARTY, SpellTarget.ALL_MONSTERS };
SpellTarget.PARTY, SpellTarget.ALL_MONSTERS };
private static int[] spellValue =
{ 1449, 2301, 3675, 2889, 2287, 3139, 1717, 2619, 5970, 5333, 2718, 6491, 5169, 761, 1253,
9463, 4322, 1614, 2446, 4396, 1885, 180, 382, 4296, 547, 759, 8330, 5514, 6673,
4178, 2409, 3983, 3245, 3340, 1953, 6181, 4731, 4744, 3180, 6156, 7525, 6612, 4925, 6587,
4573, 3990, 1562, 3128, 2597, 11157 };
private static String[] descriptions = { private static String[] descriptions = {
"KALKI reduces the AC of all party members by one, and thus makes" "KALKI reduces the AC of all party members by one, and thus makes" + " them harder to hit.",
+ " them harder to hit.",
"DIOS restores from one to eight hit points of damage from a party" "DIOS restores from one to eight hit points of damage from a party"
+ "member. It will not bring dead back to life.", + "member. It will not bring dead back to life.",
"BADIOS causes one to eight hit points of damage to a monster, and" "BADIOS causes one to eight hit points of damage to a monster, and"
+ " may kill it. It is the reverse of dios. Note the BA prefix which" + " may kill it. It is the reverse of dios. Note the BA prefix which" + " means 'not'.",
+ " means 'not'.",
"MILWA causes a softly glowing light to follow the party, allowing" "MILWA causes a softly glowing light to follow the party, allowing"
+ " them to see further into the maze, and also revealing all secret" + " them to see further into the maze, and also revealing all secret"
+ " doors. See also LOMILWA. This spell lasts only a short while.", + " doors. See also LOMILWA. This spell lasts only a short while.",
@ -284,8 +271,7 @@ class Spell extends AbstractFile
+ " on a chest 95% of the time.", + " on a chest 95% of the time.",
"MANIFO causes some of the monsters in a group to become stiff as" "MANIFO causes some of the monsters in a group to become stiff as"
+ " statues for one or more melee rounds. The chance of success," + " statues for one or more melee rounds. The chance of success,"
+ " and the duration of the effects, depend on the power of the" + " and the duration of the effects, depend on the power of the" + " target monsters.",
+ " target monsters.",
"MONTINO causes the air around a group of monsters to stop" "MONTINO causes the air around a group of monsters to stop"
+ " transmitting sound. Like MANIFO, only some of the monsters will" + " transmitting sound. Like MANIFO, only some of the monsters will"
+ " be affected, and for varying lengths of time. Monsters and" + " be affected, and for varying lengths of time. Monsters and"
@ -297,20 +283,16 @@ class Spell extends AbstractFile
+ " only the square you are in, and the next two squares, will" + " only the square you are in, and the next two squares, will"
+ " plot. Normally you might see five or six squares ahead with" + " plot. Normally you might see five or six squares ahead with"
+ " LOMILWA on. Quick Plotting lets you move fast through known" + " LOMILWA on. Quick Plotting lets you move fast through known"
+ " areas. Note that it will be turned off when you enter camp or" + " areas. Note that it will be turned off when you enter camp or" + " combat mode.",
+ " combat mode.",
"DIALKO cures paralysis, and removes the effects of MANIFO and" "DIALKO cures paralysis, and removes the effects of MANIFO and"
+ " KATINO from one member of the party.", + " KATINO from one member of the party.",
"LATUMAPIC makes it readily apparent exactly what the opposing" "LATUMAPIC makes it readily apparent exactly what the opposing" + " monsters really are.",
+ " monsters really are.",
"BAMATU has the effects of MATU at twice the effectiveness.", "BAMATU has the effects of MATU at twice the effectiveness.",
"DIAL restores two to 16 hit points of damage, and is similar to" + " DIOS.", "DIAL restores two to 16 hit points of damage, and is similar to" + " DIOS.",
"BADIAL causes two to 16 hit points of damage in the same way as" + " BADIOS.", "BADIAL causes two to 16 hit points of damage in the same way as" + " BADIOS.",
"LATUMOFIS makes a poisoned person whole and fit again. Note that" "LATUMOFIS makes a poisoned person whole and fit again. Note that"
+ " poison causes a person to lose hit points steadily during" + " poison causes a person to lose hit points steadily during" + " movement and combat.",
+ " movement and combat.", "MAPORFIC is an improved PORFIC, with effects that last for the" + " entire expedition.",
"MAPORFIC is an improved PORFIC, with effects that last for the"
+ " entire expedition.",
"DIALMA restores three to 24 hit points.", "DIALMA restores three to 24 hit points.",
"BADIALMA causes three to 24 hit points of damage.", "BADIALMA causes three to 24 hit points of damage.",
"LITOKAN causes a pillar of flame to strike a group of monsters," "LITOKAN causes a pillar of flame to strike a group of monsters,"
@ -340,8 +322,7 @@ class Spell extends AbstractFile
"HALITO causes a flame ball the size of a baseball to hit a monster," "HALITO causes a flame ball the size of a baseball to hit a monster,"
+ " doing from one to eight points of damage.", + " doing from one to eight points of damage.",
"MOGREF reduces the caster's AC by two. The effect lasts the entire" "MOGREF reduces the caster's AC by two. The effect lasts the entire" + " encounter.",
+ " encounter.",
"KATINO causes most of the monsters in a group to fall asleep." "KATINO causes most of the monsters in a group to fall asleep."
+ " Katino only effects normal, animal or humanoid monsters. The" + " Katino only effects normal, animal or humanoid monsters. The"
+ " chance of the spell affecting an individual monster, and the" + " chance of the spell affecting an individual monster, and the"

View File

@ -0,0 +1,323 @@
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 = 64;
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 = 14;
// int sppc = 15;
// 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
multAddKX (killExp, Integer.bitCount (sppc & 0x7F), 40); // 7 bits
killExp.printLong ();
System.out.println ();
WizLong a = new WizLong (1000);
a.multLong (54);
a.printLong ();
a.addLong (a);
a.printLong ();
System.out.println ();
a = new WizLong (1000);
a.multLong (500);
a.printLong ();
a.addLong (a);
a.printLong ();
System.out.println ();
a = new WizLong (1000);
a.multLong (505);
a.printLong ();
a.addLong (a);
a.printLong ();
}
}

View File

@ -21,20 +21,25 @@ import com.bytezone.diskbrowser.wizardry.Header.ScenarioData;
public class Wizardry4BootDisk extends PascalDisk public class Wizardry4BootDisk extends PascalDisk
// -----------------------------------------------------------------------------------// // -----------------------------------------------------------------------------------//
{ {
public Header scenarioHeader; private Header scenarioHeader;
// private final List<AppleDisk> disks = new ArrayList<> ();
private Relocator relocator; private Relocator relocator;
private MessageBlock messageBlock; private MessageBlock messageBlock;
private Huffman huffman; private Huffman huffman;
private final int version; private final int version;
private List<CharacterV4> characters = new ArrayList<> ();
private List<CharacterParty> parties = new ArrayList<> ();
private List<ItemV4> items = new ArrayList<> ();
private List<MonsterV4> monsters = new ArrayList<> ();
private List<String> spellNames = new ArrayList<> ();
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
public Wizardry4BootDisk (AppleDisk[] dataDisks) public Wizardry4BootDisk (AppleDisk[] dataDisks)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
super (dataDisks[0]); 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 (); DefaultTreeModel model = (DefaultTreeModel) catalogTree.getModel ();
DefaultMutableTreeNode currentRoot = (DefaultMutableTreeNode) model.getRoot (); DefaultMutableTreeNode currentRoot = (DefaultMutableTreeNode) model.getRoot ();
@ -44,9 +49,8 @@ public class Wizardry4BootDisk extends PascalDisk
FileEntry fileEntry = (FileEntry) relocNode.getUserObject (); FileEntry fileEntry = (FileEntry) relocNode.getUserObject ();
if (fileEntry != null) if (fileEntry != null)
{ {
relocator = relocator = new Relocator (fileEntry.getUniqueName (), fileEntry.getDataSource ().buffer);
new Relocator (fileEntry.getUniqueName (), fileEntry.getDataSource ().buffer); relocator.createNewBuffer (dataDisks);
relocator.createNewBuffer (dataDisks); // create new data buffer
fileEntry.setFile (relocator); fileEntry.setFile (relocator);
} }
@ -63,10 +67,7 @@ public class Wizardry4BootDisk extends PascalDisk
fileEntry = (FileEntry) huffNode.getUserObject (); fileEntry = (FileEntry) huffNode.getUserObject ();
if (fileEntry != null) if (fileEntry != null)
{ {
huffman = new Huffman ("Huffman tree", fileEntry.getDataSource ().buffer);
byte[] buffer = fileEntry.getDataSource ().buffer;
huffman = new Huffman ("Huffman tree", buffer);
fileEntry.setFile (huffman); fileEntry.setFile (huffman);
} }
@ -88,6 +89,7 @@ public class Wizardry4BootDisk extends PascalDisk
} }
} }
// scenario data
if (version == 4) if (version == 4)
{ {
DefaultMutableTreeNode scenarioNode = findNode (currentRoot, "SCENARIO.DATA"); DefaultMutableTreeNode scenarioNode = findNode (currentRoot, "SCENARIO.DATA");
@ -97,7 +99,12 @@ public class Wizardry4BootDisk extends PascalDisk
fileEntry.setFile (null); fileEntry.setFile (null);
scenarioNode.setAllowsChildren (true); scenarioNode.setAllowsChildren (true);
scenarioHeader = new Header (scenarioNode, this); scenarioHeader = new Header (scenarioNode, this);
readSpells ();
linkCharacters4 (scenarioNode, fileEntry);
linkParties ();
linkMazeLevels4 (scenarioNode, fileEntry); linkMazeLevels4 (scenarioNode, fileEntry);
linkMonstersV4 (scenarioNode, fileEntry);
linkItemsV4 (scenarioNode, fileEntry);
} }
} }
else if (version == 5) else if (version == 5)
@ -114,7 +121,10 @@ public class Wizardry4BootDisk extends PascalDisk
linkBlock2 (scenarioNode, fileEntry); linkBlock2 (scenarioNode, fileEntry);
} }
} }
else
System.out.println ("No Wizardry version set");
// monster images
if (version == 4) if (version == 4)
{ {
DefaultMutableTreeNode monstersNode = findNode (currentRoot, "200.MONSTERS"); DefaultMutableTreeNode monstersNode = findNode (currentRoot, "200.MONSTERS");
@ -138,14 +148,223 @@ public class Wizardry4BootDisk extends PascalDisk
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
private void linkMonsterImages4 (DefaultMutableTreeNode monstersNode, private void linkCharacters4 (DefaultMutableTreeNode scenarioNode, FileEntry fileEntry)
FileEntry fileEntry) // ---------------------------------------------------------------------------------//
{
ScenarioData sd = scenarioHeader.get (Header.CHARACTER_AREA);
byte[] buffer = fileEntry.getDataSource ().buffer;
List<DiskAddress> blocks = fileEntry.getSectors ();
DefaultMutableTreeNode charactersNode = linkNode ("Characters", "Characters", scenarioNode);
List<DiskAddress> allCharacterBlocks = new ArrayList<> ();
int ptr = sd.dataOffset * 512;
for (int i = 0; i < 500; i++)
{
byte[] out = huffman.decodeMessage (buffer, ptr);
String name = HexFormatter.getPascalString (out, 1);
CharacterV4 c = new CharacterV4 (name, out, i);
characters.add (c);
if (!name.isEmpty ())
{
List<DiskAddress> 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 linkParties ()
// ---------------------------------------------------------------------------------//
{
for (CharacterV4 character : characters)
{
if (character.isInParty () || character.getName ().isEmpty ())
continue;
CharacterParty party = new CharacterParty ();
parties.add (party);
link (character, party);
}
}
// ---------------------------------------------------------------------------------//
private void readSpells ()
// ---------------------------------------------------------------------------------//
{
for (int i = 0; i < 51; i++)
{
String spellName = messageBlock.getMessageLine (i + 5000);
if (spellName.startsWith ("*"))
spellName = spellName.substring (1);
spellNames.add (spellName);
}
}
// ---------------------------------------------------------------------------------//
private void link (CharacterV4 character, CharacterParty party)
// ---------------------------------------------------------------------------------//
{
if (character.isInParty ())
return;
party.add (character);
if (character.nextCharacterId > 0)
link (characters.get (character.nextCharacterId), party);
}
// ---------------------------------------------------------------------------------//
private void linkMonstersV4 (DefaultMutableTreeNode scenarioNode, FileEntry fileEntry)
// ---------------------------------------------------------------------------------//
{
ScenarioData sd = scenarioHeader.get (Header.MONSTER_AREA);
byte[] buffer = fileEntry.getDataSource ().buffer;
List<DiskAddress> blocks = fileEntry.getSectors ();
DefaultMutableTreeNode monstersNode = linkNode ("Monsters", "Monsters", scenarioNode);
List<DiskAddress> allMonsterBlocks = new ArrayList<> ();
String[] monsterNames = new String[4];
int ptr = sd.dataOffset * 512;
for (int i = 0; i < sd.total; i++)
{
byte[] out = huffman.decodeMessage (buffer, ptr);
int len = out[0] & 0xFF;
if (len > out.length)
System.out.printf ("Decoded array too short: (#%3d) %3d > %3d%n", i, len, out.length);
for (int j = 0; j < monsterNames.length; j++)
monsterNames[j] = messageBlock.getMessageLine (i * 4 + 13000 + j);
MonsterV4 monster = new MonsterV4 (monsterNames, out, i);
monsters.add (monster);
// System.out.println (monster.getName ());
List<DiskAddress> monsterBlocks = new ArrayList<> ();
DiskAddress da = blocks.get (ptr / 512);
monsterBlocks.add (da);
addToNode (monster, monstersNode, monsterBlocks);
if (!allMonsterBlocks.contains (da))
allMonsterBlocks.add (da);
ptr += sd.totalBlocks;
}
DefaultAppleFileSource afs = (DefaultAppleFileSource) monstersNode.getUserObject ();
afs.setSectors (allMonsterBlocks);
}
// ---------------------------------------------------------------------------------//
private void linkItemsV4 (DefaultMutableTreeNode scenarioNode, FileEntry fileEntry)
// ---------------------------------------------------------------------------------//
{
ScenarioData sd = scenarioHeader.get (Header.ITEM_AREA);
byte[] buffer = fileEntry.getDataSource ().buffer;
List<DiskAddress> blocks = fileEntry.getSectors ();
DefaultMutableTreeNode itemsNode = linkNode ("Items", "Items", scenarioNode);
List<DiskAddress> allItemBlocks = new ArrayList<> ();
String[] itemNames = new String[2];
int ptr = sd.dataOffset * 512;
for (int i = 0; i < sd.total; i++)
{
byte[] out = huffman.decodeMessage (buffer, ptr);
for (int j = 0; j < itemNames.length; j++)
{
itemNames[j] = messageBlock.getMessageLine (i * 2 + 14000 + j);
if (itemNames[j] == null)
itemNames[j] = "Broken Item";
}
ItemV4 item = new ItemV4 (itemNames, out, i);
items.add (item);
List<DiskAddress> itemBlocks = new ArrayList<> ();
DiskAddress da = blocks.get (ptr / 512);
itemBlocks.add (da);
addToNode (item, itemsNode, itemBlocks);
if (!allItemBlocks.contains (da))
allItemBlocks.add (da);
ptr += sd.totalBlocks;
}
DefaultAppleFileSource afs = (DefaultAppleFileSource) itemsNode.getUserObject ();
afs.setSectors (allItemBlocks);
for (CharacterV4 character : characters)
character.addPossessions (items);
// for (int i = 0; i < items.size (); i++)
// System.out.printf ("%3d %s%n", i, items.get (i));
for (ItemV4 item : items)
item.link (items, spellNames);
}
// ---------------------------------------------------------------------------------//
private void linkMazeLevels4 (DefaultMutableTreeNode scenarioNode, FileEntry fileEntry)
// ---------------------------------------------------------------------------------//
{
ScenarioData mazeData = scenarioHeader.get (Header.MAZE_AREA);
byte[] buffer = fileEntry.getDataSource ().buffer;
List<DiskAddress> blocks = fileEntry.getSectors ();
DefaultMutableTreeNode mazeNode = linkNode ("Maze", "Levels string", scenarioNode);
List<DiskAddress> 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<DiskAddress> 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)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
List<DiskAddress> pictureBlocks = fileEntry.getSectors (); List<DiskAddress> pictureBlocks = fileEntry.getSectors ();
Wiz4Monsters w4monsters = Wiz4Monsters w4monsters = new Wiz4Monsters ("monsters", fileEntry.getDataSource ().buffer);
new Wiz4Monsters ("monsters", fileEntry.getDataSource ().buffer);
fileEntry.setFile (w4monsters); fileEntry.setFile (w4monsters);
int count = 0; int count = 0;
@ -158,14 +377,12 @@ public class Wizardry4BootDisk extends PascalDisk
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
private void linkMonsterImages5 (DefaultMutableTreeNode monstersNode, private void linkMonsterImages5 (DefaultMutableTreeNode monstersNode, FileEntry fileEntry)
FileEntry fileEntry)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
List<DiskAddress> pictureBlocks = fileEntry.getSectors (); List<DiskAddress> pictureBlocks = fileEntry.getSectors ();
Wiz5Monsters w5monsters = Wiz5Monsters w5monsters = new Wiz5Monsters ("monsters", fileEntry.getDataSource ().buffer);
new Wiz5Monsters ("monsters", fileEntry.getDataSource ().buffer);
fileEntry.setFile (w5monsters); fileEntry.setFile (w5monsters);
for (Wiz5Monsters.Monster monster : w5monsters) for (Wiz5Monsters.Monster monster : w5monsters)
@ -177,30 +394,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<DiskAddress> 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<DiskAddress> 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) private void linkMazeLevels5 (DefaultMutableTreeNode scenarioNode, FileEntry fileEntry)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
@ -255,8 +448,7 @@ public class Wizardry4BootDisk extends PascalDisk
HexFormatter.getHexString (buffer, offset + i * length, length))); HexFormatter.getHexString (buffer, offset + i * length, length)));
} }
DefaultMutableTreeNode oracleNode = DefaultMutableTreeNode oracleNode = linkNode ("Block1", text.toString (), scenarioNode);
linkNode ("Block1", text.toString (), scenarioNode);
oracleNode.setAllowsChildren (false); oracleNode.setAllowsChildren (false);
DefaultAppleFileSource afs = (DefaultAppleFileSource) oracleNode.getUserObject (); DefaultAppleFileSource afs = (DefaultAppleFileSource) oracleNode.getUserObject ();
afs.setSectors (allBlocks); afs.setSectors (allBlocks);
@ -284,8 +476,7 @@ public class Wizardry4BootDisk extends PascalDisk
HexFormatter.getHexString (buffer, offset + i * length, length))); HexFormatter.getHexString (buffer, offset + i * length, length)));
} }
DefaultMutableTreeNode oracleNode = DefaultMutableTreeNode oracleNode = linkNode ("Block2", text.toString (), scenarioNode);
linkNode ("Block2", text.toString (), scenarioNode);
oracleNode.setAllowsChildren (false); oracleNode.setAllowsChildren (false);
DefaultAppleFileSource afs = (DefaultAppleFileSource) oracleNode.getUserObject (); DefaultAppleFileSource afs = (DefaultAppleFileSource) oracleNode.getUserObject ();
afs.setSectors (allBlocks); afs.setSectors (allBlocks);
@ -306,12 +497,12 @@ public class Wizardry4BootDisk extends PascalDisk
int offset = 0x08600 + i * 32 + 18; int offset = 0x08600 + i * 32 + 18;
int key = Utility.getShort (buffer, offset); int key = Utility.getShort (buffer, offset);
if (key > 0) if (key > 0)
text.append (String.format ("%04X %04X * %s%n", offset, key, text.append (
messageBlock.getMessageText (key))); String.format ("%04X %04X * %s%n", offset, key, messageBlock.getMessageLine (key)));
key = Utility.getShort (buffer, offset + 8); key = Utility.getShort (buffer, offset + 8);
if (key > 0) if (key > 0)
text.append (String.format ("%04X %04X %s%n", offset + 8, key, text.append (String.format ("%04X %04X %s%n", offset + 8, key,
messageBlock.getMessageText (key))); messageBlock.getMessageLine (key)));
} }
List<DiskAddress> allOracleBlocks = new ArrayList<> (); List<DiskAddress> allOracleBlocks = new ArrayList<> ();
@ -320,33 +511,30 @@ public class Wizardry4BootDisk extends PascalDisk
allOracleBlocks.add (blocks.get (67 + i)); allOracleBlocks.add (blocks.get (67 + i));
} }
DefaultMutableTreeNode oracleNode = DefaultMutableTreeNode oracleNode = linkNode ("Oracle", text.toString (), scenarioNode);
linkNode ("Oracle", text.toString (), scenarioNode);
oracleNode.setAllowsChildren (false); oracleNode.setAllowsChildren (false);
DefaultAppleFileSource afs = (DefaultAppleFileSource) oracleNode.getUserObject (); DefaultAppleFileSource afs = (DefaultAppleFileSource) oracleNode.getUserObject ();
afs.setSectors (allOracleBlocks); afs.setSectors (allOracleBlocks);
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
private void addToNode (AbstractFile af, DefaultMutableTreeNode node, private void addToNode (AbstractFile af, DefaultMutableTreeNode node, List<DiskAddress> blocks)
List<DiskAddress> blocks)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
DefaultAppleFileSource dafs = DefaultAppleFileSource dafs = new DefaultAppleFileSource (af.getName (), af, this, blocks);
new DefaultAppleFileSource (af.getName (), af, this, blocks);
DefaultMutableTreeNode childNode = new DefaultMutableTreeNode (dafs); DefaultMutableTreeNode childNode = new DefaultMutableTreeNode (dafs);
childNode.setAllowsChildren (false); childNode.setAllowsChildren (false);
node.add (childNode); node.add (childNode);
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
private DefaultMutableTreeNode linkNode (String name, String text, private DefaultMutableTreeNode linkNode (String name, String text, DefaultMutableTreeNode parent)
DefaultMutableTreeNode parent)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
DefaultAppleFileSource afs = new DefaultAppleFileSource (name, text, this); DefaultAppleFileSource afs = new DefaultAppleFileSource (name, text, this);
DefaultMutableTreeNode node = new DefaultMutableTreeNode (afs); DefaultMutableTreeNode node = new DefaultMutableTreeNode (afs);
parent.add (node); parent.add (node);
return node; return node;
} }
@ -362,9 +550,6 @@ public class Wizardry4BootDisk extends PascalDisk
return false; return false;
buffer = disk.readBlock (1); buffer = disk.readBlock (1);
if (buffer[510] != 1 || buffer[511] != 0) // disk #1 return buffer[510] == 1 && buffer[511] == 0; // disk #1
return false;
return true;
} }
} }

View File

@ -18,8 +18,6 @@ import com.bytezone.diskbrowser.gui.DataSource;
import com.bytezone.diskbrowser.pascal.PascalDisk; import com.bytezone.diskbrowser.pascal.PascalDisk;
import com.bytezone.diskbrowser.utilities.HexFormatter; import com.bytezone.diskbrowser.utilities.HexFormatter;
import com.bytezone.diskbrowser.utilities.Utility; import com.bytezone.diskbrowser.utilities.Utility;
import com.bytezone.diskbrowser.wizardry.Character.Attributes;
import com.bytezone.diskbrowser.wizardry.Character.Statistics;
import com.bytezone.diskbrowser.wizardry.Header.ScenarioData; import com.bytezone.diskbrowser.wizardry.Header.ScenarioData;
import com.bytezone.diskbrowser.wizardry.Spell.SpellType; import com.bytezone.diskbrowser.wizardry.Spell.SpellType;
@ -30,15 +28,18 @@ public class WizardryScenarioDisk extends PascalDisk
public Header scenarioHeader; public Header scenarioHeader;
public List<AbstractImage> images; public List<AbstractImage> images;
public List<Item> items; public List<ItemV1> items;
public List<Character> characters; public List<CharacterV1> characters;
public List<Spell> spells; public List<Spell> spells;
public List<Message> messages; public List<MessageV1> messages;
public List<Monster> monsters; public List<MonsterV1> monsters;
public List<MazeLevel> levels; public List<MazeLevel> levels;
List<ExperienceLevel> experiences; List<ExperienceLevel> experienceLevels;
List<Reward> rewards; List<Reward> rewards;
private int monsterId;
private int itemId;
// leave these here until I decide whether to use them or not // leave these here until I decide whether to use them or not
SectorType mazeSector = new SectorType ("Maze", Color.lightGray); SectorType mazeSector = new SectorType ("Maze", Color.lightGray);
SectorType monsterSector = new SectorType ("Monsters", Color.black); SectorType monsterSector = new SectorType ("Monsters", Color.black);
@ -70,18 +71,18 @@ public class WizardryScenarioDisk extends PascalDisk
} }
CodedMessage.codeOffset = 185; CodedMessage.codeOffset = 185;
Monster.counter = 0;
Item.counter = 0;
DefaultTreeModel model = (DefaultTreeModel) catalogTree.getModel (); DefaultTreeModel model = (DefaultTreeModel) catalogTree.getModel ();
DefaultMutableTreeNode currentRoot = (DefaultMutableTreeNode) model.getRoot (); DefaultMutableTreeNode currentRoot = (DefaultMutableTreeNode) model.getRoot ();
DefaultMutableTreeNode dataNode = findNode (currentRoot, "SCENARIO.DATA"); DefaultMutableTreeNode dataNode = findNode (currentRoot, "SCENARIO.DATA");
DefaultMutableTreeNode msgNode = findNode (currentRoot, "SCENARIO.MESGS"); DefaultMutableTreeNode msgNode = findNode (currentRoot, "SCENARIO.MESGS");
if (dataNode == null || msgNode == null) if (dataNode == null || msgNode == null)
{ {
System.out.println ("Wizardry data or msg node not found"); System.out.println ("Wizardry data or msg node not found");
return; return;
} }
dataNode.setAllowsChildren (true); dataNode.setAllowsChildren (true);
msgNode.setAllowsChildren (true); msgNode.setAllowsChildren (true);
@ -89,9 +90,7 @@ public class WizardryScenarioDisk extends PascalDisk
// Process SCENARIO.MESGS (requires scenario) // Process SCENARIO.MESGS (requires scenario)
AppleFileSource afs = (AppleFileSource) msgNode.getUserObject (); AppleFileSource afs = (AppleFileSource) msgNode.getUserObject ();
// DefaultMutableTreeNode node = linkNode ("Messages", "Messages string", msgNode);
extractMessages (msgNode, afs.getSectors ()); extractMessages (msgNode, afs.getSectors ());
// makeNodeVisible (node);
// Process SCENARIO.DATA (requires scenario and messages) // Process SCENARIO.DATA (requires scenario and messages)
afs = (AppleFileSource) dataNode.getUserObject (); afs = (AppleFileSource) dataNode.getUserObject ();
@ -102,33 +101,27 @@ public class WizardryScenarioDisk extends PascalDisk
extractMonsters (linkNode ("Monsters", "Monsters string", dataNode), sectors); extractMonsters (linkNode ("Monsters", "Monsters string", dataNode), sectors);
extractCharacters (linkNode ("Characters", "Characters string", dataNode), sectors); extractCharacters (linkNode ("Characters", "Characters string", dataNode), sectors);
extractImages (linkNode ("Images", "Images string", dataNode), sectors); extractImages (linkNode ("Images", "Images string", dataNode), sectors);
extractExperienceLevels (linkNode ("Experience", "Experience string", dataNode), extractExperienceLevels (linkNode ("Experience", "Experience string", dataNode), sectors);
sectors);
// node = linkNode ("Spells", "Spells string", dataNode); extractSpells (sectors);
DefaultMutableTreeNode node = null;
extractSpells (node, sectors);
extractLevels (linkNode ("Maze", "Levels string", dataNode), sectors); extractLevels (linkNode ("Maze", "Levels string", dataNode), sectors);
// Make the Spells node (and its siblings) visible
// makeNodeVisible (node);
// add information about each characters' baggage, spells known etc. // add information about each characters' baggage, spells known etc.
for (Character c : characters) for (CharacterV1 character : characters)
{ character.link (items, spells, experienceLevels);
c.linkItems (items);
c.linkSpells (spells); for (ItemV1 item : items)
int type = c.getStatistics ().typeInt; item.link (items, spells);
c.linkExperience (experiences.get (type));
}
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
private DefaultMutableTreeNode linkNode (String name, String text, private DefaultMutableTreeNode linkNode (String name, String text, DefaultMutableTreeNode parent)
DefaultMutableTreeNode parent)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
DefaultAppleFileSource afs = new DefaultAppleFileSource (name, text, this); DefaultAppleFileSource afs = new DefaultAppleFileSource (name, text, this);
DefaultMutableTreeNode node = new DefaultMutableTreeNode (afs); DefaultMutableTreeNode node = new DefaultMutableTreeNode (afs);
parent.add (node); parent.add (node);
return node; return node;
} }
@ -138,6 +131,7 @@ public class WizardryScenarioDisk extends PascalDisk
{ {
byte[] buffer = disk.readBlock (2); byte[] buffer = disk.readBlock (2);
int totalFiles = Utility.getShort (buffer, 16); int totalFiles = Utility.getShort (buffer, 16);
if (totalFiles != 3) if (totalFiles != 3)
return false; return false;
@ -148,6 +142,7 @@ public class WizardryScenarioDisk extends PascalDisk
&& !text.equals ("WIZARDRY.CODE")) && !text.equals ("WIZARDRY.CODE"))
return false; return false;
} }
return true; return true;
} }
@ -212,8 +207,8 @@ public class WizardryScenarioDisk extends PascalDisk
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
private int addReward (byte[] buffer, List<DiskAddress> blocks, private int addReward (byte[] buffer, List<DiskAddress> blocks, DefaultMutableTreeNode node,
DefaultMutableTreeNode node, int seq) int seq)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
int recLen = 168; int recLen = 168;
@ -237,8 +232,8 @@ public class WizardryScenarioDisk extends PascalDisk
ScenarioData sd = scenarioHeader.data.get (Header.CHARACTER_AREA); ScenarioData sd = scenarioHeader.data.get (Header.CHARACTER_AREA);
characters = new ArrayList<> (sd.total); characters = new ArrayList<> (sd.total);
int max = sd.totalBlocks / 2; int max = sd.totalBlocks / 2;
if (max < sd.total) // if (max < sd.total)
System.out.println ("Characters short in Wizardry disk"); // System.out.println ("Characters short in Wizardry disk");
for (int i = 0; i < max; i++) for (int i = 0; i < max; i++)
{ {
@ -253,17 +248,14 @@ public class WizardryScenarioDisk extends PascalDisk
+ "HP St In Pi Vi Ag Lu Status\n"); + "HP St In Pi Vi Ag Lu Status\n");
text.append ("------------- ---- -------- -------- ---------- " text.append ("------------- ---- -------- -------- ---------- "
+ "-- -- -- -- -- -- -- ------\n"); + "-- -- -- -- -- -- -- ------\n");
for (Character ch : characters) for (CharacterV1 ch : characters)
{ {
Statistics stats = ch.getStatistics (); int[] att = ch.getAttributes ();
Attributes att = ch.getAttributes (); text.append (String.format ("%-15s %2d %-8s %-8s %-8s %3d", ch, (ch.ageInWeeks / 52),
text.append ( ch.getAlignment (), ch.getRace (), ch.getType (), ch.hpMax));
String.format ("%-15s %2d %-8s %-8s %-8s %3d", ch, (stats.ageInWeeks / 52), text.append (String.format (" %2d %2d %2d %2d %2d %2d", att[0], att[1], att[2], att[3],
stats.alignment, stats.race, stats.type, stats.hitsMax)); att[4], att[5]));
text.append (String.format (" %2d %2d %2d %2d %2d %2d", att.strength, text.append (String.format (" %5s %s%n", ch.getStatus (), ch.isOut () ? "* OUT *" : ""));
att.intelligence, att.piety, att.vitality, att.agility, att.luck));
text.append (
String.format (" %5s %s%n", stats.status, ch.isOut () ? "* OUT *" : ""));
} }
DefaultAppleFileSource afs = (DefaultAppleFileSource) node.getUserObject (); DefaultAppleFileSource afs = (DefaultAppleFileSource) node.getUserObject ();
@ -273,22 +265,24 @@ public class WizardryScenarioDisk extends PascalDisk
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
private void addCharacters (byte[] buffer, List<DiskAddress> blocks, private void addCharacters (byte[] buffer, List<DiskAddress> blocks, DefaultMutableTreeNode node)
DefaultMutableTreeNode node)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
int recLen = 208; int recLen = 208;
for (int ptr = 0; ptr < 832; ptr += recLen) for (int ptr = 0; ptr < 832; ptr += recLen)
{ {
int nameLength = buffer[ptr] & 0xFF; int nameLength = buffer[ptr] & 0xFF;
if (nameLength == 0xC3 || buffer[ptr + 40] == 0x07) if (nameLength == 0xC3)
continue; return;
String name = HexFormatter.getString (buffer, ptr + 1, nameLength); String name = HexFormatter.getString (buffer, ptr + 1, nameLength);
if (name.isEmpty () || ("UNSET".equals (name) && buffer[ptr + 40] == 0x07)) // 7 = LOST
continue;
byte[] data2 = new byte[recLen]; byte[] data2 = new byte[recLen];
System.arraycopy (buffer, ptr, data2, 0, recLen); System.arraycopy (buffer, ptr, data2, 0, recLen);
Character c = new Character (name, data2, scenarioHeader.scenarioID); CharacterV1 c = new CharacterV1 (name, data2, scenarioHeader.scenarioID);
characters.add (c); characters.add (c);
addToNode (c, node, blocks, characterSector); addToNode (c, node, blocks, characterSector);
} }
@ -319,7 +313,7 @@ public class WizardryScenarioDisk extends PascalDisk
for (int i = 0; i < 24; i++) for (int i = 0; i < 24; i++)
text.append (" --"); text.append (" --");
text.append ("\n"); text.append ("\n");
for (Monster m : monsters) for (MonsterV1 m : monsters)
text.append (m.getDump (block) + "\n"); text.append (m.getDump (block) + "\n");
text.append ("\n"); text.append ("\n");
} }
@ -330,8 +324,7 @@ public class WizardryScenarioDisk extends PascalDisk
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
private void addMonsters (byte[] buffer, List<DiskAddress> blocks, private void addMonsters (byte[] buffer, List<DiskAddress> blocks, DefaultMutableTreeNode node)
DefaultMutableTreeNode node)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
int recLen = 158; int recLen = 158;
@ -345,7 +338,8 @@ public class WizardryScenarioDisk extends PascalDisk
byte[] data2 = new byte[recLen]; byte[] data2 = new byte[recLen];
System.arraycopy (buffer, ptr, data2, 0, recLen); System.arraycopy (buffer, ptr, data2, 0, recLen);
Monster m = new Monster (itemName, data2, rewards, monsters); MonsterV1 m = new MonsterV1 (monsterId++, itemName, data2, rewards, monsters,
scenarioHeader.scenarioID);
monsters.add (m); monsters.add (m);
addToNode (m, node, blocks, monsterSector); addToNode (m, node, blocks, monsterSector);
} }
@ -369,14 +363,16 @@ public class WizardryScenarioDisk extends PascalDisk
} }
StringBuilder text = new StringBuilder (); StringBuilder text = new StringBuilder ();
for (int block = 0; block < 3; block++) for (int block = 0; block < 2; block++)
{ {
text.append (" ID Name\n"); text.append (" ID Name ");
text.append ("--- ---------------"); for (int i = 0; i < 24; i++)
text.append (String.format ("%2d ", i));
text.append ("\n--- ---------------");
for (int i = 0; i < 24; i++) for (int i = 0; i < 24; i++)
text.append (" --"); text.append (" --");
text.append ("\n"); text.append ("\n");
for (Item item : items) for (ItemV1 item : items)
text.append (item.getDump (block) + "\n"); text.append (item.getDump (block) + "\n");
text.append ("\n"); text.append ("\n");
} }
@ -387,8 +383,7 @@ public class WizardryScenarioDisk extends PascalDisk
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
private void addItems (byte[] buffer, List<DiskAddress> blocks, private void addItems (byte[] buffer, List<DiskAddress> blocks, DefaultMutableTreeNode node)
DefaultMutableTreeNode node)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
int recLen = 78; int recLen = 78;
@ -401,14 +396,14 @@ public class WizardryScenarioDisk extends PascalDisk
byte[] data2 = new byte[recLen]; byte[] data2 = new byte[recLen];
System.arraycopy (buffer, ptr, data2, 0, recLen); System.arraycopy (buffer, ptr, data2, 0, recLen);
Item i = new Item (itemName, data2); ItemV1 i = new ItemV1 (itemId++, itemName, data2);
items.add (i); items.add (i);
addToNode (i, node, blocks, itemSector); addToNode (i, node, blocks, itemSector);
} }
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
private void extractSpells (DefaultMutableTreeNode node, List<DiskAddress> sectors) private void extractSpells (List<DiskAddress> sectors)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
spells = new ArrayList<> (); spells = new ArrayList<> ();
@ -423,6 +418,7 @@ public class WizardryScenarioDisk extends PascalDisk
byte[] buffer = disk.readBlock (da); byte[] buffer = disk.readBlock (da);
int level = 1; int level = 1;
int ptr = -1; int ptr = -1;
while (ptr < 255) while (ptr < 255)
{ {
ptr++; ptr++;
@ -431,15 +427,17 @@ public class WizardryScenarioDisk extends PascalDisk
ptr++; ptr++;
if (ptr == start) if (ptr == start)
break; break;
String spell = HexFormatter.getString (buffer, start, ptr - start); String spell = HexFormatter.getString (buffer, start, ptr - start);
if (spell.startsWith ("*")) if (spell.startsWith ("*"))
{ {
spell = spell.substring (1); spell = spell.substring (1);
++level; ++level;
} }
Spell s = Spell.getSpell (spell, spellType, level, buffer); Spell s = Spell.getSpell (spell, spellType, level, buffer);
spells.add (s); spells.add (s);
// addToNode (s, node, da, spellSector);
} }
spellType = SpellType.PRIEST; spellType = SpellType.PRIEST;
} }
@ -449,7 +447,7 @@ public class WizardryScenarioDisk extends PascalDisk
private void extractMessages (DefaultMutableTreeNode node, List<DiskAddress> sectors) private void extractMessages (DefaultMutableTreeNode node, List<DiskAddress> sectors)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
Message.resetMessageId (); MessageV1.resetMessageId ();
messages = new ArrayList<> (); messages = new ArrayList<> ();
// Copy first 504 bytes from each sector to a single contiguous buffer // Copy first 504 bytes from each sector to a single contiguous buffer
@ -472,7 +470,7 @@ public class WizardryScenarioDisk extends PascalDisk
{ {
int sequence = buffer[ptr + recordLength - 2]; int sequence = buffer[ptr + recordLength - 2];
++totalLines; ++totalLines;
if (sequence == 1) // end of message if (sequence == 1) // end of message
{ {
int totalBytes = totalLines * recordLength; int totalBytes = totalLines * recordLength;
byte[] newBuffer = new byte[totalBytes]; byte[] newBuffer = new byte[totalBytes];
@ -480,7 +478,7 @@ public class WizardryScenarioDisk extends PascalDisk
int messageStart = messageEnd - totalBytes; int messageStart = messageEnd - totalBytes;
System.arraycopy (buffer, messageStart, newBuffer, 0, totalBytes); System.arraycopy (buffer, messageStart, newBuffer, 0, totalBytes);
Message m; MessageV1 m;
if (scenarioHeader.scenarioID == 1) if (scenarioHeader.scenarioID == 1)
m = new PlainMessage (newBuffer); m = new PlainMessage (newBuffer);
else else
@ -560,7 +558,7 @@ public class WizardryScenarioDisk extends PascalDisk
System.arraycopy (buffer, 0, exactBuffer, 0, exactBuffer.length); System.arraycopy (buffer, 0, exactBuffer, 0, exactBuffer.length);
String name = "Unknown"; String name = "Unknown";
for (Monster m : monsters) for (MonsterV1 m : monsters)
if (m.imageID == i) if (m.imageID == i)
{ {
name = m.genericName; name = m.genericName;
@ -584,15 +582,18 @@ public class WizardryScenarioDisk extends PascalDisk
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
private void extractExperienceLevels (DefaultMutableTreeNode node, private void extractExperienceLevels (DefaultMutableTreeNode node, List<DiskAddress> sectors)
List<DiskAddress> sectors)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
List<DiskAddress> nodeSectors = new ArrayList<> (); List<DiskAddress> nodeSectors = new ArrayList<> ();
ScenarioData sd = scenarioHeader.data.get (Header.EXPERIENCE_AREA); ScenarioData sd = scenarioHeader.data.get (Header.EXPERIENCE_AREA);
experiences = new ArrayList<> (sd.total); experienceLevels = new ArrayList<> (sd.total);
int max = sd.totalBlocks / 2; int max = sd.totalBlocks / 2;
int count = 0;
String[] classes =
{ "FIGHTER", "MAGE", "PRIEST", "THIEF", "BISHOP", "SAMURAI", "LORD", "NINJA" };
for (int i = 0; i < max; i++) for (int i = 0; i < max; i++)
{ {
List<DiskAddress> blocks = getTwoBlocks (sd, i, sectors); List<DiskAddress> blocks = getTwoBlocks (sd, i, sectors);
@ -606,8 +607,8 @@ public class WizardryScenarioDisk extends PascalDisk
byte[] newBuffer = new byte[78]; byte[] newBuffer = new byte[78];
System.arraycopy (buffer, ptr, newBuffer, 0, newBuffer.length); System.arraycopy (buffer, ptr, newBuffer, 0, newBuffer.length);
ExperienceLevel el = new ExperienceLevel ("exp", newBuffer); ExperienceLevel el = new ExperienceLevel (classes[count++], newBuffer);
experiences.add (el); experienceLevels.add (el);
addToNode (el, node, blocks, experienceSector); addToNode (el, node, blocks, experienceSector);
} }
} }
@ -627,20 +628,18 @@ public class WizardryScenarioDisk extends PascalDisk
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
private void addToNode (AbstractFile af, DefaultMutableTreeNode node, private void addToNode (AbstractFile af, DefaultMutableTreeNode node, List<DiskAddress> blocks,
List<DiskAddress> blocks, SectorType type) SectorType type)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
DefaultAppleFileSource dafs = DefaultAppleFileSource dafs = new DefaultAppleFileSource (af.getName (), af, this, blocks);
new DefaultAppleFileSource (af.getName (), af, this, blocks);
DefaultMutableTreeNode childNode = new DefaultMutableTreeNode (dafs); DefaultMutableTreeNode childNode = new DefaultMutableTreeNode (dafs);
node.add (childNode); node.add (childNode);
childNode.setAllowsChildren (false); childNode.setAllowsChildren (false);
} }
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
private List<DiskAddress> getTwoBlocks (ScenarioData sd, int i, private List<DiskAddress> getTwoBlocks (ScenarioData sd, int i, List<DiskAddress> sectors)
List<DiskAddress> sectors)
// ---------------------------------------------------------------------------------// // ---------------------------------------------------------------------------------//
{ {
List<DiskAddress> blocks = new ArrayList<> (2); List<DiskAddress> blocks = new ArrayList<> (2);