mirror of
https://github.com/dmolony/DiskBrowser.git
synced 2024-12-01 09:50:32 +00:00
Wiz4 messages
This commit is contained in:
parent
78babc4d2c
commit
1f3894f162
@ -55,7 +55,7 @@ public class HexFormatter
|
|||||||
{
|
{
|
||||||
if (line.length () > 0 && i > 0)
|
if (line.length () > 0 && i > 0)
|
||||||
line.append ("\n");
|
line.append ("\n");
|
||||||
if (i > 0 && (i % 0x200) == 0)
|
if (i > offset && (i % 0x200) == 0)
|
||||||
line.append ("\n");
|
line.append ("\n");
|
||||||
|
|
||||||
// print offset
|
// print offset
|
||||||
|
@ -14,214 +14,226 @@ import com.bytezone.diskbrowser.utilities.HexFormatter;
|
|||||||
|
|
||||||
class Header
|
class Header
|
||||||
{
|
{
|
||||||
static String[] typeText =
|
static String[] typeText = { "header", "maze", "monsters", "rewards", "items",
|
||||||
{ "header", "maze", "monsters", "rewards", "items", "characters", "images", "char levels" };
|
"characters", "images", "char levels" };
|
||||||
static String[] scenarioNames =
|
static String[] scenarioNames =
|
||||||
{ "PROVING GROUNDS OF THE MAD OVERLORD!", "THE KNIGHT OF DIAMONDS",
|
{ "PROVING GROUNDS OF THE MAD OVERLORD!", "THE KNIGHT OF DIAMONDS",
|
||||||
"THE LEGACY OF LLYLGAMYN" };
|
"THE LEGACY OF LLYLGAMYN", "THE RETURN OF WERDNA" };
|
||||||
|
|
||||||
static final int MAZE_AREA = 1;
|
static final int MAZE_AREA = 1;
|
||||||
static final int MONSTER_AREA = 2;
|
static final int MONSTER_AREA = 2;
|
||||||
static final int TREASURE_TABLE_AREA = 3;
|
static final int TREASURE_TABLE_AREA = 3;
|
||||||
static final int ITEM_AREA = 4;
|
static final int ITEM_AREA = 4;
|
||||||
static final int CHARACTER_AREA = 5;
|
static final int CHARACTER_AREA = 5;
|
||||||
static final int IMAGE_AREA = 6;
|
static final int IMAGE_AREA = 6;
|
||||||
static final int EXPERIENCE_AREA = 7;
|
static final int EXPERIENCE_AREA = 7;
|
||||||
|
|
||||||
String scenarioTitle;
|
String scenarioTitle;
|
||||||
public int scenarioID;
|
public int scenarioID;
|
||||||
List<ScenarioData> data = new ArrayList<ScenarioData> (8);
|
List<ScenarioData> data = new ArrayList<ScenarioData> (8);
|
||||||
FormattedDisk owner;
|
FormattedDisk owner;
|
||||||
|
|
||||||
public Header (DefaultMutableTreeNode dataNode, FormattedDisk owner)
|
public Header (DefaultMutableTreeNode dataNode, FormattedDisk owner)
|
||||||
{
|
{
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
|
|
||||||
AppleFileSource afs = (AppleFileSource) dataNode.getUserObject ();
|
AppleFileSource afs = (AppleFileSource) dataNode.getUserObject ();
|
||||||
List<DiskAddress> sectors = afs.getSectors ();
|
List<DiskAddress> sectors = afs.getSectors ();
|
||||||
DefaultAppleFile daf = (DefaultAppleFile) afs.getDataSource ();
|
DefaultAppleFile daf = (DefaultAppleFile) afs.getDataSource ();
|
||||||
scenarioTitle = HexFormatter.getPascalString (daf.buffer, 0);
|
scenarioTitle = HexFormatter.getPascalString (daf.buffer, 0);
|
||||||
|
|
||||||
while (scenarioID < scenarioNames.length)
|
while (scenarioID < scenarioNames.length)
|
||||||
if (scenarioNames[scenarioID++].equals (scenarioTitle))
|
if (scenarioNames[scenarioID++].equals (scenarioTitle))
|
||||||
break;
|
break;
|
||||||
assert (scenarioID <= scenarioNames.length) : "Invalid scenario ID : " + scenarioID;
|
|
||||||
|
|
||||||
for (int i = 0; i < 8; i++)
|
if (scenarioID > scenarioNames.length)
|
||||||
data.add (new ScenarioData (daf.buffer, i, sectors));
|
System.out.println ("Invalid scenario ID : " + scenarioID + " " + scenarioTitle);
|
||||||
|
|
||||||
StringBuilder text =
|
for (int i = 0; i < 8; i++)
|
||||||
new StringBuilder ("Data type Offset Size Units ???\n"
|
data.add (new ScenarioData (daf.buffer, i, sectors));
|
||||||
+ "------------ ------ ----- ----- -----\n");
|
|
||||||
|
|
||||||
for (ScenarioData sd : data)
|
StringBuilder text = new StringBuilder ("Data type Offset Size Units ???\n"
|
||||||
text.append (sd + "\n");
|
+ "------------ ------ ----- ----- -----\n");
|
||||||
|
|
||||||
daf.setText (text.toString ());
|
for (ScenarioData sd : data)
|
||||||
|
text.append (sd + "\n");
|
||||||
|
|
||||||
text = new StringBuilder (scenarioTitle + "\n\n");
|
daf.setText (text.toString ());
|
||||||
|
|
||||||
int ptr = 106;
|
text = new StringBuilder (scenarioTitle + "\n\n");
|
||||||
while (daf.buffer[ptr] != -1)
|
|
||||||
{
|
|
||||||
text.append (HexFormatter.getPascalString (daf.buffer, ptr) + "\n");
|
|
||||||
ptr += 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
DefaultAppleFileSource dafs = new DefaultAppleFileSource ("Header", text.toString (), owner);
|
int ptr = 106;
|
||||||
dafs.setSectors (data.get (0).sectors);
|
while (daf.buffer[ptr] != -1)
|
||||||
DefaultMutableTreeNode headerNode = new DefaultMutableTreeNode (dafs);
|
{
|
||||||
dataNode.add (headerNode);
|
text.append (HexFormatter.getPascalString (daf.buffer, ptr) + "\n");
|
||||||
|
ptr += 10;
|
||||||
|
}
|
||||||
|
|
||||||
int totalBlocks = data.get (0).sectors.size ();
|
DefaultAppleFileSource dafs =
|
||||||
linkText ("Text", data.get (0).sectors.get (0), headerNode);
|
new DefaultAppleFileSource ("Header", text.toString (), owner);
|
||||||
if (scenarioID < 3)
|
dafs.setSectors (data.get (0).sectors);
|
||||||
{
|
DefaultMutableTreeNode headerNode = new DefaultMutableTreeNode (dafs);
|
||||||
linkPictures ("Alphabet", data.get (0).sectors.get (1), headerNode);
|
dataNode.add (headerNode);
|
||||||
linkPictures ("Graphics", data.get (0).sectors.get (2), headerNode);
|
|
||||||
linkPictures ("Unknown", data.get (0).sectors.get (3), headerNode);
|
|
||||||
}
|
|
||||||
linkSpells ("Mage spells", data.get (0).sectors.get (totalBlocks - 2), headerNode);
|
|
||||||
linkSpells ("Priest spells", data.get (0).sectors.get (totalBlocks - 1), headerNode);
|
|
||||||
|
|
||||||
if (false && scenarioID <= 2)
|
if (scenarioID > 3)
|
||||||
{
|
return;
|
||||||
System.out.println (printChars (daf.buffer, 1));
|
|
||||||
System.out.println (printChars (daf.buffer, 2));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void linkText (String title, DiskAddress da, DefaultMutableTreeNode headerNode)
|
int totalBlocks = data.get (0).sectors.size ();
|
||||||
{
|
linkText ("Text", data.get (0).sectors.get (0), headerNode);
|
||||||
List<DiskAddress> blocks = new ArrayList<DiskAddress> ();
|
|
||||||
blocks.add (da);
|
|
||||||
|
|
||||||
StringBuilder text = new StringBuilder (scenarioTitle + "\n\n");
|
if (scenarioID < 3)
|
||||||
|
{
|
||||||
|
linkPictures ("Alphabet", data.get (0).sectors.get (1), headerNode);
|
||||||
|
linkPictures ("Graphics", data.get (0).sectors.get (2), headerNode);
|
||||||
|
linkPictures ("Unknown", data.get (0).sectors.get (3), headerNode);
|
||||||
|
}
|
||||||
|
|
||||||
int ptr = 106;
|
linkSpells ("Mage spells", data.get (0).sectors.get (totalBlocks - 2), headerNode);
|
||||||
byte[] buffer = owner.getDisk ().readSector (da);
|
linkSpells ("Priest spells", data.get (0).sectors.get (totalBlocks - 1), headerNode);
|
||||||
while (buffer[ptr] != -1)
|
|
||||||
{
|
|
||||||
text.append (HexFormatter.getPascalString (buffer, ptr) + "\n");
|
|
||||||
ptr += 10;
|
|
||||||
}
|
|
||||||
ptr += 2;
|
|
||||||
text.append ("\n");
|
|
||||||
while (ptr < 512)
|
|
||||||
{
|
|
||||||
int value = HexFormatter.intValue (buffer[ptr], buffer[ptr + 1]);
|
|
||||||
text.append (String.format ("%04X %,6d%n", value, value));
|
|
||||||
ptr += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
DefaultAppleFileSource dafs = new DefaultAppleFileSource (title, text.toString (), owner);
|
if (false && scenarioID <= 2)
|
||||||
dafs.setSectors (blocks);
|
{
|
||||||
DefaultMutableTreeNode node = new DefaultMutableTreeNode (dafs);
|
System.out.println (printChars (daf.buffer, 1));
|
||||||
node.setAllowsChildren (false);
|
System.out.println (printChars (daf.buffer, 2));
|
||||||
headerNode.add (node);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void linkPictures (String title, DiskAddress da, DefaultMutableTreeNode headerNode)
|
private void linkText (String title, DiskAddress da, DefaultMutableTreeNode headerNode)
|
||||||
{
|
{
|
||||||
List<DiskAddress> blocks = new ArrayList<DiskAddress> ();
|
List<DiskAddress> blocks = new ArrayList<DiskAddress> ();
|
||||||
blocks.add (da);
|
blocks.add (da);
|
||||||
|
|
||||||
byte[] buffer = owner.getDisk ().readSector (da);
|
StringBuilder text = new StringBuilder (scenarioTitle + "\n\n");
|
||||||
String text = printChars (buffer, 0);
|
|
||||||
|
|
||||||
DefaultAppleFileSource dafs = new DefaultAppleFileSource (title, text, owner);
|
int ptr = 106;
|
||||||
dafs.setSectors (blocks);
|
byte[] buffer = owner.getDisk ().readSector (da);
|
||||||
DefaultMutableTreeNode node = new DefaultMutableTreeNode (dafs);
|
while (buffer[ptr] != -1)
|
||||||
node.setAllowsChildren (false);
|
{
|
||||||
headerNode.add (node);
|
text.append (HexFormatter.getPascalString (buffer, ptr) + "\n");
|
||||||
}
|
ptr += 10;
|
||||||
|
}
|
||||||
|
ptr += 2;
|
||||||
|
text.append ("\n");
|
||||||
|
while (ptr < 512)
|
||||||
|
{
|
||||||
|
int value = HexFormatter.intValue (buffer[ptr], buffer[ptr + 1]);
|
||||||
|
text.append (String.format ("%04X %,6d%n", value, value));
|
||||||
|
ptr += 2;
|
||||||
|
}
|
||||||
|
|
||||||
private void linkSpells (String title, DiskAddress da, DefaultMutableTreeNode headerNode)
|
DefaultAppleFileSource dafs =
|
||||||
{
|
new DefaultAppleFileSource (title, text.toString (), owner);
|
||||||
List<DiskAddress> blocks = new ArrayList<DiskAddress> ();
|
dafs.setSectors (blocks);
|
||||||
blocks.add (da);
|
DefaultMutableTreeNode node = new DefaultMutableTreeNode (dafs);
|
||||||
int level = 1;
|
node.setAllowsChildren (false);
|
||||||
|
headerNode.add (node);
|
||||||
|
}
|
||||||
|
|
||||||
StringBuilder list = new StringBuilder ("Level " + level + ":\n");
|
private void linkPictures (String title, DiskAddress da,
|
||||||
byte[] buffer = owner.getDisk ().readSector (da);
|
DefaultMutableTreeNode headerNode)
|
||||||
String text = HexFormatter.getString (buffer, 0, 512);
|
{
|
||||||
String[] spells = text.split ("\n");
|
List<DiskAddress> blocks = new ArrayList<DiskAddress> ();
|
||||||
for (String s : spells)
|
blocks.add (da);
|
||||||
{
|
|
||||||
if (s.length () == 0)
|
|
||||||
break;
|
|
||||||
if (s.startsWith ("*"))
|
|
||||||
{
|
|
||||||
s = s.substring (1);
|
|
||||||
level++;
|
|
||||||
list.append ("\nLevel " + level + ":\n");
|
|
||||||
}
|
|
||||||
list.append (" " + s + "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
DefaultAppleFileSource dafs = new DefaultAppleFileSource (title, list.toString (), owner);
|
byte[] buffer = owner.getDisk ().readSector (da);
|
||||||
dafs.setSectors (blocks);
|
String text = printChars (buffer, 0);
|
||||||
DefaultMutableTreeNode node = new DefaultMutableTreeNode (dafs);
|
|
||||||
node.setAllowsChildren (false);
|
|
||||||
headerNode.add (node);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String printChars (byte[] buffer, int block)
|
DefaultAppleFileSource dafs = new DefaultAppleFileSource (title, text, owner);
|
||||||
{
|
dafs.setSectors (blocks);
|
||||||
StringBuilder text = new StringBuilder ();
|
DefaultMutableTreeNode node = new DefaultMutableTreeNode (dafs);
|
||||||
for (int i = block * 512; i < (block + 1) * 512; i += 64)
|
node.setAllowsChildren (false);
|
||||||
{
|
headerNode.add (node);
|
||||||
for (int line = 0; line < 8; line++)
|
}
|
||||||
{
|
|
||||||
for (int j = 0; j < 8; j++)
|
|
||||||
{
|
|
||||||
int value = HexFormatter.intValue (buffer[i + line + j * 8]);
|
|
||||||
for (int bit = 0; bit < 7; bit++)
|
|
||||||
{
|
|
||||||
if ((value & 0x01) == 1)
|
|
||||||
text.append ("O");
|
|
||||||
else
|
|
||||||
text.append (".");
|
|
||||||
value >>= 1;
|
|
||||||
}
|
|
||||||
text.append (" ");
|
|
||||||
}
|
|
||||||
text.append ("\n");
|
|
||||||
}
|
|
||||||
text.append ("\n");
|
|
||||||
}
|
|
||||||
return text.toString ();
|
|
||||||
}
|
|
||||||
|
|
||||||
// this could be the base factory class for all Wizardry types
|
private void linkSpells (String title, DiskAddress da,
|
||||||
class ScenarioData
|
DefaultMutableTreeNode headerNode)
|
||||||
{
|
{
|
||||||
int dunno;
|
List<DiskAddress> blocks = new ArrayList<DiskAddress> ();
|
||||||
int total;
|
blocks.add (da);
|
||||||
int totalBlocks;
|
int level = 1;
|
||||||
int dataOffset;
|
|
||||||
int type;
|
|
||||||
List<DiskAddress> sectors;
|
|
||||||
|
|
||||||
public ScenarioData (byte[] buffer, int seq, List<DiskAddress> sectors)
|
StringBuilder list = new StringBuilder ("Level " + level + ":\n");
|
||||||
{
|
byte[] buffer = owner.getDisk ().readSector (da);
|
||||||
int offset = 42 + seq * 2;
|
String text = HexFormatter.getString (buffer, 0, 512);
|
||||||
dunno = HexFormatter.intValue (buffer[offset]);
|
String[] spells = text.split ("\n");
|
||||||
total = HexFormatter.intValue (buffer[offset + 16]);
|
for (String s : spells)
|
||||||
totalBlocks = HexFormatter.intValue (buffer[offset + 32]);
|
{
|
||||||
dataOffset = HexFormatter.intValue (buffer[offset + 48]);
|
if (s.length () == 0)
|
||||||
type = seq;
|
break;
|
||||||
|
if (s.startsWith ("*"))
|
||||||
|
{
|
||||||
|
s = s.substring (1);
|
||||||
|
level++;
|
||||||
|
list.append ("\nLevel " + level + ":\n");
|
||||||
|
}
|
||||||
|
list.append (" " + s + "\n");
|
||||||
|
}
|
||||||
|
|
||||||
this.sectors = new ArrayList<DiskAddress> (totalBlocks);
|
DefaultAppleFileSource dafs =
|
||||||
for (int i = dataOffset, max = dataOffset + totalBlocks; i < max; i++)
|
new DefaultAppleFileSource (title, list.toString (), owner);
|
||||||
this.sectors.add (sectors.get (i));
|
dafs.setSectors (blocks);
|
||||||
}
|
DefaultMutableTreeNode node = new DefaultMutableTreeNode (dafs);
|
||||||
|
node.setAllowsChildren (false);
|
||||||
|
headerNode.add (node);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
private String printChars (byte[] buffer, int block)
|
||||||
public String toString ()
|
{
|
||||||
{
|
StringBuilder text = new StringBuilder ();
|
||||||
return String.format ("%-15s %3d %3d %3d %3d", typeText[type], dataOffset,
|
for (int i = block * 512; i < (block + 1) * 512; i += 64)
|
||||||
totalBlocks, total, dunno);
|
{
|
||||||
}
|
for (int line = 0; line < 8; line++)
|
||||||
}
|
{
|
||||||
|
for (int j = 0; j < 8; j++)
|
||||||
|
{
|
||||||
|
int value = HexFormatter.intValue (buffer[i + line + j * 8]);
|
||||||
|
for (int bit = 0; bit < 7; bit++)
|
||||||
|
{
|
||||||
|
if ((value & 0x01) == 1)
|
||||||
|
text.append ("O");
|
||||||
|
else
|
||||||
|
text.append (".");
|
||||||
|
value >>= 1;
|
||||||
|
}
|
||||||
|
text.append (" ");
|
||||||
|
}
|
||||||
|
text.append ("\n");
|
||||||
|
}
|
||||||
|
text.append ("\n");
|
||||||
|
}
|
||||||
|
return text.toString ();
|
||||||
|
}
|
||||||
|
|
||||||
|
// this could be the base factory class for all Wizardry types
|
||||||
|
class ScenarioData
|
||||||
|
{
|
||||||
|
int dunno;
|
||||||
|
int total;
|
||||||
|
int totalBlocks;
|
||||||
|
int dataOffset;
|
||||||
|
int type;
|
||||||
|
List<DiskAddress> sectors;
|
||||||
|
|
||||||
|
public ScenarioData (byte[] buffer, int seq, List<DiskAddress> sectors)
|
||||||
|
{
|
||||||
|
int offset = 42 + seq * 2;
|
||||||
|
dunno = HexFormatter.intValue (buffer[offset]);
|
||||||
|
total = HexFormatter.intValue (buffer[offset + 16]);
|
||||||
|
totalBlocks = HexFormatter.intValue (buffer[offset + 32]);
|
||||||
|
dataOffset = HexFormatter.intValue (buffer[offset + 48]);
|
||||||
|
type = seq;
|
||||||
|
|
||||||
|
this.sectors = new ArrayList<DiskAddress> (totalBlocks);
|
||||||
|
for (int i = dataOffset, max = dataOffset + totalBlocks; i < max; i++)
|
||||||
|
if (i < sectors.size ())
|
||||||
|
this.sectors.add (sectors.get (i));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString ()
|
||||||
|
{
|
||||||
|
return String.format ("%-15s %3d %3d %3d %3d", typeText[type], dataOffset,
|
||||||
|
totalBlocks, total, dunno);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
69
src/com/bytezone/diskbrowser/wizardry/Huffman.java
Normal file
69
src/com/bytezone/diskbrowser/wizardry/Huffman.java
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
package com.bytezone.diskbrowser.wizardry;
|
||||||
|
|
||||||
|
public class Huffman
|
||||||
|
{
|
||||||
|
private final byte[] tree;
|
||||||
|
private final byte[] left;
|
||||||
|
private final byte[] right;
|
||||||
|
|
||||||
|
private int bit = 0;
|
||||||
|
private int msgPtr = 0;
|
||||||
|
private int b = 0;
|
||||||
|
private byte[] message;
|
||||||
|
|
||||||
|
public Huffman (byte[] buffer)
|
||||||
|
{
|
||||||
|
tree = new byte[256];
|
||||||
|
left = new byte[256];
|
||||||
|
right = new byte[256];
|
||||||
|
|
||||||
|
System.arraycopy (buffer, 0, tree, 0, 256);
|
||||||
|
System.arraycopy (buffer, 256, left, 0, 256);
|
||||||
|
System.arraycopy (buffer, 512, right, 0, 256);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage (byte[] message)
|
||||||
|
{
|
||||||
|
this.message = message;
|
||||||
|
bit = 0;
|
||||||
|
msgPtr = 0;
|
||||||
|
b = 0;
|
||||||
|
|
||||||
|
int len = getChar ();
|
||||||
|
StringBuilder text = new StringBuilder ();
|
||||||
|
for (int i = 0; i < len; i++)
|
||||||
|
text.append ((char) getChar ());
|
||||||
|
return text.toString ();
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte getChar ()
|
||||||
|
{
|
||||||
|
int treePtr = 0;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (bit == 0)
|
||||||
|
{
|
||||||
|
bit = 8;
|
||||||
|
b = message[msgPtr++] & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
int thisBit = b % 2;
|
||||||
|
b /= 2;
|
||||||
|
bit--;
|
||||||
|
|
||||||
|
if (thisBit == 0) // take right path
|
||||||
|
{
|
||||||
|
if ((tree[treePtr] & 0x02) != 0) // if has right leaf
|
||||||
|
return right[treePtr];
|
||||||
|
treePtr = right[treePtr]; // go to right node
|
||||||
|
}
|
||||||
|
else // take left path
|
||||||
|
{
|
||||||
|
if ((tree[treePtr] & 0x01) != 0) // if has left leaf
|
||||||
|
return left[treePtr];
|
||||||
|
treePtr = left[treePtr]; // go to left node
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
58
src/com/bytezone/diskbrowser/wizardry/MessageBlock.java
Normal file
58
src/com/bytezone/diskbrowser/wizardry/MessageBlock.java
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
package com.bytezone.diskbrowser.wizardry;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.bytezone.common.Utility;
|
||||||
|
|
||||||
|
public class MessageBlock
|
||||||
|
{
|
||||||
|
private final byte[] buffer;
|
||||||
|
private final int indexOffset;
|
||||||
|
private final int indexLength;
|
||||||
|
|
||||||
|
private final List<MessageDataBlock> messageDataBlocks =
|
||||||
|
new ArrayList<MessageDataBlock> ();
|
||||||
|
|
||||||
|
public MessageBlock (byte[] buffer)
|
||||||
|
{
|
||||||
|
this.buffer = buffer;
|
||||||
|
|
||||||
|
indexOffset = Utility.getWord (buffer, 0);
|
||||||
|
indexLength = Utility.getWord (buffer, 2);
|
||||||
|
|
||||||
|
int ptr = indexOffset * 512;
|
||||||
|
|
||||||
|
for (int i = 0, max = indexLength / 2; i < max; i++)
|
||||||
|
{
|
||||||
|
int firstMessageNo = Utility.getWord (buffer, ptr + i * 2);
|
||||||
|
MessageDataBlock messageDataBlock =
|
||||||
|
new MessageDataBlock (buffer, i * 512, firstMessageNo);
|
||||||
|
messageDataBlocks.add (messageDataBlock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getMessage (int messageNo)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < messageDataBlocks.size (); i++)
|
||||||
|
{
|
||||||
|
MessageDataBlock messageDataBlock = messageDataBlocks.get (i);
|
||||||
|
if (messageDataBlock.firstMessageNo > messageNo)
|
||||||
|
return messageDataBlocks.get (i - 1).getMessage (messageNo);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// public int getBlock (int msgNo)
|
||||||
|
// {
|
||||||
|
// int ptr = indexOffset * 512;
|
||||||
|
//
|
||||||
|
// for (int i = 0; i < indexLength; i += 2)
|
||||||
|
// {
|
||||||
|
// int msg = Utility.getWord (buffer, ptr + i);
|
||||||
|
// if (msg > msgNo)
|
||||||
|
// return i - 1;
|
||||||
|
// }
|
||||||
|
// return indexLength - 1;
|
||||||
|
// }
|
||||||
|
}
|
130
src/com/bytezone/diskbrowser/wizardry/MessageDataBlock.java
Normal file
130
src/com/bytezone/diskbrowser/wizardry/MessageDataBlock.java
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
package com.bytezone.diskbrowser.wizardry;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.bytezone.common.Utility;
|
||||||
|
import com.bytezone.diskbrowser.utilities.HexFormatter;
|
||||||
|
|
||||||
|
public class MessageDataBlock
|
||||||
|
{
|
||||||
|
private final byte[] buffer;
|
||||||
|
private final int offset;
|
||||||
|
final int firstMessageNo;
|
||||||
|
|
||||||
|
private final int groupCount;
|
||||||
|
private final List<Message> messages = new ArrayList<Message> ();
|
||||||
|
|
||||||
|
public MessageDataBlock (byte[] buffer, int offset, int firstMessageNo)
|
||||||
|
{
|
||||||
|
this.buffer = buffer;
|
||||||
|
this.offset = offset;
|
||||||
|
this.firstMessageNo = firstMessageNo;
|
||||||
|
|
||||||
|
boolean debug = firstMessageNo == 0;
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
{
|
||||||
|
System.out.println (HexFormatter.format (buffer, offset, 512));
|
||||||
|
System.out.println ();
|
||||||
|
}
|
||||||
|
|
||||||
|
int ptr = offset + 0x1FF; // last byte in block
|
||||||
|
groupCount = buffer[ptr--] & 0xFF;
|
||||||
|
|
||||||
|
int currentMessageNo = firstMessageNo;
|
||||||
|
int totalMessageBytes = 0;
|
||||||
|
|
||||||
|
for (int i = 0, max = groupCount - 1; i < groupCount; i++, max--)
|
||||||
|
{
|
||||||
|
int huffBytes = buffer[ptr];
|
||||||
|
|
||||||
|
for (int j = 0; j < huffBytes; j++)
|
||||||
|
{
|
||||||
|
int messageLength = buffer[ptr - j - 1] & 0xFF;
|
||||||
|
totalMessageBytes += messageLength;
|
||||||
|
Message message = new Message (currentMessageNo + j,
|
||||||
|
offset + totalMessageBytes - messageLength, messageLength);
|
||||||
|
messages.add (message);
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr -= huffBytes;
|
||||||
|
currentMessageNo += huffBytes;
|
||||||
|
|
||||||
|
ptr--;
|
||||||
|
|
||||||
|
if (max > 0)
|
||||||
|
{
|
||||||
|
byte gap = buffer[ptr--];
|
||||||
|
int skip = gap & 0xFF;
|
||||||
|
|
||||||
|
if ((gap & 0x80) != 0) // is high bit set?
|
||||||
|
{
|
||||||
|
gap &= 0x7F;
|
||||||
|
int gap2 = buffer[ptr--] & 0xFF;
|
||||||
|
skip = gap * 256 + gap2;
|
||||||
|
}
|
||||||
|
|
||||||
|
skip--;
|
||||||
|
currentMessageNo += skip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
System.out.println (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] getMessage (int messageNo)
|
||||||
|
{
|
||||||
|
for (Message message : messages)
|
||||||
|
if (message.msgNo == messageNo)
|
||||||
|
{
|
||||||
|
byte[] returnMessage = new byte[message.length];
|
||||||
|
System.arraycopy (buffer, message.offset, returnMessage, 0, message.length);
|
||||||
|
return returnMessage;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString ()
|
||||||
|
{
|
||||||
|
StringBuilder text = new StringBuilder ();
|
||||||
|
|
||||||
|
for (Message message : messages)
|
||||||
|
{
|
||||||
|
text.append (message);
|
||||||
|
text.append ("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (text.length () > 0)
|
||||||
|
text.deleteCharAt (text.length () - 1);
|
||||||
|
|
||||||
|
return text.toString ();
|
||||||
|
}
|
||||||
|
|
||||||
|
class Message
|
||||||
|
{
|
||||||
|
final int msgNo;
|
||||||
|
final int offset;
|
||||||
|
final int length;
|
||||||
|
|
||||||
|
public Message (int msgNo, int offset, int length)
|
||||||
|
{
|
||||||
|
this.msgNo = msgNo;
|
||||||
|
this.offset = offset;
|
||||||
|
this.length = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString ()
|
||||||
|
{
|
||||||
|
StringBuilder text = new StringBuilder ();
|
||||||
|
|
||||||
|
String data = Utility.getHex (buffer, offset, length);
|
||||||
|
text.append (String.format ("%5d: %02X %02X : %s", msgNo, offset, length, data));
|
||||||
|
|
||||||
|
return text.toString ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -11,16 +11,18 @@ import com.bytezone.diskbrowser.disk.AppleDisk;
|
|||||||
import com.bytezone.diskbrowser.disk.DefaultAppleFileSource;
|
import com.bytezone.diskbrowser.disk.DefaultAppleFileSource;
|
||||||
import com.bytezone.diskbrowser.disk.Disk;
|
import com.bytezone.diskbrowser.disk.Disk;
|
||||||
import com.bytezone.diskbrowser.disk.DiskAddress;
|
import com.bytezone.diskbrowser.disk.DiskAddress;
|
||||||
import com.bytezone.diskbrowser.disk.SectorType;
|
|
||||||
import com.bytezone.diskbrowser.pascal.FileEntry;
|
import com.bytezone.diskbrowser.pascal.FileEntry;
|
||||||
import com.bytezone.diskbrowser.pascal.PascalDisk;
|
import com.bytezone.diskbrowser.pascal.PascalDisk;
|
||||||
import com.bytezone.diskbrowser.utilities.Utility;
|
import com.bytezone.diskbrowser.utilities.Utility;
|
||||||
|
import com.bytezone.diskbrowser.wizardry.Header.ScenarioData;
|
||||||
|
|
||||||
public class Wizardry4BootDisk extends PascalDisk
|
public class Wizardry4BootDisk extends PascalDisk
|
||||||
{
|
{
|
||||||
|
public Header scenarioHeader;
|
||||||
List<AppleDisk> disks = new ArrayList<AppleDisk> ();
|
List<AppleDisk> disks = new ArrayList<AppleDisk> ();
|
||||||
// protected Disk[] dataDisks;
|
// protected Disk[] dataDisks;
|
||||||
private Relocator relocator;
|
private Relocator relocator;
|
||||||
|
private MessageBlock messageBlock;
|
||||||
|
|
||||||
public Wizardry4BootDisk (AppleDisk[] dataDisks)
|
public Wizardry4BootDisk (AppleDisk[] dataDisks)
|
||||||
{
|
{
|
||||||
@ -34,7 +36,6 @@ public class Wizardry4BootDisk extends PascalDisk
|
|||||||
// get the relocation table
|
// get the relocation table
|
||||||
DefaultMutableTreeNode relocNode = findNode (currentRoot, "SYSTEM.RELOC");
|
DefaultMutableTreeNode relocNode = findNode (currentRoot, "SYSTEM.RELOC");
|
||||||
FileEntry fileEntry = (FileEntry) relocNode.getUserObject ();
|
FileEntry fileEntry = (FileEntry) relocNode.getUserObject ();
|
||||||
|
|
||||||
if (fileEntry != null)
|
if (fileEntry != null)
|
||||||
{
|
{
|
||||||
relocator =
|
relocator =
|
||||||
@ -46,7 +47,6 @@ public class Wizardry4BootDisk extends PascalDisk
|
|||||||
// reset the code segment so that it rebuilds itself from the new data
|
// reset the code segment so that it rebuilds itself from the new data
|
||||||
DefaultMutableTreeNode pascalNode = findNode (currentRoot, "SYSTEM.PASCAL");
|
DefaultMutableTreeNode pascalNode = findNode (currentRoot, "SYSTEM.PASCAL");
|
||||||
fileEntry = (FileEntry) pascalNode.getUserObject ();
|
fileEntry = (FileEntry) pascalNode.getUserObject ();
|
||||||
|
|
||||||
if (fileEntry != null)
|
if (fileEntry != null)
|
||||||
{
|
{
|
||||||
fileEntry.setFile (null);
|
fileEntry.setFile (null);
|
||||||
@ -55,54 +55,99 @@ public class Wizardry4BootDisk extends PascalDisk
|
|||||||
|
|
||||||
DefaultMutableTreeNode scenarioNode = findNode (currentRoot, "SCENARIO.DATA");
|
DefaultMutableTreeNode scenarioNode = findNode (currentRoot, "SCENARIO.DATA");
|
||||||
fileEntry = (FileEntry) scenarioNode.getUserObject ();
|
fileEntry = (FileEntry) scenarioNode.getUserObject ();
|
||||||
|
|
||||||
if (fileEntry != null)
|
if (fileEntry != null)
|
||||||
{
|
{
|
||||||
fileEntry.setFile (null);
|
fileEntry.setFile (null);
|
||||||
|
|
||||||
scenarioNode.setAllowsChildren (true);
|
scenarioNode.setAllowsChildren (true);
|
||||||
|
scenarioHeader = new Header (scenarioNode, this);
|
||||||
byte[] buffer = fileEntry.getDataSource ().buffer;
|
linkMazeLevels (scenarioNode, fileEntry);
|
||||||
|
|
||||||
for (int i = 0; i < 14; i++)
|
|
||||||
{
|
|
||||||
byte[] level = new byte[896];
|
|
||||||
// System.out.println (HexFormatter.format (buffer, 0, 512));
|
|
||||||
System.arraycopy (buffer, 0xC600 + i * 1024, level, 0, level.length);
|
|
||||||
MazeLevel maze = new MazeLevel (level, i);
|
|
||||||
|
|
||||||
List<DiskAddress> blocks = new ArrayList<DiskAddress> ();
|
|
||||||
addToNode (maze, scenarioNode, blocks, null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DefaultMutableTreeNode monstersNode = findNode (currentRoot, "200.MONSTERS");
|
DefaultMutableTreeNode monstersNode = findNode (currentRoot, "200.MONSTERS");
|
||||||
fileEntry = (FileEntry) monstersNode.getUserObject ();
|
fileEntry = (FileEntry) monstersNode.getUserObject ();
|
||||||
|
|
||||||
if (fileEntry != null)
|
if (fileEntry != null)
|
||||||
{
|
{
|
||||||
monstersNode.setAllowsChildren (true);
|
fileEntry.setFile (null);
|
||||||
byte[] pictureBuffer = fileEntry.getDataSource ().buffer;
|
|
||||||
List<DiskAddress> pictureBlocks = fileEntry.getSectors ();
|
|
||||||
|
|
||||||
int count = 0;
|
monstersNode.setAllowsChildren (true);
|
||||||
loop: for (int block = 0; block < 24; block++)
|
linkMonsterImages (monstersNode, fileEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
DefaultMutableTreeNode messagesNode = findNode (currentRoot, "ASCII.KRN");
|
||||||
|
fileEntry = (FileEntry) messagesNode.getUserObject ();
|
||||||
|
if (fileEntry != null)
|
||||||
|
{
|
||||||
|
messageBlock = new MessageBlock (fileEntry.getDataSource ().buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
DefaultMutableTreeNode huffNode = findNode (currentRoot, "ASCII.HUFF");
|
||||||
|
fileEntry = (FileEntry) huffNode.getUserObject ();
|
||||||
|
if (fileEntry != null)
|
||||||
|
{
|
||||||
|
// byte[] tree = new byte[256];
|
||||||
|
// byte[] left = new byte[256];
|
||||||
|
// byte[] right = new byte[256];
|
||||||
|
|
||||||
|
byte[] buffer = fileEntry.getDataSource ().buffer;
|
||||||
|
|
||||||
|
// System.arraycopy (buffer, 0, tree, 0, 256);
|
||||||
|
// System.arraycopy (buffer, 256, left, 0, 256);
|
||||||
|
// System.arraycopy (buffer, 512, right, 0, 256);
|
||||||
|
Huffman huffman = new Huffman (buffer);
|
||||||
|
|
||||||
|
System.out.println (huffman.getMessage (messageBlock.getMessage (2043)));
|
||||||
|
System.out.println (huffman.getMessage (messageBlock.getMessage (2044)));
|
||||||
|
System.out.println (huffman.getMessage (messageBlock.getMessage (2045)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void linkMazeLevels (DefaultMutableTreeNode scenarioNode, FileEntry fileEntry)
|
||||||
|
{
|
||||||
|
ScenarioData mazeData = scenarioHeader.data.get (Header.MAZE_AREA);
|
||||||
|
|
||||||
|
byte[] buffer = fileEntry.getDataSource ().buffer;
|
||||||
|
List<DiskAddress> blocks = fileEntry.getSectors ();
|
||||||
|
|
||||||
|
DefaultMutableTreeNode mazeNode = linkNode ("Maze", "Levels string", scenarioNode);
|
||||||
|
for (int i = 0; i < 15; i++)
|
||||||
|
{
|
||||||
|
byte[] level = new byte[896];
|
||||||
|
System.arraycopy (buffer, mazeData.dataOffset * 512 + i * 1024, level, 0,
|
||||||
|
level.length);
|
||||||
|
|
||||||
|
List<DiskAddress> mazeBlocks = new ArrayList<DiskAddress> ();
|
||||||
|
int ptr = mazeData.dataOffset + i * 2;
|
||||||
|
mazeBlocks.add (blocks.get (ptr));
|
||||||
|
mazeBlocks.add (blocks.get (ptr + 1));
|
||||||
|
addToNode (new MazeLevel (level, i), mazeNode, mazeBlocks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void linkMonsterImages (DefaultMutableTreeNode monstersNode,
|
||||||
|
FileEntry fileEntry)
|
||||||
|
{
|
||||||
|
byte[] pictureBuffer = fileEntry.getDataSource ().buffer;
|
||||||
|
List<DiskAddress> pictureBlocks = fileEntry.getSectors ();
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
for (int block = 0; block < 24; block++)
|
||||||
|
{
|
||||||
|
int ptr = block * 512;
|
||||||
|
for (int pic = 0; pic < 2; pic++)
|
||||||
{
|
{
|
||||||
int ptr = block * 512;
|
byte[] buffer = new byte[240];
|
||||||
for (int pic = 0; pic < 2; pic++)
|
System.arraycopy (pictureBuffer, ptr + pic * 256, buffer, 0, 240);
|
||||||
{
|
Wiz4Image image = new Wiz4Image ("Image " + count++, buffer);
|
||||||
byte[] buffer = new byte[240];
|
List<DiskAddress> monsterBlocks = new ArrayList<DiskAddress> ();
|
||||||
System.arraycopy (pictureBuffer, ptr + pic * 256, buffer, 0, 240);
|
monsterBlocks.add (pictureBlocks.get (block));
|
||||||
Wiz4Image image = new Wiz4Image ("Image " + count++, buffer);
|
addToNode (image, monstersNode, monsterBlocks);
|
||||||
List<DiskAddress> blocks = new ArrayList<DiskAddress> ();
|
|
||||||
blocks.add (pictureBlocks.get (block));
|
|
||||||
addToNode (image, monstersNode, blocks, null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addToNode (AbstractFile af, DefaultMutableTreeNode node,
|
private void addToNode (AbstractFile af, DefaultMutableTreeNode node,
|
||||||
List<DiskAddress> blocks, SectorType type)
|
List<DiskAddress> blocks)
|
||||||
{
|
{
|
||||||
DefaultAppleFileSource dafs =
|
DefaultAppleFileSource dafs =
|
||||||
new DefaultAppleFileSource (af.getName (), af, this, blocks);
|
new DefaultAppleFileSource (af.getName (), af, this, blocks);
|
||||||
@ -111,6 +156,15 @@ public class Wizardry4BootDisk extends PascalDisk
|
|||||||
childNode.setAllowsChildren (false);
|
childNode.setAllowsChildren (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private DefaultMutableTreeNode linkNode (String name, String text,
|
||||||
|
DefaultMutableTreeNode parent)
|
||||||
|
{
|
||||||
|
DefaultAppleFileSource afs = new DefaultAppleFileSource (name, text, this);
|
||||||
|
DefaultMutableTreeNode node = new DefaultMutableTreeNode (afs);
|
||||||
|
parent.add (node);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean isWizardryIVorV (Disk disk, boolean debug)
|
public static boolean isWizardryIVorV (Disk disk, boolean debug)
|
||||||
{
|
{
|
||||||
// Wizardry IV or V boot code
|
// Wizardry IV or V boot code
|
||||||
|
@ -488,12 +488,12 @@ public class WizardryScenarioDisk extends PascalDisk
|
|||||||
System.arraycopy (buffer, 0, data2, 0, data2.length);
|
System.arraycopy (buffer, 0, data2, 0, data2.length);
|
||||||
// System.out.println (HexFormatter.format (data2));
|
// System.out.println (HexFormatter.format (data2));
|
||||||
|
|
||||||
MazeLevel model = new MazeLevel (data2, i + 1);
|
MazeLevel mazeLevel = new MazeLevel (data2, i + 1);
|
||||||
model.setMessages (messages);
|
mazeLevel.setMessages (messages);
|
||||||
model.setMonsters (monsters);
|
mazeLevel.setMonsters (monsters);
|
||||||
model.setItems (items);
|
mazeLevel.setItems (items);
|
||||||
levels.add (model);
|
levels.add (mazeLevel);
|
||||||
addToNode (model, node, blocks, mazeSector);
|
addToNode (mazeLevel, node, blocks, mazeSector);
|
||||||
}
|
}
|
||||||
|
|
||||||
StringBuilder text = new StringBuilder ();
|
StringBuilder text = new StringBuilder ();
|
||||||
|
Loading…
Reference in New Issue
Block a user