Compare commits

...

47 Commits

Author SHA1 Message Date
Denis Molony 2bc330e377 tidying 2024-05-07 08:34:02 +10:00
Denis Molony 6c81bcc93b allow dos 4.5 2024-05-07 08:28:33 +10:00
Denis Molony 171fd66ba1 tidying 2024-05-02 12:38:45 +10:00
Denis Molony aa77ec1cd4 fixed catalog date display problem 2024-04-29 18:26:31 +10:00
Denis Molony 8f95988596 link to DiskBrowserApp 2024-04-06 16:33:53 +10:00
Denis Molony 8cb682f068 added C1/4100 2024-03-12 17:37:13 +10:00
Denis Molony dfc7a68580 renamed jarFolder 2023-09-30 23:55:41 +10:00
Denis Molony 4b476457d3 added ant build.xml 2023-09-28 15:27:27 +10:00
Denis Molony 3bf972a761 tidying 2023-09-16 06:51:31 +10:00
Denis Molony fd5bee6e5c tidying 2023-04-07 19:50:02 +10:00
Denis Molony 0af6714119 tidying 2023-03-16 09:00:31 +10:00
Denis Molony 22dfaf65c6 spacing 2023-03-11 16:35:48 +10:00
Denis Molony f4a6465b04 shorten absolute path 2023-02-24 12:33:21 +10:00
Denis Molony 64d5ce9ee2 allow 2img length = 0 2023-02-20 13:02:53 +10:00
Denis Molony 4e48437adc tidying 2023-02-15 20:30:34 +10:00
Denis Molony e2abdcabc9 added comment 2023-01-16 13:08:46 +10:00
Denis Molony bc0993e9d3 better pascal TEXT handling 2022-12-15 20:35:26 +10:00
Denis Molony 9fba3893ba tidying 2022-12-11 01:59:44 +10:00
Denis Molony 09c4542118 Merge branch 'master' of https://github.com/dmolony/DiskBrowser.git 2022-12-11 01:56:35 +10:00
Denis Molony af3ead0441 tidying 2022-12-11 01:54:00 +10:00
Denis Molony c12392200b
Merge pull request #24 from frankmilliron/master
Add some new equates
2022-11-27 04:53:01 +10:00
frankmilliron 794fef8610
Add some new equates 2022-11-26 10:31:06 -08:00
frankmilliron 2ec0e10c5e
Add some new equates 2022-11-26 10:27:06 -08:00
Denis Molony 668ed719fa tidying 2022-09-16 06:26:52 +10:00
Denis Molony 23b95675cf tidying 2022-08-22 16:55:32 +10:00
Denis Molony b98ecbed8d allow truncated bin2 files 2022-08-10 21:01:21 +10:00
Denis Molony 82381a6a47 fixed DateTime bug 2022-08-10 18:06:43 +10:00
Denis Molony 3f2f1bfbca stupid eclipse 2022-08-10 15:10:16 +10:00
Denis Molony a7119528a6 reorder block allocations 2022-08-10 15:08:10 +10:00
Denis Molony 6f943ae8c2 tidying 2022-07-31 10:08:15 +10:00
Denis Molony 5add6c0729 tidying 2022-07-31 09:58:00 +10:00
Denis Molony 921c946ab5 Added Squeeze format (BQY) 2022-07-31 09:21:52 +10:00
Denis Molony 898587b23b Added a formatted checkbox to the save dialog 2022-07-31 07:13:59 +10:00
Denis Molony 37c489f252 Fixed Pascal bug with invalid dates 2022-07-29 23:00:30 +10:00
Denis Molony 036e47b9b1 tidying 2022-07-09 08:13:05 +10:00
Denis Molony 250c1a9bd9 more spell code 2022-06-21 13:59:42 +10:00
Denis Molony b19e89d7cf fixed bug in known spells 2022-06-21 12:51:43 +10:00
Denis Molony d71cabb754 tidying 2022-06-17 18:24:43 +10:00
Denis Molony 848b2469ae refactoring Character 2022-06-11 15:52:58 +10:00
Denis Molony 989b1d5ab9 fixed link to WizardryApp 2022-06-10 15:59:47 +10:00
Denis Molony e0a2c50d5b fixed attributes bug 2022-06-10 15:56:48 +10:00
Denis Molony 8765299cf4 tidying 2022-06-09 16:14:52 +10:00
Denis Molony 97fe58d94d refactoring getWizLong and getSignedShort 2022-06-06 10:15:14 +10:00
Denis Molony 7d4d8c75e6 adjusted huffman decode routine 2022-06-04 13:06:20 +10:00
Denis Molony f5664a9ce9 Updated Item 2022-05-31 17:44:41 +10:00
Denis Molony 9d8cdcd67b explained wiz4 naming convention 2022-05-29 19:58:12 +10:00
Denis Molony 12b74f9d21 Wizardry IV screen 2022-05-29 19:51:19 +10:00
56 changed files with 1606 additions and 1087 deletions

4
.gitignore vendored
View File

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

View File

@ -1,5 +1,6 @@
# Apple II Disk Browser
### Alternative
There is a new release of [DiskBrowser2](https://github.com/dmolony/diskbrowser2) available.
### Features
- Cross-platform (Windows, MacOS, Linux)
- Disk formats
@ -61,7 +62,10 @@ For the truly retro look, programs can be displayed in the [original 40-column l
#### Infocom
![Infocom](resources/zork.png?raw=true "Infocom")
#### 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")
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
DiskBrowser has an inbuilt Visicalc processor which will evaluate the sheet and display the results.
![Visicalc](resources/visicalc.png?raw=true "Visicalc")

40
build.xml Normal file
View File

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

BIN
resources/wizardry4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

View File

@ -10,7 +10,7 @@ public class ApplesoftBasicProgram extends BasicProgram implements ApplesoftCons
// -----------------------------------------------------------------------------------//
{
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 AppleBasicFormatter appleBasicFormatter;

View File

@ -8,8 +8,8 @@ import com.bytezone.diskbrowser.utilities.HexFormatter;
public class BasicTextFile extends TextFile
// -----------------------------------------------------------------------------------//
{
private static String underline = "------------------------------------------"
+ "------------------------------------\n";
private static String underline =
"------------------------------------------" + "------------------------------------\n";
private static String fullUnderline = "---------- ------- " + underline;
private int recordLength; // prodos aux
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);
this.eof = eof;
recordLength = auxType;
prodosFile = true;
}
@ -42,6 +43,7 @@ public class BasicTextFile extends TextFile
this.buffers = buffers;
this.eof = eof;
recordLength = auxType;
prodosFile = true;
}
@ -167,8 +169,7 @@ public class BasicTextFile extends TextFile
if (textPreferences.showTextOffsets)
{
line = line.replaceAll ("\\n", "\n ");
text.append (
String.format ("%,10d %,8d %s%n", recNo * recordLength, recNo, line));
text.append (String.format ("%,10d %,8d %s%n", recNo * recordLength, recNo, line));
}
else
text.append (String.format ("%s%n", line));

View File

@ -16,9 +16,10 @@ import com.bytezone.diskbrowser.utilities.Utility;
public abstract class HiResImage extends AbstractFile
// -----------------------------------------------------------------------------------//
{
static final String[] auxTypes = { "Paintworks Packed SHR Image", "Packed Super Hi-Res Image",
"Super Hi-Res Image (Apple Preferred Format)", "Packed QuickDraw II PICT File",
"Packed Super Hi-Res 3200 color image", "DreamGraphix" };
static final String[] auxTypes =
{ "Paintworks Packed SHR Image", "Packed Super Hi-Res Image",
"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_OFFSET_AUX_0 = 32_256;
@ -115,7 +116,8 @@ public abstract class HiResImage extends AbstractFile
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 monochrome;
@ -275,8 +277,8 @@ public abstract class HiResImage extends AbstractFile
{
String auxText = "";
StringBuilder text = new StringBuilder ();
text.append (String.format ("Image File : %s%nFile type : $%02X %s%n", name, fileType,
ProdosConstants.fileTypes[fileType]));
text.append (String.format ("Image File : %s%nFile type : $%02X %s%n", name,
fileType, ProdosConstants.fileTypes[fileType]));
switch (fileType)
{
@ -393,7 +395,8 @@ public abstract class HiResImage extends AbstractFile
{
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;
}
@ -462,12 +465,13 @@ public abstract class HiResImage extends AbstractFile
int type = (buffer[ptr] & 0xC0) >>> 6; // 0-3
int count = (buffer[ptr++] & 0x3F) + 1; // 1-64
text.append (String.format ("%04X/%04d: %02X (%d,%2d) ", ptr - 1, size, buffer[ptr - 1],
type, count));
text.append (String.format ("%04X/%04d: %02X (%d,%2d) ", ptr - 1, size,
buffer[ptr - 1], type, count));
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;
size += count;
}
@ -651,8 +655,8 @@ public abstract class HiResImage extends AbstractFile
if (buffer.length < 4)
return false;
return buffer[0] == (byte) 0xC1 && buffer[1] == (byte) 0xD0 && buffer[2] == (byte) 0xD0
&& buffer[3] == 0;
return buffer[0] == (byte) 0xC1 && buffer[1] == (byte) 0xD0
&& buffer[2] == (byte) 0xD0 && buffer[3] == 0;
}
// ---------------------------------------------------------------------------------//

View File

@ -4,6 +4,8 @@ package com.bytezone.diskbrowser.applefile;
public class PascalText extends TextFile
// -----------------------------------------------------------------------------------//
{
private final static int PAGE_SIZE = 1024;
// ---------------------------------------------------------------------------------//
public PascalText (String name, byte[] buffer)
// ---------------------------------------------------------------------------------//
@ -16,28 +18,34 @@ public class PascalText extends TextFile
public String getText ()
// ---------------------------------------------------------------------------------//
{
// Text files are broken up into 1024-byte pages.
// [DLE] [indent] [text] [CR] ... [nulls]
StringBuilder text = new StringBuilder (getHeader ());
int ptr = 0x400;
int ptr = PAGE_SIZE; // skip text editor header
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;
}
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)
text.append (" ");
ptr += 2;
}
String line = getLine (ptr);
text.append (line + "\n");
ptr += line.length () + 1;
while (buffer[ptr] != 0x0D)
text.append ((char) buffer[ptr++]);
text.append ("\n");
ptr++;
}
if (text.length () > 0)
@ -45,16 +53,4 @@ public class PascalText extends TextFile
return text.toString ();
}
// ---------------------------------------------------------------------------------//
private String getLine (int ptr)
// ---------------------------------------------------------------------------------//
{
StringBuilder line = new StringBuilder ();
while (buffer[ptr] != 0x0D)
line.append ((char) buffer[ptr++]);
return line.toString ();
}
}

View File

@ -3,6 +3,7 @@ package com.bytezone.diskbrowser.applefile;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Locale;
import com.bytezone.diskbrowser.disk.FormattedDisk;
import com.bytezone.diskbrowser.prodos.DirectoryHeader;
@ -15,7 +16,8 @@ import com.bytezone.diskbrowser.utilities.Utility;
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 String UNDERLINE =
"----------------------------------------------------\n";
@ -86,7 +88,6 @@ public class ProdosDirectory extends AbstractFile implements ProdosConstants
int nameLength = buffer[i] & 0x0F;
String filename = HexFormatter.getString (buffer, i + 1, nameLength);
String subType = "";
String locked;
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 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)
{
case FILE_TYPE_TEXT:
int aux = Utility.getShort (buffer, i + 31);
subType = String.format ("R=%5d", aux);
break;
@ -134,14 +135,13 @@ public class ProdosDirectory extends AbstractFile implements ProdosConstants
case FILE_TYPE_PNT:
case FILE_TYPE_PIC:
case FILE_TYPE_FOT:
aux = Utility.getShort (buffer, i + 31);
subType = String.format ("A=$%4X", aux);
break;
case FILE_TYPE_AWP:
aux = Utility.intValue (buffer[i + 32], buffer[i + 31]); // backwards!
if (aux != 0)
filename = convert (filename, aux);
int flags = Utility.intValue (buffer[i + 32], buffer[i + 31]); // aux backwards!
if (flags != 0)
filename = convert (filename, flags);
break;
default:
@ -149,9 +149,10 @@ public class ProdosDirectory extends AbstractFile implements ProdosConstants
}
String forkFlag = storageType == 5 ? "+" : " ";
text.append (String.format ("%s%-15s %3s%s %5d %9s %5s %9s %5s %8d %7s%n",
locked, filename, ProdosConstants.fileTypes[type], forkFlag, blocks, dateM,
timeM, dateC, timeC, eof, subType));
text.append (
String.format ("%s%-15s %3s%s %5d %9s %5s %9s %5s %8d %7s %04X%n",
locked, filename, ProdosConstants.fileTypes[type], forkFlag, blocks,
dateM, timeM, dateC, timeC, eof, subType, aux));
break;
default:

View File

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

View File

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

View File

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

View File

@ -22,10 +22,19 @@
0035 YSAV1
0036 CSWL
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
004F RND-HI
0050 LINNUM
0050 LINNUM line number, unsigned word
0067 Basic program address LO
0068 Basic program address HI
0069 Basic variables address LO
@ -52,8 +61,48 @@
0200 Input buffer
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
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
C00B SLOTC3ROMON Enable slot ROM from $C300-$C3FF
C000 KYBD - last key pressed
C010 STROBE - Clear KYBD
C000 KBD - Last key pressed
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
C051 TXTSET - Display Text
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
C056 LORES - Display LoRes 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
C081 ROMIN - Read ROM; write RAM bank 2
@ -96,6 +158,9 @@ C08D Read ROM; write RAM bank 1
C08E Read ROM; no write
C08F Read/write RAM bank 1
C600 BOOT0 - Disk II controller ROM
0801 BOOT1 - Disk II bootstrap RAM
D52C INLIN numeric input
DB3A STROUT - output a string
DB5C output a character
@ -106,6 +171,7 @@ DEC0 SYNCHR
DEC9 syntax error
DFE3 PTRGET
E000 Applesoft BASIC entry
E053 find a variable
E10C convert FP to INT
E2F2 GIVAYF - convert (A,Y) to FP
@ -177,15 +243,16 @@ F941 PRINTAX - print AX registers in hex
F948 PRBLNK - print 3 spaces
F94A PRBL2 - print X blank spaces
FAA6 reboot DOS
FAA6 PWRUP - reboot
FAFF 0 = Autostart ROM, 1 = Old Monitor
FB1E PREAD - read game paddle
FB2F initialise text screen
FB2F INIT - initialise text screen
FB39 text mode - SETTXT
FB40 SETGR
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
FBDD BELL1 - beep speaker
FBF4 CURSRIT - move cursor right
@ -193,6 +260,7 @@ FBF4 CURSRIT - move cursor right
FC10 CURSLFT - move cursor left
FC1A CURSUP - move cursor up
FC22 VTAB
FC24 VTABZ
FC42 CLREOP - clear to end of page
FC58 HOME - clear screen
FC62 CR
@ -215,12 +283,13 @@ FDE3 PRHEX - print a hex digit
FDED COUT - print a character (in Acc)
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
FE84 SETNORM - set normal mode
FE89 disconnect DOS from I/O links
FE89 SETKBD - disconnect DOS from I/O links
FE8B INPORT
FE93 disconnect DOS from I/O links
FE93 SETVID - disconnect DOS from I/O links
FE95 OUTPORT
FECD WRITE
FEFD READ
@ -231,6 +300,14 @@ FF3A BELL
FF3F IOREST - restore all registers
FF4A IOSAVE - save all registers
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
FFC7 ZMODE - monitor get ASCII return
FFFA NMI_VECTOR
FFFB NMI_VECTOR
FFFC RESET_VECTOR
FFFD RESET_VECTOR
FFFE IRQ_VECTOR
FFFF IRQ_VECTOR

View File

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

View File

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

View File

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

View File

@ -733,12 +733,8 @@ public class AppleDisk implements Disk
{
StringBuilder text = new StringBuilder ();
String path = file.getAbsolutePath ();
String home = System.getProperty ("user.home");
if (path.startsWith (home))
path = "~" + path.substring (home.length ());
text.append (String.format ("Path ......... %s%n", path));
text.append (
String.format ("Path ......... %s%n", Utility.getShortPath (file.getAbsolutePath ())));
text.append (String.format ("File name .... %s%n", file.getName ()));
text.append (String.format ("File size .... %,d%n", file.length ()));
text.append (String.format ("Tracks ....... %d%n", tracks));

View File

@ -148,7 +148,7 @@ public class DiskFactory
if ("sdk".equals (suffix) // NuFX disk
|| "shk".equals (suffix) // NuFX files or disk
|| "bxy".equals (suffix)) // NuFX in Binary2
|| "bxy".equals (suffix)) // NuFX in Bin2
{
if (debug)
System.out.println (" ** sdk/shk/bxy **");
@ -156,7 +156,11 @@ public class DiskFactory
{
nuFX = new NuFX (file.toPath ());
if (nuFX.getTotalDisks () == 0 && nuFX.getTotalFiles () == 0)
{
if (debug)
System.out.println ("Empty NuFX file");
return null;
}
byte[] diskBuffer = nuFX.getDiskBuffer ();
if (diskBuffer == null)
@ -173,7 +177,7 @@ public class DiskFactory
}
catch (Exception e)
{
// e.printStackTrace ();
// e.printStackTrace ();
if (e.getMessage () == null)
System.out.println (e);
else
@ -183,10 +187,10 @@ public class DiskFactory
return null;
}
}
else if ("bny".equals (suffix)) // Binary2 uncompressed files
else if ("bny".equals (suffix) || "bqy".equals (suffix)) // Binary2 uncompressed files
{
if (debug)
System.out.println (" ** bny **");
System.out.println (" ** bny/bqy **");
try
{
binary2 = new Binary2 (file.toPath ());
@ -414,7 +418,8 @@ public class DiskFactory
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;
}
@ -574,8 +579,8 @@ public class DiskFactory
disk = new DataDisk (appleDisk256);
if (debug)
System.out
.println ("Factory creating disk : " + disk.getDisk ().getFile ().getAbsolutePath ());
System.out.println (
"Factory creating disk : " + disk.getDisk ().getFile ().getAbsolutePath ());
if (disk != null && compressed)
disk.setOriginalPath (originalPath);

View File

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

View File

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

View File

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

View File

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

View File

@ -36,6 +36,7 @@ public class FontAction extends DefaultAction implements QuitListener
{
super ("Set Font...", "Set display to a different font or font size",
"/com/bytezone/loadlister/");
int mask = Toolkit.getDefaultToolkit ().getMenuShortcutKeyMaskEx ();
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);
FontChangeListener[] listeners =
(listenerList.getListeners (FontChangeListener.class));
FontChangeListener[] listeners = (listenerList.getListeners (FontChangeListener.class));
for (FontChangeListener listener : listeners)
listener.changeFont (fontChangeEvent);
}

View File

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

View File

@ -1,9 +1,15 @@
package com.bytezone.diskbrowser.gui;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.io.File;
import javax.swing.Action;
import javax.swing.JCheckBox;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.KeyStroke;
import com.bytezone.diskbrowser.applefile.AppleFileSource;
@ -12,12 +18,17 @@ class SaveFileAction extends AbstractSaveAction implements FileSelectionListener
//-----------------------------------------------------------------------------------//
{
AppleFileSource appleFileSource;
private JCheckBox formatted = new JCheckBox ("Formatted");
// ---------------------------------------------------------------------------------//
SaveFileAction ()
// ---------------------------------------------------------------------------------//
{
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;
}
setSelectedFile (new File (appleFileSource.getUniqueName () + ".bin"));
saveBuffer (appleFileSource.getDataSource ().getBuffer ());
if (formatted.isSelected ())
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;
setEnabled (
event.appleFileSource != null && event.appleFileSource.getDataSource () != null
&& event.appleFileSource.getDataSource ().getBuffer () != null);
setEnabled (appleFileSource != null && appleFileSource.getDataSource () != null
&& appleFileSource.getDataSource ().getBuffer () != null);
}
}

View File

@ -4,6 +4,7 @@ import java.awt.event.ActionEvent;
import java.io.File;
import java.util.List;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
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);
setSelectedFile (new File ("SavedSectors.bin"));
saveBuffer (buffer);
if (fileChooser.showSaveDialog (null) == JFileChooser.APPROVE_OPTION)
saveBuffer (buffer);
}
// ---------------------------------------------------------------------------------//

View File

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

View File

@ -14,10 +14,9 @@ public class Binary2Header
// -----------------------------------------------------------------------------------//
{
static DateTimeFormatter formatter = DateTimeFormatter.ofPattern ("dd-LLL-yy HH:mm");
static String[] osTypes =
{ "Prodos", "DOS 3.3", "Reserved", "DOS 3.2 or 3.1", "Pascal", "Macintosh MFS",
"Macintosh HFS", "Lisa", "CPM", "Reserved", "MS-DOS", "High Sierra (CD-ROM)",
"ISO 9660 (CD-ROM)", "AppleShare" };
static String[] osTypes = { "Prodos", "DOS 3.3", "Reserved", "DOS 3.2 or 3.1", "Pascal",
"Macintosh MFS", "Macintosh HFS", "Lisa", "CPM", "Reserved", "MS-DOS", "High Sierra (CD-ROM)",
"ISO 9660 (CD-ROM)", "AppleShare" };
int ptr;
byte[] buffer;
@ -89,8 +88,8 @@ public class Binary2Header
public String getLine ()
// ---------------------------------------------------------------------------------//
{
return String.format (" %-33s %3s $%04X %s unc %7d", fileName,
fileTypes[fileType], auxType, modified.format (formatter), eof);
return String.format (" %-33s %3s $%04X %s unc %7d", fileName, fileTypes[fileType],
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 total blocks ... %02X%n", prodos16totalBlocks));
text.append (String.format ("Prodos eof ............ %06X %<,d%n", prodos16eof));
text.append (
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 ("Disk space needed ..... %08X %<,d%n", diskSpaceRequired));
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 ("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 ("Following files ....... %02X%n", filesToFollow));

View File

@ -9,8 +9,7 @@ import com.bytezone.diskbrowser.utilities.Utility;
public class MasterHeader
// -----------------------------------------------------------------------------------//
{
private static final byte[] NuFile =
{ 0x4E, (byte) 0xF5, 0x46, (byte) 0xE9, 0x6C, (byte) 0xE5 };
private static final byte[] NuFile = { 0x4E, (byte) 0xF5, 0x46, (byte) 0xE9, 0x6C, (byte) 0xE5 };
private static final byte[] BIN2 = { 0x0A, 0x47, 0x4C };
private final int crc;
@ -35,15 +34,6 @@ public class MasterHeader
if (Utility.isMagic (buffer, ptr, NuFile))
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))
{
binary2Header = new Binary2Header (buffer, 0);

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,6 @@
package com.bytezone.diskbrowser.pascal;
import java.awt.Color;
import java.text.DateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
@ -30,8 +29,8 @@ public class PascalDisk extends AbstractFormattedDisk
// -----------------------------------------------------------------------------------//
{
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 DateTimeFormatter dtf =
DateTimeFormatter.ofLocalizedDate (FormatStyle.SHORT);
private final VolumeEntry volumeEntry;
private final PascalCatalogSector diskCatalogSector;
@ -50,8 +49,8 @@ public class PascalDisk extends AbstractFormattedDisk
SectorType fotoSector = new SectorType ("Foto", Color.gray);
SectorType badSector = new SectorType ("Bad", Color.darkGray);
SectorType[] sectors = { catalogSector, badSector, codeSector, textSector, infoSector, dataSector,
grafSector, fotoSector };
SectorType[] sectors = { catalogSector, badSector, codeSector, textSector, infoSector,
dataSector, grafSector, fotoSector };
// ---------------------------------------------------------------------------------//
public PascalDisk (Disk disk)
@ -102,7 +101,8 @@ public class PascalDisk extends AbstractFormattedDisk
freeBlocks.set (i, false);
}
diskCatalogSector = new PascalCatalogSector (disk, disk.readBlocks (sectors), sectors);
diskCatalogSector =
new PascalCatalogSector (disk, disk.readBlocks (sectors), sectors);
// read the catalog
List<DiskAddress> addresses = new ArrayList<> ();
@ -235,7 +235,6 @@ public class PascalDisk extends AbstractFormattedDisk
}
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));
@ -300,16 +299,18 @@ public class PascalDisk extends AbstractFormattedDisk
{
String newLine = String.format ("%n");
String newLine2 = newLine + newLine;
String line =
"---- --------------- ---- -------- ------- ---- ---- ----" + newLine;
String line = "---- --------------- ---- -------- ------- ---- ---- ----"
+ newLine;
String date = volumeEntry.localDate == null ? "--" : volumeEntry.localDate.format (dtf);
String date =
volumeEntry.localDate == null ? "--" : volumeEntry.localDate.format (dtf);
StringBuilder text = new StringBuilder ();
text.append ("File : " + getDisplayPath () + newLine2);
text.append ("Volume : " + volumeEntry.name + newLine);
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);
int usedBlocks = 6;
@ -322,15 +323,16 @@ public class PascalDisk extends AbstractFormattedDisk
date = ce.localDate == null ? "--" : ce.localDate.format (dtf);
int bytes = (size - 1) * 512 + ce.bytesUsedInLastBlock;
String fileType =
ce.fileType < 0 || ce.fileType >= fileTypes.length ? "????" : fileTypes[ce.fileType];
text.append (String.format ("%4d %-15s %-6s %8s %,8d $%03X $%03X $%03X%n", size,
ce.name, fileType, date, bytes, ce.firstBlock, ce.lastBlock, size));
String fileType = ce.fileType < 0 || ce.fileType >= fileTypes.length ? "????"
: fileTypes[ce.fileType];
text.append (String.format ("%4d %-15s %-6s %8s %,8d $%03X $%03X $%03X%n",
size, ce.name, fileType, date, bytes, ce.firstBlock, ce.lastBlock, size));
}
text.append (line);
text.append (String.format ("Blocks free : %3d Blocks used : %3d Total blocks : %3d%n",
(volumeEntry.totalBlocks - usedBlocks), usedBlocks, volumeEntry.totalBlocks));
text.append (
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);
}

View File

@ -16,7 +16,7 @@ abstract class CatalogEntry implements AppleFileSource
// -----------------------------------------------------------------------------------//
{
static String[] storageTypes = { "Del", "Sdl", "Sap", "Tre", "Pas", "Ext", "", "", "",
"", "", "", "", "DIR", "SDH", "VDH" };
"", "", "", "", "DIR", "SDH", "VDH" };
Disk disk;
ProdosDisk parentDisk;
@ -111,6 +111,7 @@ abstract class CatalogEntry implements AppleFileSource
StringBuilder text = new StringBuilder ();
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 ("Created ....... %s%n",
created == null ? "" : created.format (ProdosDisk.df)));

View File

@ -72,8 +72,8 @@ class FileEntry extends CatalogEntry implements ProdosConstants
private FileEntry link;
// ---------------------------------------------------------------------------------//
FileEntry (ProdosDisk fDisk, byte[] entryBuffer, DirectoryHeader parent, int parentBlock,
int entryNo)
FileEntry (ProdosDisk fDisk, byte[] entryBuffer, DirectoryHeader parent,
int parentBlock, int entryNo)
// ---------------------------------------------------------------------------------//
{
super (fDisk, entryBuffer, parentBlock, entryNo);
@ -143,7 +143,8 @@ class FileEntry extends CatalogEntry implements ProdosConstants
{
int storageType = buffer2[i] & 0x0F;
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)
addDataBlocks (storageType, keyBlock, dataBlocks);
@ -162,40 +163,40 @@ class FileEntry extends CatalogEntry implements ProdosConstants
// ---------------------------------------------------------------------------------//
{
DiskAddress emptyDiskAddress = disk.getDiskAddress (0);
List<Integer> blocks = new ArrayList<> ();
List<Integer> blockNos = new ArrayList<> ();
switch (storageType)
{
case SEEDLING:
if (isValid (keyPtr))
blocks.add (keyPtr);
blockNos.add (keyPtr);
break;
case SAPLING:
if (isValid (keyPtr))
blocks.addAll (readIndex (keyPtr));
blockNos.addAll (readIndex (keyPtr));
break;
case TREE:
if (isValid (keyPtr))
for (Integer indexBlock : readMasterIndex (keyPtr))
if (isValid (indexBlock))
blocks.addAll (readIndex (indexBlock));
blockNos.addAll (readIndex (indexBlock));
break;
}
// remove trailing empty blocks
while (blocks.size () > 0 && blocks.get (blocks.size () - 1) == 0)
blocks.remove (blocks.size () - 1);
while (blockNos.size () > 0 && blockNos.get (blockNos.size () - 1) == 0)
blockNos.remove (blockNos.size () - 1);
for (Integer block : blocks)
for (Integer blockNo : blockNos)
{
if (block == 0)
if (blockNo == 0)
dataBlocks.add (emptyDiskAddress);
else
{
parentDisk.setSectorType (block, parentDisk.dataSector);
dataBlocks.add (disk.getDiskAddress (block));
parentDisk.setSectorType (blockNo, parentDisk.dataSector);
dataBlocks.add (disk.getDiskAddress (blockNo));
}
}
}
@ -349,7 +350,8 @@ class FileEntry extends CatalogEntry implements ProdosConstants
file = new DoubleHiResImage (name, outBuffer);
break;
case 0x8000:
file = new SHRPictureFile2 (name, outBuffer, FILE_TYPE_PIC, 0x2000, 0x8000);
file =
new SHRPictureFile2 (name, outBuffer, FILE_TYPE_PIC, 0x2000, 0x8000);
break;
default:
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
// file = new SHRPictureFile2 (name, exactBuffer, fileType, auxType, endOfFile);
else if ((name.equals ("DOS.3.3") || name.equals ("DDOS.3.3")) && endOfFile == 0x2800
&& DosMasterFile.isDos33 (parentDisk, exactBuffer))
else if ((name.equals ("DOS.3.3") || name.equals ("DDOS.3.3"))
&& endOfFile == 0x2800 && DosMasterFile.isDos33 (parentDisk, exactBuffer))
{
file = new DosMasterFile (name, exactBuffer);
}
@ -413,8 +415,8 @@ class FileEntry extends CatalogEntry implements ProdosConstants
case FILE_TYPE_DIRECTORY:
VolumeDirectoryHeader vdh = parentDisk.getVolumeDirectoryHeader ();
file = new ProdosDirectory (parentDisk, name, buffer, vdh.totalBlocks, vdh.freeBlocks,
vdh.usedBlocks);
file = new ProdosDirectory (parentDisk, name, buffer, vdh.totalBlocks,
vdh.freeBlocks, vdh.usedBlocks);
break;
case FILE_TYPE_APPLESOFT_BASIC_VARS:
@ -547,6 +549,8 @@ class FileEntry extends CatalogEntry implements ProdosConstants
case FILE_TYPE_NON:
if (name.endsWith (".TIFF") && HiResImage.isTiff (exactBuffer))
file = new OriginalHiResImage (name, exactBuffer, auxType);
else if (name.endsWith (".JAVA"))
file = new BasicTextFile (name, exactBuffer, auxType, endOfFile);
else
file = new DefaultAppleFile (name, exactBuffer);
break;
@ -623,7 +627,8 @@ class FileEntry extends CatalogEntry implements ProdosConstants
if (addresses.size () > 0)
{
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 ();
}
logicalBlock += 256;
@ -723,8 +728,8 @@ class FileEntry extends CatalogEntry implements ProdosConstants
}
// ---------------------------------------------------------------------------------//
private int readIndexBlock (int indexBlock, List<DiskAddress> addresses, List<TextBuffer> buffers,
int logicalBlock)
private int readIndexBlock (int indexBlock, List<DiskAddress> addresses,
List<TextBuffer> buffers, int logicalBlock)
// ---------------------------------------------------------------------------------//
{
byte[] indexBuffer = disk.readBlock (indexBlock);
@ -736,7 +741,8 @@ class FileEntry extends CatalogEntry implements ProdosConstants
else if (addresses.size () > 0)
{
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 ();
}
logicalBlock++;
@ -807,13 +813,14 @@ class FileEntry extends CatalogEntry implements ProdosConstants
String locked = (access == 0x00) ? "*" : " ";
if (true)
return String.format ("%s %03d %s", ProdosConstants.fileTypes[fileType], blocksUsed, locked)
+ name;
return String.format ("%s %03d %s", ProdosConstants.fileTypes[fileType],
blocksUsed, locked) + name;
String timeC = created == null ? "" : created.format (ProdosDisk.df);
String timeF = modified == null ? "" : modified.format (ProdosDisk.df);
return String.format ("%s %s%-30s %3d %,10d %15s %15s", ProdosConstants.fileTypes[fileType],
locked, parentDirectory.name + "/" + name, blocksUsed, endOfFile, timeC, timeF);
return String.format ("%s %s%-30s %3d %,10d %15s %15s",
ProdosConstants.fileTypes[fileType], locked, parentDirectory.name + "/" + name,
blocksUsed, endOfFile, timeC, timeF);
}
}

View File

@ -7,6 +7,7 @@ import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
@ -31,7 +32,8 @@ public class ProdosDisk extends AbstractFormattedDisk
{
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");
final SectorType dosSector = new SectorType ("Bootstrap Loader", Color.lightGray);

View File

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

View File

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

View File

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

View File

@ -40,14 +40,13 @@ public final class Utility
private static MathContext mathContext4 = new MathContext (6);
private static MathContext mathContext8 = new MathContext (15);
private static final List<String> suffixes = Arrays.asList ("po", "dsk", "do", "hdv", "2mg",
"d13", "sdk", "shk", "bxy", "bny", "woz", "img", "dimg");
private static final List<String> suffixes = Arrays.asList ("po", "dsk", "do", "hdv",
"2mg", "d13", "sdk", "shk", "bxy", "bny", "bqy", "woz", "img", "dimg");
// ---------------------------------------------------------------------------------//
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
@ -256,7 +255,8 @@ public final class Utility
}
catch (DateTimeException e)
{
System.out.printf ("Bad date/time: %d %d %d %d %d %n", year, month, day, hour, minute);
System.out.printf ("Bad date/time: %d %d %d %d %d %n", year, month, day, hour,
minute);
}
}
@ -316,7 +316,8 @@ public final class Utility
public static int readTriple (byte[] buffer, int ptr)
// ---------------------------------------------------------------------------------//
{
return (buffer[ptr] & 0xFF) | (buffer[ptr + 1] & 0xFF) << 8 | (buffer[ptr + 2] & 0xFF) << 16;
return (buffer[ptr] & 0xFF) | (buffer[ptr + 1] & 0xFF) << 8
| (buffer[ptr + 2] & 0xFF) << 16;
}
// ---------------------------------------------------------------------------------//
@ -385,8 +386,8 @@ public final class Utility
if (exponent == 0)
return 0.0;
int mantissa =
(buffer[ptr + 2] & 0x7F) << 16 | (buffer[ptr + 1] & 0xFF) << 8 | (buffer[ptr] & 0xFF);
int mantissa = (buffer[ptr + 2] & 0x7F) << 16 | (buffer[ptr + 1] & 0xFF) << 8
| (buffer[ptr] & 0xFF);
boolean negative = (buffer[ptr + 2] & 0x80) != 0;
double value = 0.5;
@ -409,9 +410,10 @@ public final class Utility
if (exponent == 0)
return 0.0;
long mantissa = (long) (buffer[ptr + 6] & 0x7F) << 48 | (long) (buffer[ptr + 5] & 0xFF) << 40
| (long) (buffer[ptr + 4] & 0xFF) << 32 | (long) (buffer[ptr + 3] & 0xFF) << 24
| (buffer[ptr + 2] & 0xFF) << 16 | (buffer[ptr + 1] & 0xFF) << 8 | (buffer[ptr] & 0xFF);
long mantissa = (long) (buffer[ptr + 6] & 0x7F) << 48
| (long) (buffer[ptr + 5] & 0xFF) << 40 | (long) (buffer[ptr + 4] & 0xFF) << 32
| (long) (buffer[ptr + 3] & 0xFF) << 24 | (buffer[ptr + 2] & 0xFF) << 16
| (buffer[ptr + 1] & 0xFF) << 8 | (buffer[ptr] & 0xFF);
boolean negative = (buffer[ptr + 6] & 0x80) != 0;
double value = 0.5;
@ -445,7 +447,38 @@ public final class Utility
else
year += 1900;
return LocalDate.of (year, month, 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;
}
// ---------------------------------------------------------------------------------//
@ -490,11 +523,13 @@ public final class Utility
int[] val = new int[6];
for (int i = 0; i < 6; i++)
val[i] = Integer.parseInt (String.format ("%02X", buffer[ptr + i] & 0xFF));
// val[i] = buffer[ptr + i] & 0xFF;
LocalDateTime date = LocalDateTime.of (val[3] + 2000, val[5], val[4], val[2], val[1], val[0]);
LocalDateTime date =
LocalDateTime.of (val[3] + 2000, val[5], val[4], val[2], val[1], val[0]);
return date;
}
catch (DateTimeException | NumberFormatException e)
catch (DateTimeException e)
{
return null;
}
@ -534,6 +569,23 @@ public final class Utility
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)
// ---------------------------------------------------------------------------------//
@ -582,7 +634,8 @@ public final class Utility
public static boolean isPossibleVariable (byte value)
// ---------------------------------------------------------------------------------//
{
return isDigit (value) || isLetter (value) || value == ASCII_DOLLAR || value == ASCII_PERCENT;
return isDigit (value) || isLetter (value) || value == ASCII_DOLLAR
|| value == ASCII_PERCENT;
}
// ---------------------------------------------------------------------------------//
@ -662,41 +715,42 @@ public final class Utility
return ~crc; // one's complement
}
static int[] crc32_tab = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b,
0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a,
0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e,
0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa,
0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11,
0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589,
0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8,
0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158,
0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f,
0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3,
0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e,
0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2,
0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76,
0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd,
0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795,
0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14,
0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4,
0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3,
0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53,
0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02,
0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d };
static int[] crc32_tab = { //
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535,
0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd,
0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d,
0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac,
0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab,
0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb,
0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea,
0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce,
0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409,
0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739,
0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268,
0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0,
0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8,
0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703,
0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7,
0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae,
0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6,
0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d,
0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5,
0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d };
}

View File

@ -1,24 +1,122 @@
package com.bytezone.diskbrowser.wizardry;
import com.bytezone.diskbrowser.applefile.AbstractFile;
import com.bytezone.diskbrowser.utilities.Utility;
// -----------------------------------------------------------------------------------//
public abstract class Character extends AbstractFile
// -----------------------------------------------------------------------------------//
{
static int MAGE_SPELLS = 0;
static int PRIEST_SPELLS = 1;
static String[] races = { "No race", "Human", "Elf", "Dwarf", "Gnome", "Hobbit" };
static String[] alignments = { "Unalign", "Good", "Neutral", "Evil" };
static String[] types =
{ "Fighter", "Mage", "Priest", "Thief", "Bishop", "Samurai", "Lord", "Ninja" };
static String[] statuses =
{ "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)
// ---------------------------------------------------------------------------------//
{
super (name, buffer);
}
// ---------------------------------------------------------------------------------//
void get3x5Bits (int[] attributes, int ptr, int value)
// ---------------------------------------------------------------------------------//
{
attributes[ptr] = value & 0x001F;
attributes[ptr + 1] = (value & 0x03E0) >>> 5;
attributes[ptr + 2] = (value & 0x7C00) >>> 10;
}
// ---------------------------------------------------------------------------------//
void get2x5Bits (int[] attributes, int ptr, int value)
// ---------------------------------------------------------------------------------//
{
attributes[ptr] = value & 0x001F;
attributes[ptr + 1] = (value & 0x03E0) >>> 5;
}
// ---------------------------------------------------------------------------------//
protected void checkKnownSpells (byte[] buffer, int ptr)
// ---------------------------------------------------------------------------------//
{
for (int i = 0; i < 7; i++)
{
spellAllowance[MAGE_SPELLS][i] = Utility.getShort (buffer, ptr + 8 + i * 2);
spellAllowance[PRIEST_SPELLS][i] = Utility.getShort (buffer, ptr + 22 + i * 2);
}
int bit = 1; // skip first bit
int val = buffer[ptr];
mysteryBit = (val & 0x01) == 1;
for (int i = 0; i < spellsKnown.length; i++)
{
if (bit == 8)
{
val = buffer[++ptr];
bit = 0;
}
spellsKnown[i] = ((val >>> bit++) & 0x01) != 0;
}
}
// ---------------------------------------------------------------------------------//
public String getAwardString ()
// ---------------------------------------------------------------------------------//
{
StringBuilder text = new StringBuilder ();
int awards = Utility.getShort (buffer, 206);
for (int i = 0; i < 16; i++)
{
if ((awards & 0x01) != 0)
text.append (awardsText[i]);
awards >>>= 1;
}
return text.toString ();
}
}

View File

@ -10,13 +10,25 @@ import com.bytezone.diskbrowser.utilities.Utility;
class CharacterV1 extends Character
// -----------------------------------------------------------------------------------//
{
private static char[] awardsText = ">!$#&*<?BCPKODG@".toCharArray ();
private String race;
private String type;
private String alignment;
private String status;
private final Attributes attributes;
private final Statistics stats;
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<Baggage> baggageList = new ArrayList<> ();
private final List<Possession> possessions = new ArrayList<> ();
// ---------------------------------------------------------------------------------//
CharacterV1 (String name, byte[] buffer, int scenario)
@ -26,100 +38,67 @@ class CharacterV1 extends Character
this.scenario = scenario;
attributes = new Attributes ();
stats = new Statistics ();
inMaze = Utility.getShort (buffer, 32) != 0;
race = races[buffer[34] & 0xFF];
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];
typeInt = buffer[36] & 0xFF;
type = types[typeInt];
stats.gold = Utility.getShort (buffer, 52) + Utility.getShort (buffer, 54) * 10000
+ Utility.getShort (buffer, 56) * 100000000L;
stats.experience = Utility.getShort (buffer, 124) + Utility.getShort (buffer, 126) * 10000;
stats.level = Utility.getShort (buffer, 132);
ageInWeeks = Utility.getShort (buffer, 38);
stats.hitsLeft = Utility.getShort (buffer, 134);
stats.hitsMax = Utility.getShort (buffer, 136);
statusInt = buffer[40];
status = statuses[statusInt];
stats.armourClass = buffer[176];
alignment = alignments[buffer[42] & 0xFF];
attributes.strength = (buffer[44] & 0xFF) % 16;
if (attributes.strength < 3)
attributes.strength += 16;
attributes.array[0] = attributes.strength;
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));
int i1 = (buffer[44] & 0xFF) / 16;
int i2 = (buffer[45] & 0xFF) % 4;
attributes.intelligence = i1 / 2 + i2 * 8;
attributes.array[1] = attributes.intelligence;
gold = Utility.getWizLong (buffer, 52);
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)
// ---------------------------------------------------------------------------------//
{
boolean equipped;
boolean identified;
int totItems = buffer[58];
stats.assetValue = 0;
for (int ptr = 60; totItems > 0; ptr += 8, totItems--)
possessionsCount = Utility.getShort (buffer, 58);
for (int i = 0; i < possessionsCount; i++)
{
int itemID = buffer[ptr + 6] & 0xFF;
if (scenario == 3)
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));
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 linkSpells (List<Spell> spellList)
public void link (List<ItemV1> itemList, List<Spell> spellList,
List<ExperienceLevel> experienceLevels)
// ---------------------------------------------------------------------------------//
{
int index = 0;
for (int i = 138; i < 145; i++)
for (int bit = 0; bit < 8; bit++)
{
if (((buffer[i] >>> bit) & 0x01) != 0)
{
spellBook.add (spellList.get (index));
// System.out.println (spellList.get (index));
}
for (Possession baggage : possessions)
{
baggage.item = itemList.get (baggage.itemId);
assetValue += baggage.item.getCost ();
}
if (++index >= spellList.size ())
break;
}
for (int i = 0; i < spellsKnown.length; i++)
if (spellsKnown[i])
spellBook.add (spellList.get (i));
nextLevel = experienceLevels.get (typeInt).getExperiencePoints (characterLevel + 1);
}
// ---------------------------------------------------------------------------------//
@ -129,158 +108,105 @@ class CharacterV1 extends Character
{
StringBuilder text = new StringBuilder ();
text.append ("Character name ..... " + getName ());
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 (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.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);
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]);
int[] spellPoints = getMageSpellPoints ();
text.append ("\n\nMage spell points ..");
for (int i = 0; i < spellPoints.length; i++)
text.append (" " + spellPoints[i]);
for (int i = 0; i < spellAllowance[MAGE_SPELLS].length; i++)
text.append (" " + spellAllowance[MAGE_SPELLS][i]);
spellPoints = getPriestSpellPoints ();
text.append ("\nPriest spell points ");
for (int i = 0; i < spellPoints.length; i++)
text.append (" " + spellPoints[i]);
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 (Baggage b : baggageList)
for (Possession b : possessions)
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;
}
// ---------------------------------------------------------------------------------//
public String getAwardString ()
// ---------------------------------------------------------------------------------//
{
StringBuilder text = new StringBuilder ();
int awards = Utility.getShort (buffer, 206);
for (int i = 0; i < 16; i++)
{
if ((awards & 0x01) != 0)
text.append (awardsText[i]);
awards >>>= 1;
}
return text.toString ();
return nextLevel;
}
// ---------------------------------------------------------------------------------//
public boolean isOut ()
// ---------------------------------------------------------------------------------//
{
return (buffer[32] == 1);
return inMaze;
}
// ---------------------------------------------------------------------------------//
public String getType ()
// ---------------------------------------------------------------------------------//
{
return stats.type;
return type;
}
// ---------------------------------------------------------------------------------//
public String getStatus ()
// ---------------------------------------------------------------------------------//
{
return status;
}
// ---------------------------------------------------------------------------------//
public String getRace ()
// ---------------------------------------------------------------------------------//
{
return stats.race;
return race;
}
// ---------------------------------------------------------------------------------//
public String getAlignment ()
// ---------------------------------------------------------------------------------//
{
return stats.alignment;
return alignment;
}
// ---------------------------------------------------------------------------------//
public Attributes getAttributes ()
int[] getAttributes ()
// ---------------------------------------------------------------------------------//
{
return attributes;
}
// ---------------------------------------------------------------------------------//
public Statistics getStatistics ()
public Iterator<Possession> getBaggage ()
// ---------------------------------------------------------------------------------//
{
return stats;
}
// ---------------------------------------------------------------------------------//
public Iterator<Baggage> getBaggage ()
// ---------------------------------------------------------------------------------//
{
return baggageList.iterator ();
return possessions.iterator ();
}
// ---------------------------------------------------------------------------------//
@ -299,18 +225,21 @@ class CharacterV1 extends Character
}
// ---------------------------------------------------------------------------------//
public class Baggage
public class Possession
// ---------------------------------------------------------------------------------//
{
public Item item;
public ItemV1 item;
int itemId;
public boolean cursed;
public boolean equipped;
public boolean identified;
public Baggage (Item item, boolean equipped, boolean identified)
public Possession (int itemId, boolean equipped, boolean cursed, boolean identified)
{
this.item = item;
this.itemId = itemId;
this.equipped = equipped;
this.identified = identified;
this.cursed = cursed;
}
@Override
@ -320,38 +249,4 @@ class CharacterV1 extends Character
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 long 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 = new int[6];
}
}

View File

@ -18,33 +18,22 @@ public class CharacterV4 extends Character
int id;
int nextCharacterId;
CharacterParty party;
String partialSlogan;
public final boolean inMaze;
public final Race race;
public final CharacterClass characterClass;
public final int age;
public final CharacterStatus status;
public final Alignment alignment;
public final int[] attributes = new int[6]; // 0:18
public final int[] saveVs = new int[5]; // 0:31
public final long gold;
public final int possessionsCount;
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 charlev; // character level?
public final int hpLeft;
public final int hpMax;
public final boolean mysteryBit; // first bit in spellsKnown
public final boolean[] spellsKnown = new boolean[50];
public final int[][] spellAllowance = new int[2][7];
public final int hpCalCmd;
public final int armourClass;
public final int healPts;
public final boolean crithitm;
@ -57,31 +46,6 @@ public class CharacterV4 extends Character
int unknown4;
int unknown5;
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
}
public enum Status
{
OK, AFRAID, ASLEEP, PLYZE, STONED, DEAD, ASHES, LOST
}
// ---------------------------------------------------------------------------------//
CharacterV4 (String name, byte[] buffer, int id)
// ---------------------------------------------------------------------------------//
@ -91,28 +55,23 @@ public class CharacterV4 extends Character
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.signedShort (buffer, 39);
armourClass = Utility.getSignedShort (buffer, 39);
status = CharacterStatus.values ()[Utility.getShort (buffer, 41)];
alignment = Alignment.values ()[Utility.getShort (buffer, 43)];
int attr1 = Utility.getShort (buffer, 45);
int attr2 = Utility.getShort (buffer, 47);
attributes[0] = attr1 & 0x001F;
attributes[1] = (attr1 & 0x03E0) >>> 5;
attributes[2] = attr1 & (0x7C00) >>> 10;
attributes[3] = attr2 & 0x001F;
attributes[4] = attr2 & (0x03E0) >>> 5;
attributes[5] = attr2 & (0x7C00) >>> 10;
get3x5Bits (attributes, 0, Utility.getShort (buffer, 45));
get3x5Bits (attributes, 3, Utility.getShort (buffer, 47));
gold = 0;
unknown1 = Utility.getShort (buffer, 49); // was luck/skill (4 bytes)
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);
@ -133,30 +92,14 @@ public class CharacterV4 extends Character
experience = 0;
nextCharacterId = Utility.getShort (buffer, 125);
maxlevac = Utility.getShort (buffer, 131);
charlev = Utility.getShort (buffer, 133);
characterLevel = Utility.getShort (buffer, 133);
hpLeft = Utility.getShort (buffer, 135);
hpMax = Utility.getShort (buffer, 137);
mysteryBit = (buffer[139] & 0x01) == 1;
int index = -1; // skip mystery bit
for (int i = 139; i < 146; i++)
for (int bit = 0; bit < 8; bit++)
{
if (((buffer[i] >>> bit) & 0x01) != 0)
if (index >= 0)
spellsKnown[index] = true;
checkKnownSpells (buffer, 139);
if (++index >= MAX_SPELLS)
break;
}
for (int i = 0; i < 7; i++)
{
spellAllowance[MAGE_SPELLS][i] = Utility.getShort (buffer, 147 + i * 2);
spellAllowance[PRIEST_SPELLS][i] = Utility.getShort (buffer, 161 + i * 2);
}
hpCalCmd = Utility.signedShort (buffer, 175);
hpCalCmd = Utility.getSignedShort (buffer, 175);
// armourClass = Utility.getSignedShort (buffer, 177); // see offset 39
healPts = Utility.getShort (buffer, 179);
@ -194,7 +137,8 @@ public class CharacterV4 extends Character
String getPartialSlogan ()
// ---------------------------------------------------------------------------------//
{
return buffer[17] == 0 ? "" : HexFormatter.getPascalString (buffer, 17);
// return buffer[17] == 0 ? "" : HexFormatter.getPascalString (buffer, 17);
return partialSlogan;
}
// ---------------------------------------------------------------------------------//
@ -250,7 +194,7 @@ public class CharacterV4 extends Character
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", charlev));
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 ()));
@ -266,7 +210,8 @@ public class CharacterV4 extends Character
if (!party.slogan.isEmpty () || party.characters.size () > 1)
{
text.append ("\n");
for (int i = possessionsCount; i < 9; i++)
text.append ("\n");
text.append (party);
}

View File

@ -32,7 +32,7 @@ class Huffman extends AbstractFile
}
// ---------------------------------------------------------------------------------//
byte[] decodeMessage (byte[] buffer, int offset, int length)
byte[] decodeMessageOld (byte[] buffer, int offset, int length)
// ---------------------------------------------------------------------------------//
{
this.message = buffer;
@ -54,6 +54,27 @@ class Huffman extends AbstractFile
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)
// ---------------------------------------------------------------------------------//
@ -93,7 +114,7 @@ class Huffman extends AbstractFile
currentByte = message[msgPtr++]; // ...get a new byte
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
byte nodeValue = buffer[treePtr + offset[currentBit]];
@ -118,6 +139,7 @@ class Huffman extends AbstractFile
walk (0, "", text);
bufferContents = text.toString ();
}
return bufferContents;
}

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

@ -1,36 +1,53 @@
package com.bytezone.diskbrowser.wizardry;
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;
private final int type;
private final long cost;
public int partyOwns;
int itemId;
String genericName;
static int counter = 0;
public final Dice damage;
public final int armourClass;
public final int speed;
protected long price;
public Dice wephpdam;
public int armourClass;
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)
// ---------------------------------------------------------------------------------//
{
super (name, buffer);
itemID = counter++;
genericName = HexFormatter.getPascalString (buffer, 16);
type = buffer[32];
cost = Utility.getShort (buffer, 44) + Utility.getShort (buffer, 46) * 10000
+ Utility.getShort (buffer, 48) * 100000000L;
armourClass = buffer[62];
damage = new Dice (buffer, 66);
speed = buffer[72]; // 14 flags
}
// ---------------------------------------------------------------------------------//
@ -40,127 +57,39 @@ class Item extends AbstractFile implements Comparable<Item>
{
StringBuilder text = new StringBuilder ();
text.append ("Name ......... : " + getName ());
// int length = HexFormatter.intValue (buffer[16]);
text.append ("\nGeneric name . : " + genericName);
text.append ("\nType ......... : " + type);
text.append ("\nCost ......... : " + cost);
text.append ("\nArmour class . : " + armourClass);
text.append ("\nDamage ....... : " + damage);
text.append ("\nSpeed ........ : " + speed);
text.append ("\nCursed? ...... : " + isCursed ());
int stock = getStockOnHand ();
text.append ("\nStock on hand : " + stock);
if (stock < 0)
text.append (" (always in stock)");
text.append (String.format ("ID ............... %s%n%n", itemId));
text.append (String.format ("Name ............. %s%n", name));
text.append (String.format ("Generic name ..... %s%n", genericName));
text.append (String.format ("Cost ............. %,d%n", price));
text.append (String.format ("Damage ........... %s%n", wephpdam));
text.append (String.format ("Hit mod .......... %d%n", wephitmd));
text.append (String.format ("Critical hit ..... %s%n", crithitm));
text.append (String.format ("Type ............. %s%n", type));
text.append (String.format ("Alignment ........ %s%n", alignment));
text.append (String.format ("Armour class ..... %d%n", armourClass));
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 ();
}
// ---------------------------------------------------------------------------------//
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 ? 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 (Item otherItem)
// ---------------------------------------------------------------------------------//
{
Item item = otherItem;
return this.type - item.type;
}
}
}

View File

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

View File

@ -1,14 +1,13 @@
package com.bytezone.diskbrowser.wizardry;
import com.bytezone.diskbrowser.applefile.AbstractFile;
import com.bytezone.diskbrowser.utilities.HexFormatter;
import java.util.List;
import com.bytezone.diskbrowser.utilities.Utility;
// -----------------------------------------------------------------------------------//
public class ItemV4 extends AbstractFile
public class ItemV4 extends Item
// -----------------------------------------------------------------------------------//
{
String name;
String nameGeneric;
// ---------------------------------------------------------------------------------//
ItemV4 (String[] names, byte[] buffer, int id)
@ -16,8 +15,42 @@ public class ItemV4 extends AbstractFile
{
super (names[1], buffer);
itemId = id;
name = names[1];
nameGeneric = names[0];
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);
}
// ---------------------------------------------------------------------------------//
@ -25,7 +58,12 @@ public class ItemV4 extends AbstractFile
public String getText ()
// ---------------------------------------------------------------------------------//
{
return HexFormatter.format (buffer, 1, buffer[0] & 0xFF);
StringBuilder text = new StringBuilder (super.getText ());
// text.append ("\n\n");
// text.append (HexFormatter.format (buffer));
return text.toString ();
}
// ---------------------------------------------------------------------------------//

View File

@ -50,9 +50,9 @@ class MazeCell
MazeAddress addressTo; // if teleport/stairs/chute
public MessageV1 message;
public List<Monster> monsters;
public Item itemRequired;
public Item itemObtained;
public List<MonsterV1> monsters;
public ItemV1 itemRequired;
public ItemV1 itemObtained;
// ---------------------------------------------------------------------------------//
MazeCell (MazeAddress address)
@ -345,12 +345,12 @@ class MazeCell
sign.append ("&nbsp;Monster&nbsp;");
else
{
Monster monster = monsters.get (monsterID);
sign.append ("&nbsp;<b>" + monster.getRealName () + "&nbsp;</b>");
MonsterV1 monster = monsters.get (monsterID);
sign.append ("&nbsp;<b>" + monster.getName () + "&nbsp;</b>");
while (monster.partnerOdds == 100)
{
monster = monsters.get (monster.partnerID);
sign.append ("<br>&nbsp;<b>" + monster.getRealName () + "&nbsp;</b>");
sign.append ("<br>&nbsp;<b>" + monster.getName () + "&nbsp;</b>");
}
}
if (itemRequired != null)

View File

@ -25,8 +25,8 @@ public class MazeLevel extends AbstractFile
public final int level;
private List<MessageV1> messages;
private List<Monster> monsters;
private List<Item> items;
private List<MonsterV1> monsters;
private List<ItemV1> items;
// ---------------------------------------------------------------------------------//
public MazeLevel (byte[] buffer, int level)
@ -105,7 +105,7 @@ public class MazeLevel extends AbstractFile
for (MazeAddress address : monsterList)
{
Monster monster = getMonster (address.column);
MonsterV1 monster = getMonster (address.column);
if (monster != null)
{
text.append (String.format ("%nMonster: %04X%n", address.column));
@ -222,7 +222,7 @@ public class MazeLevel extends AbstractFile
if (messageType == 4)
{
if (address.level < monsters.size ())
extraText += monsters.get (address.level).realName;
extraText += monsters.get (address.level).getName ();
else
extraText += "Obtained: " + items.get ((address.level - 64536) * -1).getName ();
}
@ -240,7 +240,7 @@ public class MazeLevel extends AbstractFile
monsterList.add (address);
extraText = "Encounter: ";
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,
@ -288,7 +288,7 @@ public class MazeLevel extends AbstractFile
{
if (id == minenemy + range0n)
text.append ("\n");
Monster monster = monsters == null ? null : monsters.get (id);
MonsterV1 monster = monsters == null ? null : monsters.get (id);
text.append (String.format ("%3d %-16s %n", id, monster));
}
}
@ -325,14 +325,14 @@ public class MazeLevel extends AbstractFile
}
// ---------------------------------------------------------------------------------//
public void setMonsters (List<Monster> monsters)
public void setMonsters (List<MonsterV1> monsters)
// ---------------------------------------------------------------------------------//
{
this.monsters = monsters;
}
// ---------------------------------------------------------------------------------//
public void setItems (List<Item> items)
public void setItems (List<ItemV1> items)
// ---------------------------------------------------------------------------------//
{
this.items = items;
@ -527,13 +527,13 @@ public class MazeLevel extends AbstractFile
}
// ---------------------------------------------------------------------------------//
private Monster getMonster (int monsterNo)
private MonsterV1 getMonster (int monsterNo)
// ---------------------------------------------------------------------------------//
{
if (monsters == null)
return null;
for (Monster m : monsters)
for (MonsterV1 m : monsters)
if (m.match (monsterNo))
return m;

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

@ -4,122 +4,44 @@ import java.util.ArrayList;
import java.util.List;
import com.bytezone.diskbrowser.applefile.AbstractFile;
import com.bytezone.diskbrowser.utilities.HexFormatter;
import com.bytezone.diskbrowser.utilities.Utility;
// -----------------------------------------------------------------------------------//
class Monster extends AbstractFile
public abstract class Monster extends AbstractFile
// -----------------------------------------------------------------------------------//
{
int scenarioId;
public static final String[] monsterClass = { "Fighter", "Mage", "Priest", "Thief", "Midget",
"Giant", "Mythical", "Dragon", "Animal", "Were", "Undead", "Demon", "Insect", "Enchanted" };
protected final String[] breathValues =
{ "None", "Fire", "Frost", "Poison", "Level drain", "Stoning", "Magic" };
public final String genericName;
public final String realName;
public final int monsterID;
public int monsterID;
List<Monster> monsters;
Reward goldReward;
Reward chestReward;
public String genericName;
public String genericNamePlural;
public String namePlural;
final int type;
final int imageID;
public Dice groupSize;
public Dice hitPoints;
int type;
public int armourClass;
public int recsn;
List<Dice> damage = new ArrayList<> ();
public final int partnerID;
public final int partnerOdds;
public final int armourClass;
public final int recsn;
public final int mageSpellLevel;
public final int priestSpellLevel;
public int mageSpellLevel;
public int priestSpellLevel;
int experiencePoints;
int levelDrain;
int healPts;
int breathe;
int unaffect;
int unique;
int resistance;
int abilities;
public final Dice groupSize, hitPoints;
List<Dice> damage = new ArrayList<> ();
static int counter = 0;
public static String[] monsterClass = { "Fighter", "Mage", "Priest", "Thief", "Midget", "Giant",
"Mythical", "Dragon", "Animal", "Were", "Undead", "Demon", "Insect", "Enchanted" };
// 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
};
// ---------------------------------------------------------------------------------//
Monster (String name, byte[] buffer, List<Reward> rewards, List<Monster> monsters, int scenarioId)
Monster (String name, byte[] buffer)
// ---------------------------------------------------------------------------------//
{
super (name, buffer);
this.scenarioId = scenarioId;
realName = name;
genericName = HexFormatter.getPascalString (buffer, 0);
this.monsterID = counter++;
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 = 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);
}
// ---------------------------------------------------------------------------------//
private 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;
}
// ---------------------------------------------------------------------------------//
@ -129,122 +51,35 @@ class Monster extends AbstractFile
{
StringBuilder text = new StringBuilder ();
int totalExperience = scenarioId == 1 ? getExperience () : experiencePoints;
text.append (String.format ("ID .............. %d%n%n", monsterID));
text.append (String.format ("Name ............ %s%n", name));
text.append (String.format ("Name plural ..... %s%n", namePlural));
text.append (String.format ("Generic name .... %s%n", genericName));
text.append (String.format ("Generic name pl . %s%n%n", genericNamePlural));
text.append ("ID .............. " + monsterID);
text.append ("\nMonster name .... " + realName);
text.append ("\nGeneric name .... " + genericName);
text.append (String.format ("Type ............ %2d %s%n", type, monsterClass[type]));
text.append (String.format ("Armour class .... %d%n", armourClass));
text.append (String.format ("Group size ...... %s%n", groupSize));
text.append (String.format ("Hit points ...... %s%n%n", hitPoints));
text.append ("\n\nImage ID ........ " + imageID);
text.append ("\nGroup size ...... " + groupSize);
text.append ("\nHit points ...... " + hitPoints);
text.append (String.format ("# damage ........ %d%n", recsn));
text.append (String.format ("Damage .......... %s%n%n", getDamage ()));
text.append ("\n\nMonster class ... " + type + " " + monsterClass[type]);
text.append ("\nArmour class .... " + armourClass);
text.append (String.format ("Mage level ...... %d%n", mageSpellLevel));
text.append (String.format ("Priest level .... %d%n%n", priestSpellLevel));
text.append ("\n\n# damage ........ " + recsn);
text.append (String.format ("Level drain ..... %d%n", levelDrain));
text.append (String.format ("Heal pts ........ %d%n", healPts));
text.append (String.format ("Breathe ......... %d %s%n", breathe, breathValues[breathe]));
text.append (String.format ("Magic resist .... %d%% %n%n", unaffect));
text.append ("\nDamage .......... " + getDamage ());
text.append ("\n\nLevel drain ..... " + levelDrain);
text.append ("\nHeal pts? ....... " + healPts);
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);
text.append ("\nPriest level .... " + priestSpellLevel);
text.append ("\n\nUnique .......... " + unique);
text.append ("\nBreathe ......... " + breathe);
text.append ("\nUnaffect ........ " + unaffect);
text.append ("\n\nResistance ...... " + String.format ("%3d %<02X", resistance));
text.append ("\nAbilities ....... " + String.format ("%3d %<02X", abilities));
text.append (String.format ("%n%nExperience ...... %-,7d", totalExperience));
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);
text.append (
String.format ("Resistance ...... %s%n", String.format ("%3d %<02X", resistance)));
text.append (String.format ("Abilities ....... %s%n", String.format ("%3d %<02X", abilities)));
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 realName;
}
// ---------------------------------------------------------------------------------//
public String getRealName ()
// ---------------------------------------------------------------------------------//
{
return realName;
}
// ---------------------------------------------------------------------------------//
public String getDamage ()
// ---------------------------------------------------------------------------------//
@ -263,44 +98,11 @@ class Monster extends AbstractFile
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)
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 ();
}
// ---------------------------------------------------------------------------------//
public boolean match (int monsterID)
// ---------------------------------------------------------------------------------//
{
return this.monsterID == monsterID;
}
// ---------------------------------------------------------------------------------//
@Override
public String toString ()
// ---------------------------------------------------------------------------------//
{
return realName;
return name;
}
}
}

View File

@ -0,0 +1,221 @@
package com.bytezone.diskbrowser.wizardry;
import java.util.List;
import com.bytezone.diskbrowser.utilities.HexFormatter;
import com.bytezone.diskbrowser.utilities.Utility;
// -----------------------------------------------------------------------------------//
class MonsterV1 extends Monster
// -----------------------------------------------------------------------------------//
{
int scenarioId;
List<MonsterV1> monsters;
Reward goldReward;
Reward chestReward;
final int imageID;
public final int partnerID;
public final int partnerOdds;
public final int armourClass;
int experiencePoints;
int unique;
// static int counter = 0;
// Scenario #1 values
private static int[] experience = { //
55, 235, 415, 230, 380, 620, 840, 520, 550, 350, // 00-09
475, 515, 920, 600, 735, 520, 795, 780, 990, 795, // 10-19
1360, 1320, 1275, 680, 960, 600, 755, 1120, 2075, 870, // 20-29
960, 600, 1120, 2435, 1080, 2280, 975, 875, 1135, 1200, // 30-39
620, 740, 1460, 1245, 960, 1405, 1040, 1220, 1520, 1000, // 40-49
960, 2340, 2160, 2395, 790, 1140, 1235, 1790, 1720, 2240, // 50-59
1475, 1540, 1720, 1900, 1240, 1220, 1020, 20435, 5100, 3515, // 60-69
2115, 2920, 2060, 2140, 1400, 1640, 1280, 4450, 42840, 3300, // 70-79
40875, 5000, 3300, 2395, 1935, 1600, 3330, 44090, 40840, 5200, // 80-89
4155, 3000, 9200, 3160, 7460, 7320, 15880, 1600, 2200, 1000, // 90-99
1900 // 100
};
// ---------------------------------------------------------------------------------//
MonsterV1 (int id, String name, byte[] buffer, List<Reward> rewards, List<MonsterV1> monsters,
int scenarioId)
// ---------------------------------------------------------------------------------//
{
super (name, buffer);
this.scenarioId = scenarioId;
genericName = HexFormatter.getPascalString (buffer, 0);
genericNamePlural = HexFormatter.getPascalString (buffer, 16);
namePlural = HexFormatter.getPascalString (buffer, 48);
// this.monsterID = counter++;
this.monsterID = id;
this.monsters = monsters;
imageID = buffer[64];
groupSize = new Dice (buffer, 66);
hitPoints = new Dice (buffer, 72);
type = buffer[78];
armourClass = buffer[80];
recsn = buffer[82]; // number of dice
for (int i = 0, ptr = 84; i < 7; i++, ptr += 6)
{
if (buffer[ptr] == 0)
break;
damage.add (new Dice (buffer, ptr));
}
experiencePoints = Utility.getWizLong (buffer, 126);
levelDrain = buffer[132];
healPts = buffer[134];
goldReward = rewards.get (buffer[136]);
chestReward = rewards.get (buffer[138]);
partnerID = buffer[140];
partnerOdds = buffer[142];
mageSpellLevel = buffer[144];
priestSpellLevel = buffer[146];
unique = buffer[148];
breathe = buffer[150];
unaffect = buffer[152];
resistance = buffer[154]; // bit flags
abilities = buffer[156]; // bit flags
goldReward.addMonster (this, 0);
chestReward.addMonster (this, 1);
}
// ---------------------------------------------------------------------------------//
@Override
public String getText ()
// ---------------------------------------------------------------------------------//
{
StringBuilder text = new StringBuilder (super.getText ());
int totalExperience = scenarioId == 1 ? getExperience () : experiencePoints;
text.append ("\nImage ID ........ " + imageID);
text.append ("\n\nPartner ID ...... " + partnerID);
if (partnerOdds > 0)
text.append (" " + monsters.get (partnerID).getName ());
text.append ("\nPartner odds .... " + partnerOdds + "%");
text.append ("\n\nUnique .......... " + unique);
text.append (String.format ("%n%nExperience ...... %-,7d", totalExperience));
text.append (String.format ("%n%n===== Gold reward %2d ======", goldReward.id));
// text.append ("\nTable ........... " + rewardTable1);
text.append ("\n" + goldReward.getText (false));
text.append (String.format ("===== Chest reward %2d =====", chestReward.id));
// text.append ("\nTable ........... " + rewardTable2);
text.append ("\n" + chestReward.getText (false));
while (text.charAt (text.length () - 1) == 10)
text.deleteCharAt (text.length () - 1);
return text.toString ();
}
// ---------------------------------------------------------------------------------//
private int getExperience ()
// ---------------------------------------------------------------------------------//
{
int expHitPoints = hitPoints.qty * hitPoints.sides * (breathe == 0 ? 20 : 40);
int expAc = 40 * (11 - armourClass);
int expMage = getBonus (35, mageSpellLevel);
int expPriest = getBonus (35, priestSpellLevel);
int expDrain = getBonus (200, levelDrain);
int expHeal = getBonus (90, healPts);
int expDamage = recsn <= 1 ? 0 : getBonus (30, recsn);
int expUnaffect = unaffect == 0 ? 0 : getBonus (40, (unaffect / 10 + 1));
int expFlags1 = getBonus (35, Integer.bitCount (resistance & 0x7E)); // 6 bits
int expFlags2 = getBonus (40, Integer.bitCount (abilities & 0x7F)); // 7 bits
return expHitPoints + expAc + expMage + expPriest + expDrain + expHeal + expDamage + expUnaffect
+ expFlags1 + expFlags2;
}
// ---------------------------------------------------------------------------------//
private int getBonus (int base, int multiplier)
// ---------------------------------------------------------------------------------//
{
if (multiplier == 0)
return 0;
int total = base;
while (multiplier > 1)
{
int part = total % 10000; // get the last 4 digits
multiplier--;
total += total; // double the value
if (part >= 5000) // mimics the wizardry bug
total += 10000; // yay, free points
}
return total;
}
// ---------------------------------------------------------------------------------//
// public void setImage (BufferedImage image)
// // ---------------------------------------------------------------------------------//
// {
// this.image = image;
// }
// ---------------------------------------------------------------------------------//
@Override
public String getName ()
// ---------------------------------------------------------------------------------//
{
return name;
}
// ---------------------------------------------------------------------------------//
public String getDump (int block)
// ---------------------------------------------------------------------------------//
{
StringBuilder line = new StringBuilder (String.format ("%3d %-16s", monsterID, name));
// int lo = block == 0 ? 64 : block == 1 ? 88 : block == 2 ? 112 : 136;
int lo = 64 + block * 24;
int hi = lo + 24;
if (hi > buffer.length)
hi = buffer.length;
for (int i = lo; i < hi; i++)
line.append (String.format ("%02X ", buffer[i]));
if (block == 3)
if (scenarioId == 1)
{
int exp = getExperience ();
line.append (String.format (" %,6d %,6d", exp, exp - experience[monsterID]));
}
else
line.append (String.format (" %,6d", experiencePoints));
return line.toString ();
}
// ---------------------------------------------------------------------------------//
boolean match (int monsterID)
// ---------------------------------------------------------------------------------//
{
return this.monsterID == monsterID;
}
}

View File

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

View File

@ -16,12 +16,12 @@ class Reward extends AbstractFile
int totalElements;
List<RewardElement> elements;
List<Item> items;
List<Monster> goldMonsters = new ArrayList<> ();
List<Monster> chestMonsters = new ArrayList<> ();
List<ItemV1> items;
List<MonsterV1> goldMonsters = 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);
@ -41,7 +41,7 @@ class Reward extends AbstractFile
}
// ---------------------------------------------------------------------------------//
public void addMonster (Monster monster, int location)
public void addMonster (MonsterV1 monster, int location)
// ---------------------------------------------------------------------------------//
{
if (location == 0)
@ -71,14 +71,14 @@ class Reward extends AbstractFile
if (goldMonsters.size () > 0)
{
text.append ("Without chest:\n\n");
for (Monster m : goldMonsters)
for (MonsterV1 m : goldMonsters)
text.append (" " + m + "\n");
text.append ("\n");
}
if (chestMonsters.size () > 0)
{
text.append ("With chest:\n\n");
for (Monster m : chestMonsters)
for (MonsterV1 m : chestMonsters)
text.append (" " + m + "\n");
}
}

View File

@ -21,7 +21,7 @@ import com.bytezone.diskbrowser.wizardry.Header.ScenarioData;
public class Wizardry4BootDisk extends PascalDisk
// -----------------------------------------------------------------------------------//
{
public Header scenarioHeader;
private Header scenarioHeader;
private Relocator relocator;
private MessageBlock messageBlock;
private Huffman huffman;
@ -30,6 +30,8 @@ public class Wizardry4BootDisk extends PascalDisk
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)
@ -97,6 +99,7 @@ public class Wizardry4BootDisk extends PascalDisk
fileEntry.setFile (null);
scenarioNode.setAllowsChildren (true);
scenarioHeader = new Header (scenarioNode, this);
readSpells ();
linkCharacters4 (scenarioNode, fileEntry);
linkParties ();
linkMazeLevels4 (scenarioNode, fileEntry);
@ -160,7 +163,7 @@ public class Wizardry4BootDisk extends PascalDisk
for (int i = 0; i < 500; i++)
{
byte[] out = huffman.decodeMessage (buffer, ptr, sd.totalBlocks);
byte[] out = huffman.decodeMessage (buffer, ptr);
String name = HexFormatter.getPascalString (out, 1);
@ -200,6 +203,19 @@ public class Wizardry4BootDisk extends PascalDisk
}
}
// ---------------------------------------------------------------------------------//
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)
// ---------------------------------------------------------------------------------//
@ -231,12 +247,17 @@ public class Wizardry4BootDisk extends PascalDisk
for (int i = 0; i < sd.total; i++)
{
byte[] out = huffman.decodeMessage (buffer, ptr, sd.totalBlocks);
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);
@ -271,13 +292,13 @@ public class Wizardry4BootDisk extends PascalDisk
for (int i = 0; i < sd.total; i++)
{
byte[] out = huffman.decodeMessage (buffer, ptr, sd.totalBlocks);
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] = "Not found";
itemNames[j] = "Broken Item";
}
ItemV4 item = new ItemV4 (itemNames, out, i);
@ -299,6 +320,12 @@ public class Wizardry4BootDisk extends PascalDisk
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);
}
// ---------------------------------------------------------------------------------//

View File

@ -18,8 +18,6 @@ import com.bytezone.diskbrowser.gui.DataSource;
import com.bytezone.diskbrowser.pascal.PascalDisk;
import com.bytezone.diskbrowser.utilities.HexFormatter;
import com.bytezone.diskbrowser.utilities.Utility;
import com.bytezone.diskbrowser.wizardry.CharacterV1.Attributes;
import com.bytezone.diskbrowser.wizardry.CharacterV1.Statistics;
import com.bytezone.diskbrowser.wizardry.Header.ScenarioData;
import com.bytezone.diskbrowser.wizardry.Spell.SpellType;
@ -30,15 +28,18 @@ public class WizardryScenarioDisk extends PascalDisk
public Header scenarioHeader;
public List<AbstractImage> images;
public List<Item> items;
public List<ItemV1> items;
public List<CharacterV1> characters;
public List<Spell> spells;
public List<MessageV1> messages;
public List<Monster> monsters;
public List<MonsterV1> monsters;
public List<MazeLevel> levels;
List<ExperienceLevel> experiences;
List<ExperienceLevel> experienceLevels;
List<Reward> rewards;
private int monsterId;
private int itemId;
// leave these here until I decide whether to use them or not
SectorType mazeSector = new SectorType ("Maze", Color.lightGray);
SectorType monsterSector = new SectorType ("Monsters", Color.black);
@ -70,18 +71,18 @@ public class WizardryScenarioDisk extends PascalDisk
}
CodedMessage.codeOffset = 185;
Monster.counter = 0;
Item.counter = 0;
DefaultTreeModel model = (DefaultTreeModel) catalogTree.getModel ();
DefaultMutableTreeNode currentRoot = (DefaultMutableTreeNode) model.getRoot ();
DefaultMutableTreeNode dataNode = findNode (currentRoot, "SCENARIO.DATA");
DefaultMutableTreeNode msgNode = findNode (currentRoot, "SCENARIO.MESGS");
if (dataNode == null || msgNode == null)
{
System.out.println ("Wizardry data or msg node not found");
return;
}
dataNode.setAllowsChildren (true);
msgNode.setAllowsChildren (true);
@ -89,9 +90,7 @@ public class WizardryScenarioDisk extends PascalDisk
// Process SCENARIO.MESGS (requires scenario)
AppleFileSource afs = (AppleFileSource) msgNode.getUserObject ();
// DefaultMutableTreeNode node = linkNode ("Messages", "Messages string", msgNode);
extractMessages (msgNode, afs.getSectors ());
// makeNodeVisible (node);
// Process SCENARIO.DATA (requires scenario and messages)
afs = (AppleFileSource) dataNode.getUserObject ();
@ -103,21 +102,16 @@ public class WizardryScenarioDisk extends PascalDisk
extractCharacters (linkNode ("Characters", "Characters string", dataNode), sectors);
extractImages (linkNode ("Images", "Images string", dataNode), sectors);
extractExperienceLevels (linkNode ("Experience", "Experience string", dataNode), sectors);
// node = linkNode ("Spells", "Spells string", dataNode);
DefaultMutableTreeNode node = null;
extractSpells (node, sectors);
extractSpells (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.
for (CharacterV1 c : characters)
{
c.linkItems (items);
c.linkSpells (spells);
int type = c.getStatistics ().typeInt;
c.linkExperience (experiences.get (type));
}
for (CharacterV1 character : characters)
character.link (items, spells, experienceLevels);
for (ItemV1 item : items)
item.link (items, spells);
}
// ---------------------------------------------------------------------------------//
@ -127,6 +121,7 @@ public class WizardryScenarioDisk extends PascalDisk
DefaultAppleFileSource afs = new DefaultAppleFileSource (name, text, this);
DefaultMutableTreeNode node = new DefaultMutableTreeNode (afs);
parent.add (node);
return node;
}
@ -147,6 +142,7 @@ public class WizardryScenarioDisk extends PascalDisk
&& !text.equals ("WIZARDRY.CODE"))
return false;
}
return true;
}
@ -254,13 +250,12 @@ public class WizardryScenarioDisk extends PascalDisk
+ "-- -- -- -- -- -- -- ------\n");
for (CharacterV1 ch : characters)
{
Statistics stats = ch.getStatistics ();
Attributes att = ch.getAttributes ();
text.append (String.format ("%-15s %2d %-8s %-8s %-8s %3d", ch, (stats.ageInWeeks / 52),
stats.alignment, stats.race, stats.type, stats.hitsMax));
text.append (String.format (" %2d %2d %2d %2d %2d %2d", att.strength, att.intelligence,
att.piety, att.vitality, att.agility, att.luck));
text.append (String.format (" %5s %s%n", stats.status, ch.isOut () ? "* OUT *" : ""));
int[] att = ch.getAttributes ();
text.append (String.format ("%-15s %2d %-8s %-8s %-8s %3d", ch, (ch.ageInWeeks / 52),
ch.getAlignment (), ch.getRace (), ch.getType (), ch.hpMax));
text.append (String.format (" %2d %2d %2d %2d %2d %2d", att[0], att[1], att[2], att[3],
att[4], att[5]));
text.append (String.format (" %5s %s%n", ch.getStatus (), ch.isOut () ? "* OUT *" : ""));
}
DefaultAppleFileSource afs = (DefaultAppleFileSource) node.getUserObject ();
@ -318,7 +313,7 @@ public class WizardryScenarioDisk extends PascalDisk
for (int i = 0; i < 24; i++)
text.append (" --");
text.append ("\n");
for (Monster m : monsters)
for (MonsterV1 m : monsters)
text.append (m.getDump (block) + "\n");
text.append ("\n");
}
@ -343,7 +338,8 @@ public class WizardryScenarioDisk extends PascalDisk
byte[] data2 = new byte[recLen];
System.arraycopy (buffer, ptr, data2, 0, recLen);
Monster m = new Monster (itemName, data2, rewards, monsters, scenarioHeader.scenarioID);
MonsterV1 m = new MonsterV1 (monsterId++, itemName, data2, rewards, monsters,
scenarioHeader.scenarioID);
monsters.add (m);
addToNode (m, node, blocks, monsterSector);
}
@ -376,7 +372,7 @@ public class WizardryScenarioDisk extends PascalDisk
for (int i = 0; i < 24; i++)
text.append (" --");
text.append ("\n");
for (Item item : items)
for (ItemV1 item : items)
text.append (item.getDump (block) + "\n");
text.append ("\n");
}
@ -400,14 +396,14 @@ public class WizardryScenarioDisk extends PascalDisk
byte[] data2 = new byte[recLen];
System.arraycopy (buffer, ptr, data2, 0, recLen);
Item i = new Item (itemName, data2);
ItemV1 i = new ItemV1 (itemId++, itemName, data2);
items.add (i);
addToNode (i, node, blocks, itemSector);
}
}
// ---------------------------------------------------------------------------------//
private void extractSpells (DefaultMutableTreeNode node, List<DiskAddress> sectors)
private void extractSpells (List<DiskAddress> sectors)
// ---------------------------------------------------------------------------------//
{
spells = new ArrayList<> ();
@ -422,6 +418,7 @@ public class WizardryScenarioDisk extends PascalDisk
byte[] buffer = disk.readBlock (da);
int level = 1;
int ptr = -1;
while (ptr < 255)
{
ptr++;
@ -430,15 +427,17 @@ public class WizardryScenarioDisk extends PascalDisk
ptr++;
if (ptr == start)
break;
String spell = HexFormatter.getString (buffer, start, ptr - start);
if (spell.startsWith ("*"))
{
spell = spell.substring (1);
++level;
}
Spell s = Spell.getSpell (spell, spellType, level, buffer);
spells.add (s);
// addToNode (s, node, da, spellSector);
}
spellType = SpellType.PRIEST;
}
@ -559,7 +558,7 @@ public class WizardryScenarioDisk extends PascalDisk
System.arraycopy (buffer, 0, exactBuffer, 0, exactBuffer.length);
String name = "Unknown";
for (Monster m : monsters)
for (MonsterV1 m : monsters)
if (m.imageID == i)
{
name = m.genericName;
@ -588,7 +587,7 @@ public class WizardryScenarioDisk extends PascalDisk
{
List<DiskAddress> nodeSectors = new ArrayList<> ();
ScenarioData sd = scenarioHeader.data.get (Header.EXPERIENCE_AREA);
experiences = new ArrayList<> (sd.total);
experienceLevels = new ArrayList<> (sd.total);
int max = sd.totalBlocks / 2;
int count = 0;
@ -609,7 +608,7 @@ public class WizardryScenarioDisk extends PascalDisk
byte[] newBuffer = new byte[78];
System.arraycopy (buffer, ptr, newBuffer, 0, newBuffer.length);
ExperienceLevel el = new ExperienceLevel (classes[count++], newBuffer);
experiences.add (el);
experienceLevels.add (el);
addToNode (el, node, blocks, experienceSector);
}
}