mirror of
https://github.com/dmolony/DiskBrowser.git
synced 2024-06-01 18:41:27 +00:00
Compare commits
67 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
2bc330e377 | ||
|
6c81bcc93b | ||
|
171fd66ba1 | ||
|
aa77ec1cd4 | ||
|
8f95988596 | ||
|
8cb682f068 | ||
|
dfc7a68580 | ||
|
4b476457d3 | ||
|
3bf972a761 | ||
|
fd5bee6e5c | ||
|
0af6714119 | ||
|
22dfaf65c6 | ||
|
f4a6465b04 | ||
|
64d5ce9ee2 | ||
|
4e48437adc | ||
|
e2abdcabc9 | ||
|
bc0993e9d3 | ||
|
9fba3893ba | ||
|
09c4542118 | ||
|
af3ead0441 | ||
|
c12392200b | ||
|
794fef8610 | ||
|
2ec0e10c5e | ||
|
668ed719fa | ||
|
23b95675cf | ||
|
b98ecbed8d | ||
|
82381a6a47 | ||
|
3f2f1bfbca | ||
|
a7119528a6 | ||
|
6f943ae8c2 | ||
|
5add6c0729 | ||
|
921c946ab5 | ||
|
898587b23b | ||
|
37c489f252 | ||
|
036e47b9b1 | ||
|
250c1a9bd9 | ||
|
b19e89d7cf | ||
|
d71cabb754 | ||
|
848b2469ae | ||
|
989b1d5ab9 | ||
|
e0a2c50d5b | ||
|
8765299cf4 | ||
|
97fe58d94d | ||
|
7d4d8c75e6 | ||
|
f5664a9ce9 | ||
|
9d8cdcd67b | ||
|
12b74f9d21 | ||
|
1b405c6f38 | ||
|
66d6910f91 | ||
|
572ee8c3a1 | ||
|
2a14b7baad | ||
|
a633e28ed3 | ||
|
ca11e8ee68 | ||
|
ce52253f5d | ||
|
e408aa3d62 | ||
|
c4b4d17f52 | ||
|
0b72f1a37d | ||
|
1b86b31233 | ||
|
1b9e9d47ac | ||
|
decc781572 | ||
|
16ccc2632a | ||
|
40c2afbd48 | ||
|
f9038810d2 | ||
|
3435e825df | ||
|
ff7c6fd126 | ||
|
91846d8563 | ||
|
19b6339ac5 |
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -1,4 +0,0 @@
|
||||||
/bin/
|
|
||||||
.project
|
|
||||||
.classpath
|
|
||||||
build.xml
|
|
|
@ -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
40
build.xml
Normal 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
BIN
resources/wizardry4.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.0 MiB |
|
@ -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;
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -16,9 +16,10 @@ import com.bytezone.diskbrowser.utilities.Utility;
|
||||||
public abstract class HiResImage extends AbstractFile
|
public abstract class HiResImage extends AbstractFile
|
||||||
// -----------------------------------------------------------------------------------//
|
// -----------------------------------------------------------------------------------//
|
||||||
{
|
{
|
||||||
static final String[] auxTypes = { "Paintworks Packed SHR Image", "Packed Super Hi-Res Image",
|
static final String[] auxTypes =
|
||||||
"Super Hi-Res Image (Apple Preferred Format)", "Packed QuickDraw II PICT File",
|
{ "Paintworks Packed SHR Image", "Packed Super Hi-Res Image",
|
||||||
"Packed Super Hi-Res 3200 color image", "DreamGraphix" };
|
"Super Hi-Res Image (Apple Preferred Format)", "Packed QuickDraw II PICT File",
|
||||||
|
"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;
|
||||||
|
@ -115,7 +116,8 @@ public abstract class HiResImage extends AbstractFile
|
||||||
|
|
||||||
static PaletteFactory paletteFactory = new PaletteFactory ();
|
static PaletteFactory paletteFactory = new PaletteFactory ();
|
||||||
|
|
||||||
static final byte[] pngHeader = { (byte) 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A };
|
static final byte[] pngHeader =
|
||||||
|
{ (byte) 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A };
|
||||||
|
|
||||||
static boolean colourQuirks;
|
static boolean colourQuirks;
|
||||||
static boolean monochrome;
|
static boolean monochrome;
|
||||||
|
@ -275,8 +277,8 @@ public abstract class HiResImage extends AbstractFile
|
||||||
{
|
{
|
||||||
String auxText = "";
|
String auxText = "";
|
||||||
StringBuilder text = new StringBuilder ();
|
StringBuilder text = new StringBuilder ();
|
||||||
text.append (String.format ("Image File : %s%nFile type : $%02X %s%n", name, fileType,
|
text.append (String.format ("Image File : %s%nFile type : $%02X %s%n", name,
|
||||||
ProdosConstants.fileTypes[fileType]));
|
fileType, ProdosConstants.fileTypes[fileType]));
|
||||||
|
|
||||||
switch (fileType)
|
switch (fileType)
|
||||||
{
|
{
|
||||||
|
@ -393,7 +395,8 @@ public abstract class HiResImage extends AbstractFile
|
||||||
{
|
{
|
||||||
if (dataBuffer.getSize () < rgbList.length + element)
|
if (dataBuffer.getSize () < rgbList.length + element)
|
||||||
{
|
{
|
||||||
System.out.printf ("Bollocks: %d %d %d%n", dataBuffer.getSize (), rgbList.length, element);
|
System.out.printf ("Bollocks: %d %d %d%n", dataBuffer.getSize (), rgbList.length,
|
||||||
|
element);
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -462,12 +465,13 @@ public abstract class HiResImage extends AbstractFile
|
||||||
int type = (buffer[ptr] & 0xC0) >>> 6; // 0-3
|
int type = (buffer[ptr] & 0xC0) >>> 6; // 0-3
|
||||||
int count = (buffer[ptr++] & 0x3F) + 1; // 1-64
|
int count = (buffer[ptr++] & 0x3F) + 1; // 1-64
|
||||||
|
|
||||||
text.append (String.format ("%04X/%04d: %02X (%d,%2d) ", ptr - 1, size, buffer[ptr - 1],
|
text.append (String.format ("%04X/%04d: %02X (%d,%2d) ", ptr - 1, size,
|
||||||
type, count));
|
buffer[ptr - 1], type, count));
|
||||||
|
|
||||||
if (type == 0)
|
if (type == 0)
|
||||||
{
|
{
|
||||||
text.append (String.format ("%s%n", HexFormatter.getHexString (buffer, ptr, count)));
|
text.append (
|
||||||
|
String.format ("%s%n", HexFormatter.getHexString (buffer, ptr, count)));
|
||||||
ptr += count;
|
ptr += count;
|
||||||
size += count;
|
size += count;
|
||||||
}
|
}
|
||||||
|
@ -651,8 +655,8 @@ public abstract class HiResImage extends AbstractFile
|
||||||
if (buffer.length < 4)
|
if (buffer.length < 4)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return buffer[0] == (byte) 0xC1 && buffer[1] == (byte) 0xD0 && buffer[2] == (byte) 0xD0
|
return buffer[0] == (byte) 0xC1 && buffer[1] == (byte) 0xD0
|
||||||
&& buffer[3] == 0;
|
&& buffer[2] == (byte) 0xD0 && buffer[3] == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------//
|
// ---------------------------------------------------------------------------------//
|
||||||
|
|
|
@ -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 ();
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -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:
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -157,14 +157,15 @@ 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") || (suffix.equalsIgnoreCase ("po") && tracks > 50)) // ULTIMATE APPLE1 CFFA 3.5.po
|
else if (suffix.equalsIgnoreCase ("HDV") //
|
||||||
|
|| (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
|
||||||
this.blocks = tracks * sectors;
|
this.blocks = tracks * sectors;
|
||||||
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;
|
||||||
|
@ -732,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));
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
@ -363,6 +368,8 @@ public class DiskFactory
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
disk.setOriginalPath (originalPath); // allow Save converted disk...
|
||||||
|
|
||||||
return disk;
|
return disk;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
@ -411,7 +418,8 @@ public class DiskFactory
|
||||||
|
|
||||||
if (length != DISK_143K) // 16 sector floppy disk
|
if (length != DISK_143K) // 16 sector floppy disk
|
||||||
{
|
{
|
||||||
System.out.printf ("%s: invalid file length : %,d%n", file.getName (), file.length ());
|
System.out.printf ("%s: invalid file length : %,d%n", file.getName (),
|
||||||
|
file.length ());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -571,8 +579,8 @@ public class DiskFactory
|
||||||
disk = new DataDisk (appleDisk256);
|
disk = new DataDisk (appleDisk256);
|
||||||
|
|
||||||
if (debug)
|
if (debug)
|
||||||
System.out
|
System.out.println (
|
||||||
.println ("Factory creating disk : " + disk.getDisk ().getFile ().getAbsolutePath ());
|
"Factory creating disk : " + disk.getDisk ().getFile ().getAbsolutePath ());
|
||||||
|
|
||||||
if (disk != null && compressed)
|
if (disk != null && compressed)
|
||||||
disk.setOriginalPath (originalPath);
|
disk.setOriginalPath (originalPath);
|
||||||
|
@ -678,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 ());
|
||||||
|
@ -713,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)
|
||||||
|
@ -728,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;
|
||||||
}
|
}
|
||||||
|
@ -853,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)
|
||||||
{
|
{
|
||||||
|
@ -878,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;
|
||||||
|
@ -888,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);
|
||||||
|
|
||||||
|
@ -895,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;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------//
|
// ---------------------------------------------------------------------------------//
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------//
|
// ---------------------------------------------------------------------------------//
|
||||||
|
|
|
@ -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 ();
|
||||||
|
|
||||||
|
|
|
@ -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));
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 ());
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------//
|
// ---------------------------------------------------------------------------------//
|
||||||
|
|
|
@ -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 ());
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------//
|
// ---------------------------------------------------------------------------------//
|
||||||
|
|
125
src/com/bytezone/diskbrowser/nufx/Squeeze.java
Normal file
125
src/com/bytezone/diskbrowser/nufx/Squeeze.java
Normal 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)
|
||||||
|
// ---------------------------------------------------------------------------------//
|
||||||
|
{
|
||||||
|
};
|
||||||
|
}
|
|
@ -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
|
|
@ -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<> ();
|
||||||
|
|
||||||
|
|
|
@ -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++)
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
@ -47,8 +49,8 @@ public class PascalDisk extends AbstractFormattedDisk
|
||||||
SectorType fotoSector = new SectorType ("Foto", Color.gray);
|
SectorType fotoSector = new SectorType ("Foto", Color.gray);
|
||||||
SectorType badSector = new SectorType ("Bad", Color.darkGray);
|
SectorType badSector = new SectorType ("Bad", Color.darkGray);
|
||||||
|
|
||||||
SectorType[] sectors = { catalogSector, badSector, codeSector, textSector, infoSector, dataSector,
|
SectorType[] sectors = { catalogSector, badSector, codeSector, textSector, infoSector,
|
||||||
grafSector, fotoSector };
|
dataSector, grafSector, fotoSector };
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------//
|
// ---------------------------------------------------------------------------------//
|
||||||
public PascalDisk (Disk disk)
|
public PascalDisk (Disk disk)
|
||||||
|
@ -99,7 +101,8 @@ public class PascalDisk extends AbstractFormattedDisk
|
||||||
freeBlocks.set (i, false);
|
freeBlocks.set (i, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
diskCatalogSector = new PascalCatalogSector (disk, disk.readBlocks (sectors), sectors);
|
diskCatalogSector =
|
||||||
|
new PascalCatalogSector (disk, disk.readBlocks (sectors), sectors);
|
||||||
|
|
||||||
// read the catalog
|
// read the catalog
|
||||||
List<DiskAddress> addresses = new ArrayList<> ();
|
List<DiskAddress> addresses = new ArrayList<> ();
|
||||||
|
@ -174,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);
|
||||||
|
@ -208,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;
|
||||||
|
@ -278,14 +299,18 @@ public class PascalDisk extends AbstractFormattedDisk
|
||||||
{
|
{
|
||||||
String newLine = String.format ("%n");
|
String newLine = String.format ("%n");
|
||||||
String newLine2 = newLine + newLine;
|
String newLine2 = newLine + newLine;
|
||||||
String line =
|
String line = "---- --------------- ---- -------- ------- ---- ---- ----"
|
||||||
"---- --------------- ---- -------- ------- ---- ---- ----" + newLine;
|
+ newLine;
|
||||||
String date = volumeEntry.date == null ? "--" : df.format (volumeEntry.date.getTime ());
|
|
||||||
|
String date =
|
||||||
|
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);
|
||||||
text.append ("Date : " + date + newLine2);
|
text.append ("Date : " + date + newLine2);
|
||||||
text.append ("Blks Name Type Date Length Frst Last Blks\n");
|
text.append (
|
||||||
|
"Blks Name Type Date Length Frst Last Blks\n");
|
||||||
text.append (line);
|
text.append (line);
|
||||||
|
|
||||||
int usedBlocks = 6;
|
int usedBlocks = 6;
|
||||||
|
@ -294,16 +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 =
|
String fileType = ce.fileType < 0 || ce.fileType >= fileTypes.length ? "????"
|
||||||
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", size,
|
text.append (String.format ("%4d %-15s %-6s %8s %,8d $%03X $%03X $%03X%n",
|
||||||
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 (String.format ("Blocks free : %3d Blocks used : %3d Total blocks : %3d%n",
|
text.append (
|
||||||
(volumeEntry.totalBlocks - usedBlocks), usedBlocks, volumeEntry.totalBlocks));
|
String.format ("Blocks free : %3d Blocks used : %3d Total blocks : %3d%n",
|
||||||
|
(volumeEntry.totalBlocks - usedBlocks), usedBlocks, volumeEntry.totalBlocks));
|
||||||
|
|
||||||
return new DefaultAppleFileSource (volumeEntry.name, text.toString (), this);
|
return new DefaultAppleFileSource (volumeEntry.name, text.toString (), this);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------//
|
// ---------------------------------------------------------------------------------//
|
||||||
|
|
|
@ -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)));
|
||||||
|
|
|
@ -72,8 +72,8 @@ class FileEntry extends CatalogEntry implements ProdosConstants
|
||||||
private FileEntry link;
|
private FileEntry link;
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------//
|
// ---------------------------------------------------------------------------------//
|
||||||
FileEntry (ProdosDisk fDisk, byte[] entryBuffer, DirectoryHeader parent, int parentBlock,
|
FileEntry (ProdosDisk fDisk, byte[] entryBuffer, DirectoryHeader parent,
|
||||||
int entryNo)
|
int parentBlock, int entryNo)
|
||||||
// ---------------------------------------------------------------------------------//
|
// ---------------------------------------------------------------------------------//
|
||||||
{
|
{
|
||||||
super (fDisk, entryBuffer, parentBlock, entryNo);
|
super (fDisk, entryBuffer, parentBlock, entryNo);
|
||||||
|
@ -143,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);
|
||||||
|
@ -162,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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -349,7 +350,8 @@ class FileEntry extends CatalogEntry implements ProdosConstants
|
||||||
file = new DoubleHiResImage (name, outBuffer);
|
file = new DoubleHiResImage (name, outBuffer);
|
||||||
break;
|
break;
|
||||||
case 0x8000:
|
case 0x8000:
|
||||||
file = new SHRPictureFile2 (name, outBuffer, FILE_TYPE_PIC, 0x2000, 0x8000);
|
file =
|
||||||
|
new SHRPictureFile2 (name, outBuffer, FILE_TYPE_PIC, 0x2000, 0x8000);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
file = new AssemblerProgram (name, exactBuffer, auxType);
|
file = new AssemblerProgram (name, exactBuffer, auxType);
|
||||||
|
@ -369,8 +371,8 @@ class FileEntry extends CatalogEntry implements ProdosConstants
|
||||||
}
|
}
|
||||||
// else if (name.endsWith (".PIC")) // 0091 X-BASIC../../XBASIC.PIC
|
// else if (name.endsWith (".PIC")) // 0091 X-BASIC../../XBASIC.PIC
|
||||||
// file = new SHRPictureFile2 (name, exactBuffer, fileType, auxType, endOfFile);
|
// file = new SHRPictureFile2 (name, exactBuffer, fileType, auxType, endOfFile);
|
||||||
else if ((name.equals ("DOS.3.3") || name.equals ("DDOS.3.3")) && endOfFile == 0x2800
|
else if ((name.equals ("DOS.3.3") || name.equals ("DDOS.3.3"))
|
||||||
&& DosMasterFile.isDos33 (parentDisk, exactBuffer))
|
&& endOfFile == 0x2800 && DosMasterFile.isDos33 (parentDisk, exactBuffer))
|
||||||
{
|
{
|
||||||
file = new DosMasterFile (name, exactBuffer);
|
file = new DosMasterFile (name, exactBuffer);
|
||||||
}
|
}
|
||||||
|
@ -413,8 +415,8 @@ class FileEntry extends CatalogEntry implements ProdosConstants
|
||||||
|
|
||||||
case FILE_TYPE_DIRECTORY:
|
case FILE_TYPE_DIRECTORY:
|
||||||
VolumeDirectoryHeader vdh = parentDisk.getVolumeDirectoryHeader ();
|
VolumeDirectoryHeader vdh = parentDisk.getVolumeDirectoryHeader ();
|
||||||
file = new ProdosDirectory (parentDisk, name, buffer, vdh.totalBlocks, vdh.freeBlocks,
|
file = new ProdosDirectory (parentDisk, name, buffer, vdh.totalBlocks,
|
||||||
vdh.usedBlocks);
|
vdh.freeBlocks, vdh.usedBlocks);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FILE_TYPE_APPLESOFT_BASIC_VARS:
|
case FILE_TYPE_APPLESOFT_BASIC_VARS:
|
||||||
|
@ -547,6 +549,8 @@ class FileEntry extends CatalogEntry implements ProdosConstants
|
||||||
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;
|
||||||
|
@ -623,7 +627,8 @@ class FileEntry extends CatalogEntry implements ProdosConstants
|
||||||
if (addresses.size () > 0)
|
if (addresses.size () > 0)
|
||||||
{
|
{
|
||||||
byte[] tempBuffer = disk.readBlocks (addresses);
|
byte[] tempBuffer = disk.readBlocks (addresses);
|
||||||
buffers.add (new TextBuffer (tempBuffer, auxType, logicalBlock - addresses.size ()));
|
buffers.add (
|
||||||
|
new TextBuffer (tempBuffer, auxType, logicalBlock - addresses.size ()));
|
||||||
addresses.clear ();
|
addresses.clear ();
|
||||||
}
|
}
|
||||||
logicalBlock += 256;
|
logicalBlock += 256;
|
||||||
|
@ -723,8 +728,8 @@ class FileEntry extends CatalogEntry implements ProdosConstants
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------//
|
// ---------------------------------------------------------------------------------//
|
||||||
private int readIndexBlock (int indexBlock, List<DiskAddress> addresses, List<TextBuffer> buffers,
|
private int readIndexBlock (int indexBlock, List<DiskAddress> addresses,
|
||||||
int logicalBlock)
|
List<TextBuffer> buffers, int logicalBlock)
|
||||||
// ---------------------------------------------------------------------------------//
|
// ---------------------------------------------------------------------------------//
|
||||||
{
|
{
|
||||||
byte[] indexBuffer = disk.readBlock (indexBlock);
|
byte[] indexBuffer = disk.readBlock (indexBlock);
|
||||||
|
@ -736,7 +741,8 @@ class FileEntry extends CatalogEntry implements ProdosConstants
|
||||||
else if (addresses.size () > 0)
|
else if (addresses.size () > 0)
|
||||||
{
|
{
|
||||||
byte[] tempBuffer = disk.readBlocks (addresses);
|
byte[] tempBuffer = disk.readBlocks (addresses);
|
||||||
buffers.add (new TextBuffer (tempBuffer, auxType, logicalBlock - addresses.size ()));
|
buffers
|
||||||
|
.add (new TextBuffer (tempBuffer, auxType, logicalBlock - addresses.size ()));
|
||||||
addresses.clear ();
|
addresses.clear ();
|
||||||
}
|
}
|
||||||
logicalBlock++;
|
logicalBlock++;
|
||||||
|
@ -807,13 +813,14 @@ class FileEntry extends CatalogEntry implements ProdosConstants
|
||||||
String locked = (access == 0x00) ? "*" : " ";
|
String locked = (access == 0x00) ? "*" : " ";
|
||||||
|
|
||||||
if (true)
|
if (true)
|
||||||
return String.format ("%s %03d %s", ProdosConstants.fileTypes[fileType], blocksUsed, locked)
|
return String.format ("%s %03d %s", ProdosConstants.fileTypes[fileType],
|
||||||
+ name;
|
blocksUsed, locked) + name;
|
||||||
|
|
||||||
String timeC = created == null ? "" : created.format (ProdosDisk.df);
|
String timeC = created == null ? "" : created.format (ProdosDisk.df);
|
||||||
String timeF = modified == null ? "" : modified.format (ProdosDisk.df);
|
String timeF = modified == null ? "" : modified.format (ProdosDisk.df);
|
||||||
|
|
||||||
return String.format ("%s %s%-30s %3d %,10d %15s %15s", ProdosConstants.fileTypes[fileType],
|
return String.format ("%s %s%-30s %3d %,10d %15s %15s",
|
||||||
locked, parentDirectory.name + "/" + name, blocksUsed, endOfFile, timeC, timeF);
|
ProdosConstants.fileTypes[fileType], locked, parentDirectory.name + "/" + name,
|
||||||
|
blocksUsed, endOfFile, timeC, timeF);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------//
|
// ---------------------------------------------------------------------------------//
|
||||||
|
|
|
@ -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 + "]";
|
||||||
+ "]";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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));
|
||||||
|
|
|
@ -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 };
|
||||||
}
|
}
|
385
src/com/bytezone/diskbrowser/wizardry/Character.java
Executable file → Normal file
385
src/com/bytezone/diskbrowser/wizardry/Character.java
Executable file → Normal file
|
@ -1,24 +1,14 @@
|
||||||
package com.bytezone.diskbrowser.wizardry;
|
package com.bytezone.diskbrowser.wizardry;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
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 static char[] awardsText = ">!$#&*<?BCPKODG@".toCharArray ();
|
static int MAGE_SPELLS = 0;
|
||||||
|
static int PRIEST_SPELLS = 1;
|
||||||
private final Attributes attributes;
|
|
||||||
private final Statistics stats;
|
|
||||||
int scenario;
|
|
||||||
|
|
||||||
private final List<Spell> spellBook = new ArrayList<> ();
|
|
||||||
private final List<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" };
|
||||||
|
@ -26,196 +16,90 @@ 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;
|
||||||
|
|
||||||
|
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
|
||||||
|
{
|
||||||
|
NORACE, HUMAN, ELF, DWARF, GNOME, HOBBIT
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Alignment
|
||||||
|
{
|
||||||
|
UNALIGN, GOOD, NEUTRAL, EVIL
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum CharacterStatus
|
||||||
|
{
|
||||||
|
OK, AFRAID, ASLEEP, PLYZE, STONED, DEAD, ASHES, LOST
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum CharacterClass
|
||||||
|
{
|
||||||
|
FIGHTER, MAGE, PRIEST, THIEF, BISHOP, SAMURAI, LORD, NINJA
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------//
|
// ---------------------------------------------------------------------------------//
|
||||||
Character (String name, byte[] buffer, int scenario)
|
Character (String name, byte[] buffer)
|
||||||
// ---------------------------------------------------------------------------------//
|
// ---------------------------------------------------------------------------------//
|
||||||
{
|
{
|
||||||
super (name, buffer);
|
super (name, buffer);
|
||||||
this.scenario = scenario;
|
|
||||||
|
|
||||||
attributes = new Attributes ();
|
|
||||||
stats = new Statistics ();
|
|
||||||
|
|
||||||
stats.race = races[buffer[34] & 0xFF];
|
|
||||||
stats.typeInt = buffer[36] & 0xFF;
|
|
||||||
stats.type = types[stats.typeInt];
|
|
||||||
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;
|
|
||||||
stats.experience = Utility.getShort (buffer, 124) + Utility.getShort (buffer, 126) * 10000;
|
|
||||||
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)
|
void get3x5Bits (int[] attributes, int ptr, int value)
|
||||||
// ---------------------------------------------------------------------------------//
|
// ---------------------------------------------------------------------------------//
|
||||||
{
|
{
|
||||||
boolean equipped;
|
attributes[ptr] = value & 0x001F;
|
||||||
boolean identified;
|
attributes[ptr + 1] = (value & 0x03E0) >>> 5;
|
||||||
int totItems = buffer[58];
|
attributes[ptr + 2] = (value & 0x7C00) >>> 10;
|
||||||
stats.assetValue = 0;
|
}
|
||||||
|
|
||||||
for (int ptr = 60; totItems > 0; ptr += 8, totItems--)
|
// ---------------------------------------------------------------------------------//
|
||||||
|
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 ())
|
|
||||||
{
|
|
||||||
Item item = itemList.get (itemID);
|
|
||||||
equipped = (buffer[ptr] == 1);
|
|
||||||
identified = (buffer[ptr + 4] == 1);
|
|
||||||
baggageList.add (new Baggage (item, equipped, identified));
|
|
||||||
stats.assetValue += item.getCost ();
|
|
||||||
item.partyOwns++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
System.out.println (
|
|
||||||
getName () + " ItemID : " + itemID + " is outside range 0:" + (itemList.size () - 1));
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------//
|
int bit = 1; // skip first bit
|
||||||
public void linkSpells (List<Spell> spellList)
|
int val = buffer[ptr];
|
||||||
// ---------------------------------------------------------------------------------//
|
mysteryBit = (val & 0x01) == 1;
|
||||||
{
|
|
||||||
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 ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------//
|
for (int i = 0; i < spellsKnown.length; i++)
|
||||||
@Override
|
{
|
||||||
public String getText ()
|
if (bit == 8)
|
||||||
// ---------------------------------------------------------------------------------//
|
{
|
||||||
{
|
val = buffer[++ptr];
|
||||||
StringBuilder text = new StringBuilder ();
|
bit = 0;
|
||||||
|
}
|
||||||
text.append ("Character name ..... " + getName ());
|
spellsKnown[i] = ((val >>> bit++) & 0x01) != 0;
|
||||||
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 ............. " + getAwardString ());
|
|
||||||
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 ();
|
|
||||||
text.append ("\n\nMage spell points ..");
|
|
||||||
for (int i = 0; i < spellPoints.length; i++)
|
|
||||||
text.append (" " + spellPoints[i]);
|
|
||||||
|
|
||||||
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 ();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------//
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------//
|
// ---------------------------------------------------------------------------------//
|
||||||
|
@ -235,127 +119,4 @@ class Character extends AbstractFile
|
||||||
|
|
||||||
return text.toString ();
|
return text.toString ();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// ---------------------------------------------------------------------------------//
|
|
||||||
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];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
40
src/com/bytezone/diskbrowser/wizardry/CharacterParty.java
Normal file
40
src/com/bytezone/diskbrowser/wizardry/CharacterParty.java
Normal 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 ();
|
||||||
|
}
|
||||||
|
}
|
252
src/com/bytezone/diskbrowser/wizardry/CharacterV1.java
Executable file
252
src/com/bytezone/diskbrowser/wizardry/CharacterV1.java
Executable 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 ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
223
src/com/bytezone/diskbrowser/wizardry/CharacterV4.java
Normal file
223
src/com/bytezone/diskbrowser/wizardry/CharacterV4.java
Normal 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 ();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
|
@ -101,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)
|
||||||
// ---------------------------------------------------------------------------------//
|
// ---------------------------------------------------------------------------------//
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
207
src/com/bytezone/diskbrowser/wizardry/Item.java
Executable file → Normal 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
156
src/com/bytezone/diskbrowser/wizardry/ItemV1.java
Executable file
156
src/com/bytezone/diskbrowser/wizardry/ItemV1.java
Executable 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;
|
||||||
|
// }
|
||||||
|
}
|
76
src/com/bytezone/diskbrowser/wizardry/ItemV4.java
Normal file
76
src/com/bytezone/diskbrowser/wizardry/ItemV4.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -49,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)
|
||||||
|
@ -345,12 +345,12 @@ class MazeCell
|
||||||
sign.append (" Monster ");
|
sign.append (" Monster ");
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Monster monster = monsters.get (monsterID);
|
MonsterV1 monster = monsters.get (monsterID);
|
||||||
sign.append (" <b>" + monster.getRealName () + " </b>");
|
sign.append (" <b>" + monster.getName () + " </b>");
|
||||||
while (monster.partnerOdds == 100)
|
while (monster.partnerOdds == 100)
|
||||||
{
|
{
|
||||||
monster = monsters.get (monster.partnerID);
|
monster = monsters.get (monster.partnerID);
|
||||||
sign.append ("<br> <b>" + monster.getRealName () + " </b>");
|
sign.append ("<br> <b>" + monster.getName () + " </b>");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (itemRequired != null)
|
if (itemRequired != null)
|
||||||
|
|
|
@ -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));
|
||||||
|
|
||||||
|
|
|
@ -24,9 +24,9 @@ public class MazeLevel extends AbstractFile
|
||||||
"Rock/Water", "Fizzle", "Message/Item", "Monster" };
|
"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)
|
||||||
|
@ -94,7 +94,7 @@ public class MazeLevel extends AbstractFile
|
||||||
text.append ("\n\n");
|
text.append ("\n\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));
|
||||||
|
@ -105,7 +105,7 @@ public 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));
|
||||||
|
@ -191,6 +191,12 @@ public class MazeLevel extends AbstractFile
|
||||||
List<MazeAddress> monsterList)
|
List<MazeAddress> monsterList)
|
||||||
// ---------------------------------------------------------------------------------//
|
// ---------------------------------------------------------------------------------//
|
||||||
{
|
{
|
||||||
|
if (monsters == null)
|
||||||
|
{
|
||||||
|
System.out.println ("monsters is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
text.append ("\n\nSQREXTRA SQRTYPE TSQUARE AUX0 AUX1 AUX2\n");
|
text.append ("\n\nSQREXTRA SQRTYPE TSQUARE AUX0 AUX1 AUX2\n");
|
||||||
for (int j = 0; j < 16; j++)
|
for (int j = 0; j < 16; j++)
|
||||||
{
|
{
|
||||||
|
@ -216,7 +222,7 @@ public class MazeLevel extends AbstractFile
|
||||||
if (messageType == 4)
|
if (messageType == 4)
|
||||||
{
|
{
|
||||||
if (address.level < monsters.size ())
|
if (address.level < monsters.size ())
|
||||||
extraText += monsters.get (address.level).realName;
|
extraText += monsters.get (address.level).getName ();
|
||||||
else
|
else
|
||||||
extraText += "Obtained: " + items.get ((address.level - 64536) * -1).getName ();
|
extraText += "Obtained: " + items.get ((address.level - 64536) * -1).getName ();
|
||||||
}
|
}
|
||||||
|
@ -234,7 +240,7 @@ public class MazeLevel extends AbstractFile
|
||||||
monsterList.add (address);
|
monsterList.add (address);
|
||||||
extraText = "Encounter: ";
|
extraText = "Encounter: ";
|
||||||
if (monsters != null)
|
if (monsters != null)
|
||||||
extraText += monsters.get (address.column).realName;
|
extraText += monsters.get (address.column).getName ();
|
||||||
}
|
}
|
||||||
|
|
||||||
text.append (String.format (" %X --> %X %-15s %04X %04X %04X %s%n", j,
|
text.append (String.format (" %X --> %X %-15s %04X %04X %04X %s%n", j,
|
||||||
|
@ -247,6 +253,7 @@ public class MazeLevel extends AbstractFile
|
||||||
// ---------------------------------------------------------------------------------//
|
// ---------------------------------------------------------------------------------//
|
||||||
{
|
{
|
||||||
text.append ("\n\n");
|
text.append ("\n\n");
|
||||||
|
int savePtr = ptr;
|
||||||
|
|
||||||
text.append (String.format ("MINENEMY %04X %04X %04X%n", Utility.getShort (buffer, ptr),
|
text.append (String.format ("MINENEMY %04X %04X %04X%n", Utility.getShort (buffer, ptr),
|
||||||
Utility.getShort (buffer, ptr + 10), Utility.getShort (buffer, ptr + 20)));
|
Utility.getShort (buffer, ptr + 10), Utility.getShort (buffer, ptr + 20)));
|
||||||
|
@ -262,6 +269,29 @@ public class MazeLevel extends AbstractFile
|
||||||
ptr += 2;
|
ptr += 2;
|
||||||
text.append (String.format ("PERCWORS %04X %04X %04X%n", Utility.getShort (buffer, ptr),
|
text.append (String.format ("PERCWORS %04X %04X %04X%n", Utility.getShort (buffer, ptr),
|
||||||
Utility.getShort (buffer, ptr + 10), Utility.getShort (buffer, ptr + 20)));
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------//
|
// ---------------------------------------------------------------------------------//
|
||||||
|
@ -288,21 +318,21 @@ public class MazeLevel extends AbstractFile
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------//
|
// ---------------------------------------------------------------------------------//
|
||||||
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;
|
||||||
|
@ -418,7 +448,7 @@ public class MazeLevel extends AbstractFile
|
||||||
|
|
||||||
case 11: // screen message
|
case 11: // screen message
|
||||||
MazeAddress messageAddress = getAddress (b);
|
MazeAddress messageAddress = getAddress (b);
|
||||||
Message m = getMessage (messageAddress.row);
|
MessageV1 m = getMessage (messageAddress.row);
|
||||||
if (m != null)
|
if (m != null)
|
||||||
cell.message = m;
|
cell.message = m;
|
||||||
|
|
||||||
|
@ -483,13 +513,13 @@ public class MazeLevel extends AbstractFile
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------//
|
// ---------------------------------------------------------------------------------//
|
||||||
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;
|
||||||
|
|
||||||
|
@ -497,13 +527,13 @@ public 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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------//
|
// ---------------------------------------------------------------------------------//
|
||||||
|
|
|
@ -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);
|
361
src/com/bytezone/diskbrowser/wizardry/Monster.java
Executable file → Normal file
361
src/com/bytezone/diskbrowser/wizardry/Monster.java
Executable file → Normal file
|
@ -1,123 +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 =
|
||||||
|
{ "None", "Fire", "Frost", "Poison", "Level drain", "Stoning", "Magic" };
|
||||||
|
|
||||||
List<Monster> monsters;
|
public int monsterID;
|
||||||
Reward goldReward;
|
|
||||||
Reward chestReward;
|
public String genericName;
|
||||||
|
public String genericNamePlural;
|
||||||
|
public String namePlural;
|
||||||
|
|
||||||
|
public Dice groupSize;
|
||||||
|
public Dice hitPoints;
|
||||||
|
int type;
|
||||||
|
public int armourClass;
|
||||||
|
public int recsn;
|
||||||
|
List<Dice> damage = new ArrayList<> ();
|
||||||
|
|
||||||
|
public int mageSpellLevel;
|
||||||
|
public int priestSpellLevel;
|
||||||
|
|
||||||
public final int type;
|
|
||||||
public final int imageID;
|
|
||||||
int rewardTable1;
|
|
||||||
int rewardTable2;
|
|
||||||
public final int partnerID;
|
|
||||||
public final int partnerOdds;
|
|
||||||
public final int armourClass;
|
|
||||||
public final int recsn;
|
|
||||||
public final int mageSpellLevel;
|
|
||||||
public final int priestSpellLevel;
|
|
||||||
int levelDrain;
|
int levelDrain;
|
||||||
int healPts;
|
int healPts;
|
||||||
int breathe;
|
int breathe;
|
||||||
int unaffect;
|
int unaffect;
|
||||||
int unique;
|
|
||||||
int resistance;
|
int resistance;
|
||||||
int abilities;
|
int abilities;
|
||||||
public final Dice groupSize, hitPoints;
|
|
||||||
List<Dice> damage = new ArrayList<> ();
|
|
||||||
|
|
||||||
static int counter = 0;
|
|
||||||
static boolean debug = true;
|
|
||||||
static int[] pwr = { 0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 0, 0, 0, 0, 0 };
|
|
||||||
static int[] weight1 = { 0, 1, 2, 4, 8, 16, 32, 64, 253, 506, 0 };
|
|
||||||
static int[] weight2 = { 0, 60, 120, 180, 300, 540, 1020, 0 };
|
|
||||||
|
|
||||||
public static String[] monsterClass = { "Fighter", "Mage", "Priest", "Thief", "Midget", "Giant",
|
|
||||||
"Mythical", "Dragon", "Animal", "Were", "Undead", "Demon", "Insect", "Enchanted" };
|
|
||||||
|
|
||||||
private static int[] experience = { //
|
|
||||||
55, 235, 415, 230, 380, 620, 840, 520, 550, 350, // 00-09
|
|
||||||
475, 515, 920, 600, 735, 520, 795, 780, 990, 795, // 10-19
|
|
||||||
1360, 1320, 1275, 680, 960, 600, 755, 1120, 2075, 870, // 20-29
|
|
||||||
960, 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, // 90-99
|
|
||||||
1900 // 100
|
|
||||||
};
|
|
||||||
|
|
||||||
int expHitPoints;
|
|
||||||
int expMage;
|
|
||||||
int expPriest;
|
|
||||||
int expDrain;
|
|
||||||
int expHeal;
|
|
||||||
int expAc;
|
|
||||||
int expDamage;
|
|
||||||
int expUnaffect;
|
|
||||||
int expFlags1;
|
|
||||||
int expFlags2;
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------//
|
// ---------------------------------------------------------------------------------//
|
||||||
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];
|
|
||||||
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 < 8; i++, ptr += 6)
|
|
||||||
{
|
|
||||||
if (buffer[ptr] == 0)
|
|
||||||
break;
|
|
||||||
damage.add (new Dice (buffer, ptr));
|
|
||||||
}
|
|
||||||
|
|
||||||
levelDrain = buffer[132];
|
|
||||||
healPts = buffer[134];
|
|
||||||
rewardTable1 = buffer[136];
|
|
||||||
rewardTable2 = 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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------//
|
// ---------------------------------------------------------------------------------//
|
||||||
|
@ -127,201 +51,35 @@ 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 exp2 = hitPoints.qty * hitPoints.sides;
|
text.append (String.format ("Name plural ..... %s%n", namePlural));
|
||||||
// exp2 *= breathe == 0 ? 20 : 40;
|
text.append (String.format ("Generic name .... %s%n", genericName));
|
||||||
|
text.append (String.format ("Generic name pl . %s%n%n", genericNamePlural));
|
||||||
|
|
||||||
// int exp3 = weight2[recsn]; // 1-6
|
text.append (String.format ("Type ............ %2d %s%n", type, monsterClass[type]));
|
||||||
// int exp3 = 0;
|
text.append (String.format ("Armour class .... %d%n", armourClass));
|
||||||
// if (recsn > 1)
|
text.append (String.format ("Group size ...... %s%n", groupSize));
|
||||||
// exp3 = recsn * 30;
|
text.append (String.format ("Hit points ...... %s%n%n", hitPoints));
|
||||||
|
|
||||||
// int exp4 = (11 - armourClass) * 40;
|
text.append (String.format ("# damage ........ %d%n", recsn));
|
||||||
|
text.append (String.format ("Damage .......... %s%n%n", getDamage ()));
|
||||||
|
|
||||||
// int exp5 = getBonus (35, mageSpellLevel); // correct
|
text.append (String.format ("Mage level ...... %d%n", mageSpellLevel));
|
||||||
// int exp6 = getBonus (35, priestSpellLevel); // correct
|
text.append (String.format ("Priest level .... %d%n%n", priestSpellLevel));
|
||||||
// int exp10 = getBonus (200, levelDrain); // correct
|
|
||||||
// int exp8 = getBonus (90, healPts); // correct
|
|
||||||
|
|
||||||
// int exp7 = weight1[unaffect / 10] * 80;
|
text.append (String.format ("Level drain ..... %d%n", levelDrain));
|
||||||
// int exp7 = unaffect > 0 ? (unaffect / 10 + 1) * 40 : 0;
|
text.append (String.format ("Heal pts ........ %d%n", healPts));
|
||||||
|
text.append (String.format ("Breathe ......... %d %s%n", breathe, breathValues[breathe]));
|
||||||
// int exp11 = breathe > 0 ? exp2 + 20 : 0;
|
text.append (String.format ("Magic resist .... %d%% %n%n", unaffect));
|
||||||
// int exp12 = getBonus (35, Integer.bitCount (resistance & 0x7E));
|
|
||||||
// int exp9 = getBonus (40, Integer.bitCount (abilities & 0x7F));
|
|
||||||
|
|
||||||
int totalExperience = setExperience ();
|
|
||||||
|
|
||||||
text.append ("ID .............. " + monsterID);
|
|
||||||
text.append ("\nMonster name .... " + realName);
|
|
||||||
text.append ("\nGeneric name .... " + genericName);
|
|
||||||
|
|
||||||
text.append ("\n\nImage ID ........ " + imageID);
|
|
||||||
text.append ("\nGroup size ...... " + groupSize);
|
|
||||||
text.append ("\nHit points ...... " + hitPoints);
|
|
||||||
if (debug)
|
|
||||||
text.append (" " + expHitPoints);
|
|
||||||
|
|
||||||
text.append ("\n\nMonster class ... " + type + " " + monsterClass[type]);
|
|
||||||
text.append ("\nArmour class .... " + armourClass);
|
|
||||||
if (debug)
|
|
||||||
text.append (" " + expAc);
|
|
||||||
|
|
||||||
text.append ("\n\n# damage ........ " + recsn);
|
|
||||||
if (debug)
|
|
||||||
text.append (" " + expDamage);
|
|
||||||
|
|
||||||
text.append ("\nDamage .......... " + getDamage ());
|
|
||||||
|
|
||||||
text.append ("\n\nLevel drain ..... " + levelDrain);
|
|
||||||
if (debug)
|
|
||||||
text.append (" " + expDrain);
|
|
||||||
text.append ("\nHeal pts? ....... " + healPts);
|
|
||||||
if (debug)
|
|
||||||
text.append (" " + expHeal);
|
|
||||||
|
|
||||||
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 (" " + expMage);
|
|
||||||
text.append ("\nPriest level .... " + priestSpellLevel);
|
|
||||||
if (debug)
|
|
||||||
text.append (" " + expPriest);
|
|
||||||
|
|
||||||
text.append ("\n\nUnique .......... " + unique);
|
|
||||||
text.append ("\nBreathe ......... " + breathe);
|
|
||||||
// if (debug)
|
|
||||||
// text.append (" " + expBreathe);
|
|
||||||
text.append ("\nUnaffect ........ " + unaffect);
|
|
||||||
if (debug)
|
|
||||||
text.append (" " + expUnaffect);
|
|
||||||
|
|
||||||
text.append ("\n\nResistance ...... " + String.format ("%02X", resistance));
|
|
||||||
if (debug)
|
|
||||||
text.append (" " + expFlags1);
|
|
||||||
text.append ("\nAbilities ....... " + String.format ("%02X", abilities));
|
|
||||||
if (debug)
|
|
||||||
text.append (" " + expFlags2);
|
|
||||||
|
|
||||||
text.append (
|
text.append (
|
||||||
String.format ("%n%nExperience ...... %,7d %,7d", totalExperience, experience[monsterID]));
|
String.format ("Resistance ...... %s%n", String.format ("%3d %<02X", resistance)));
|
||||||
|
text.append (String.format ("Abilities ....... %s%n", String.format ("%3d %<02X", abilities)));
|
||||||
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 ();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------//
|
|
||||||
private int setExperience2 ()
|
|
||||||
// ---------------------------------------------------------------------------------//
|
|
||||||
{
|
|
||||||
expHitPoints = hitPoints.qty * hitPoints.sides * breathe == 0 ? 20 : 40;
|
|
||||||
|
|
||||||
expMage = 35 * mageSpellLevel;
|
|
||||||
expPriest = 35 * priestSpellLevel;
|
|
||||||
expDrain = 200 * levelDrain;
|
|
||||||
expHeal = 90 * healPts;
|
|
||||||
|
|
||||||
expAc = 40 * (11 - armourClass);
|
|
||||||
|
|
||||||
expDamage = recsn <= 1 ? 0 : 30 * recsn;
|
|
||||||
expUnaffect = unaffect == 0 ? 0 : 40 * (unaffect / 10 + 1);
|
|
||||||
expFlags1 = 35 * Integer.bitCount (resistance & 0x7E);
|
|
||||||
expFlags2 = 40 * Integer.bitCount (abilities & 0x7F);
|
|
||||||
|
|
||||||
return expHitPoints + expMage + expPriest + expDrain + expHeal + expAc + expDamage + expUnaffect
|
|
||||||
+ expFlags1 + expFlags2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------//
|
|
||||||
private int setExperience ()
|
|
||||||
// ---------------------------------------------------------------------------------//
|
|
||||||
{
|
|
||||||
expHitPoints = hitPoints.qty * hitPoints.sides * breathe == 0 ? 20 : 40;
|
|
||||||
|
|
||||||
expMage = getBonus (35, mageSpellLevel);
|
|
||||||
expPriest = getBonus (35, priestSpellLevel);
|
|
||||||
expDrain = getBonus (200, levelDrain);
|
|
||||||
expHeal = getBonus (90, healPts);
|
|
||||||
|
|
||||||
expAc = 40 * (11 - armourClass);
|
|
||||||
|
|
||||||
expDamage = recsn <= 1 ? 0 : getBonus (30, recsn);
|
|
||||||
expUnaffect = unaffect == 0 ? 0 : getBonus (40, (unaffect / 10 + 1));
|
|
||||||
expFlags1 = getBonus (35, Integer.bitCount (resistance & 0x7E));
|
|
||||||
expFlags2 = getBonus (40, Integer.bitCount (abilities & 0x7F));
|
|
||||||
|
|
||||||
return expHitPoints + expMage + expPriest + expDrain + expHeal + expAc + expDamage + expUnaffect
|
|
||||||
+ expFlags1 + expFlags2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------//
|
|
||||||
private int getExperienceOld ()
|
|
||||||
// ---------------------------------------------------------------------------------//
|
|
||||||
{
|
|
||||||
// these values definitely affect the damage a monster does (when breathing?)
|
|
||||||
// int exp2 = ((buffer[72] & 0xFF) * (buffer[74] & 0xFF) - 1) * 20;
|
|
||||||
int exp2 = hitPoints.qty * hitPoints.sides;
|
|
||||||
exp2 *= breathe == 0 ? 20 : 40;
|
|
||||||
|
|
||||||
int exp3 = weight2[recsn];
|
|
||||||
int exp4 = (11 - armourClass) * 40;
|
|
||||||
|
|
||||||
int exp5 = getBonus (35, mageSpellLevel);
|
|
||||||
int exp6 = getBonus (35, priestSpellLevel);
|
|
||||||
int exp10 = getBonus (200, levelDrain);
|
|
||||||
int exp8 = getBonus (90, healPts);
|
|
||||||
|
|
||||||
int exp7 = weight1[unaffect / 10] * 80;
|
|
||||||
int exp11 = breathe > 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 ()
|
||||||
// ---------------------------------------------------------------------------------//
|
// ---------------------------------------------------------------------------------//
|
||||||
|
@ -331,45 +89,20 @@ class Monster extends AbstractFile
|
||||||
for (Dice d : damage)
|
for (Dice d : damage)
|
||||||
text.append (d + ", ");
|
text.append (d + ", ");
|
||||||
|
|
||||||
text.deleteCharAt (text.length () - 1);
|
if (text.length () > 0)
|
||||||
text.deleteCharAt (text.length () - 1);
|
{
|
||||||
|
text.deleteCharAt (text.length () - 1);
|
||||||
|
text.deleteCharAt (text.length () - 1);
|
||||||
|
}
|
||||||
|
|
||||||
return text.toString ();
|
return text.toString ();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------//
|
|
||||||
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 = setExperience ();
|
|
||||||
line.append (String.format (" %,6d", exp));
|
|
||||||
if (exp != experience[monsterID])
|
|
||||||
line.append (String.format (" %,6d", experience[monsterID]));
|
|
||||||
}
|
|
||||||
return line.toString ();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------//
|
|
||||||
public boolean match (int monsterID)
|
|
||||||
// ---------------------------------------------------------------------------------//
|
|
||||||
{
|
|
||||||
return this.monsterID == monsterID;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------//
|
// ---------------------------------------------------------------------------------//
|
||||||
@Override
|
@Override
|
||||||
public String toString ()
|
public String toString ()
|
||||||
// ---------------------------------------------------------------------------------//
|
// ---------------------------------------------------------------------------------//
|
||||||
{
|
{
|
||||||
return realName;
|
return name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
221
src/com/bytezone/diskbrowser/wizardry/MonsterV1.java
Executable file
221
src/com/bytezone/diskbrowser/wizardry/MonsterV1.java
Executable 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;
|
||||||
|
}
|
||||||
|
}
|
44
src/com/bytezone/diskbrowser/wizardry/MonsterV4.java
Normal file
44
src/com/bytezone/diskbrowser/wizardry/MonsterV4.java
Normal 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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
// -----------------------------------------------------------------------------------//
|
// -----------------------------------------------------------------------------------//
|
||||||
{
|
{
|
||||||
// ---------------------------------------------------------------------------------//
|
// ---------------------------------------------------------------------------------//
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -16,12 +16,12 @@ class Reward extends AbstractFile
|
||||||
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);
|
||||||
|
@ -41,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
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------//
|
// ---------------------------------------------------------------------------------//
|
||||||
|
@ -71,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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,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];
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,6 +36,7 @@ class Spell extends AbstractFile
|
||||||
// ---------------------------------------------------------------------------------//
|
// ---------------------------------------------------------------------------------//
|
||||||
{
|
{
|
||||||
super (spellName, buffer);
|
super (spellName, buffer);
|
||||||
|
|
||||||
this.spellType = type;
|
this.spellType = type;
|
||||||
this.level = level;
|
this.level = level;
|
||||||
|
|
||||||
|
@ -60,6 +62,7 @@ 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];
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------//
|
// ---------------------------------------------------------------------------------//
|
||||||
|
@ -189,24 +192,8 @@ 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", "MATU",
|
private static String[] spellNames = { "KALKI", "DIOS", "BADIOS", "MILWA", "PORFIC", "MATU",
|
||||||
|
@ -261,6 +248,13 @@ class Spell extends AbstractFile
|
||||||
SpellTarget.MONSTER_GROUP, SpellTarget.MONSTER_GROUP, SpellTarget.MONSTER, SpellTarget.PARTY,
|
SpellTarget.MONSTER_GROUP, SpellTarget.MONSTER_GROUP, SpellTarget.MONSTER, SpellTarget.PARTY,
|
||||||
SpellTarget.VARIABLE, SpellTarget.PARTY, SpellTarget.PARTY, SpellTarget.ALL_MONSTERS };
|
SpellTarget.VARIABLE, SpellTarget.PARTY, 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" + " them harder to hit.",
|
"KALKI reduces the AC of all party members by one, and thus makes" + " 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"
|
||||||
|
|
323
src/com/bytezone/diskbrowser/wizardry/WizLong.java
Normal file
323
src/com/bytezone/diskbrowser/wizardry/WizLong.java
Normal 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 ();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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 ();
|
||||||
|
@ -103,21 +102,16 @@ public class WizardryScenarioDisk extends PascalDisk
|
||||||
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), sectors);
|
extractExperienceLevels (linkNode ("Experience", "Experience string", dataNode), sectors);
|
||||||
// node = linkNode ("Spells", "Spells string", dataNode);
|
|
||||||
DefaultMutableTreeNode node = null;
|
extractSpells (sectors);
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------//
|
// ---------------------------------------------------------------------------------//
|
||||||
|
@ -127,6 +121,7 @@ public class WizardryScenarioDisk extends PascalDisk
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,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;
|
||||||
|
|
||||||
|
@ -146,6 +142,7 @@ public class WizardryScenarioDisk extends PascalDisk
|
||||||
&& !text.equals ("WIZARDRY.CODE"))
|
&& !text.equals ("WIZARDRY.CODE"))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,15 +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 (String.format ("%-15s %2d %-8s %-8s %-8s %3d", ch, (stats.ageInWeeks / 52),
|
ch.getAlignment (), ch.getRace (), ch.getType (), ch.hpMax));
|
||||||
stats.alignment, stats.race, stats.type, stats.hitsMax));
|
text.append (String.format (" %2d %2d %2d %2d %2d %2d", att[0], att[1], att[2], att[3],
|
||||||
text.append (String.format (" %2d %2d %2d %2d %2d %2d", att.strength, att.intelligence,
|
att[4], att[5]));
|
||||||
att.piety, att.vitality, att.agility, att.luck));
|
text.append (String.format (" %5s %s%n", ch.getStatus (), ch.isOut () ? "* OUT *" : ""));
|
||||||
text.append (String.format (" %5s %s%n", stats.status, ch.isOut () ? "* OUT *" : ""));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DefaultAppleFileSource afs = (DefaultAppleFileSource) node.getUserObject ();
|
DefaultAppleFileSource afs = (DefaultAppleFileSource) node.getUserObject ();
|
||||||
|
@ -277,15 +273,16 @@ public class WizardryScenarioDisk extends PascalDisk
|
||||||
{
|
{
|
||||||
int nameLength = buffer[ptr] & 0xFF;
|
int nameLength = buffer[ptr] & 0xFF;
|
||||||
if (nameLength == 0xC3)
|
if (nameLength == 0xC3)
|
||||||
continue;
|
return;
|
||||||
|
|
||||||
String name = HexFormatter.getString (buffer, ptr + 1, nameLength);
|
String name = HexFormatter.getString (buffer, ptr + 1, nameLength);
|
||||||
if ("UNSET".equals (name) && buffer[ptr + 40] == 0x07) // 7 = LOST
|
if (name.isEmpty () || ("UNSET".equals (name) && buffer[ptr + 40] == 0x07)) // 7 = LOST
|
||||||
continue;
|
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);
|
||||||
}
|
}
|
||||||
|
@ -316,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");
|
||||||
}
|
}
|
||||||
|
@ -341,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);
|
||||||
}
|
}
|
||||||
|
@ -365,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");
|
||||||
}
|
}
|
||||||
|
@ -396,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<> ();
|
||||||
|
@ -418,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++;
|
||||||
|
@ -426,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;
|
||||||
}
|
}
|
||||||
|
@ -444,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
|
||||||
|
@ -475,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
|
||||||
|
@ -555,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,7 +587,7 @@ public class WizardryScenarioDisk extends PascalDisk
|
||||||
{
|
{
|
||||||
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;
|
int count = 0;
|
||||||
|
@ -605,7 +608,7 @@ 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 (classes[count++], newBuffer);
|
ExperienceLevel el = new ExperienceLevel (classes[count++], newBuffer);
|
||||||
experiences.add (el);
|
experienceLevels.add (el);
|
||||||
addToNode (el, node, blocks, experienceSector);
|
addToNode (el, node, blocks, experienceSector);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user