package com.bytezone.diskbrowser.wizardry; import java.util.ArrayList; import java.util.List; import javax.swing.tree.DefaultMutableTreeNode; import com.bytezone.diskbrowser.applefile.AppleFileSource; import com.bytezone.diskbrowser.applefile.DefaultAppleFile; import com.bytezone.diskbrowser.disk.DefaultAppleFileSource; import com.bytezone.diskbrowser.disk.DiskAddress; import com.bytezone.diskbrowser.disk.FormattedDisk; import com.bytezone.diskbrowser.utilities.HexFormatter; class Header { static String[] typeText = { "header", "maze", "monsters", "rewards", "items", "characters", "images", "char levels" }; static String[] scenarioNames = { "PROVING GROUNDS OF THE MAD OVERLORD!", "THE KNIGHT OF DIAMONDS", "THE LEGACY OF LLYLGAMYN" }; static final int MAZE_AREA = 1; static final int MONSTER_AREA = 2; static final int TREASURE_TABLE_AREA = 3; static final int ITEM_AREA = 4; static final int CHARACTER_AREA = 5; static final int IMAGE_AREA = 6; static final int EXPERIENCE_AREA = 7; String scenarioTitle; public int scenarioID; List data = new ArrayList (8); FormattedDisk owner; public Header (DefaultMutableTreeNode dataNode, FormattedDisk owner) { this.owner = owner; AppleFileSource afs = (AppleFileSource) dataNode.getUserObject (); List sectors = afs.getSectors (); DefaultAppleFile daf = (DefaultAppleFile) afs.getDataSource (); scenarioTitle = HexFormatter.getPascalString (daf.buffer, 0); while (scenarioID < scenarioNames.length) if (scenarioNames[scenarioID++].equals (scenarioTitle)) break; assert (scenarioID <= scenarioNames.length) : "Invalid scenario ID : " + scenarioID; for (int i = 0; i < 8; i++) data.add (new ScenarioData (daf.buffer, i, sectors)); StringBuilder text = new StringBuilder ("Data type Offset Size Units ???\n" + "------------ ------ ----- ----- -----\n"); for (ScenarioData sd : data) text.append (sd + "\n"); daf.setText (text.toString ()); text = new StringBuilder (scenarioTitle + "\n\n"); int ptr = 106; while (daf.buffer[ptr] != -1) { text.append (HexFormatter.getPascalString (daf.buffer, ptr) + "\n"); ptr += 10; } DefaultAppleFileSource dafs = new DefaultAppleFileSource ("Header", text.toString (), owner); dafs.setSectors (data.get (0).sectors); DefaultMutableTreeNode headerNode = new DefaultMutableTreeNode (dafs); dataNode.add (headerNode); int totalBlocks = data.get (0).sectors.size (); linkText ("Text", data.get (0).sectors.get (0), headerNode); 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); } 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) { System.out.println (printChars (daf.buffer, 1)); System.out.println (printChars (daf.buffer, 2)); } } private void linkText (String title, DiskAddress da, DefaultMutableTreeNode headerNode) { List blocks = new ArrayList (); blocks.add (da); StringBuilder text = new StringBuilder (scenarioTitle + "\n\n"); int ptr = 106; byte[] buffer = owner.getDisk ().readSector (da); 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); dafs.setSectors (blocks); DefaultMutableTreeNode node = new DefaultMutableTreeNode (dafs); node.setAllowsChildren (false); headerNode.add (node); } private void linkPictures (String title, DiskAddress da, DefaultMutableTreeNode headerNode) { List blocks = new ArrayList (); blocks.add (da); byte[] buffer = owner.getDisk ().readSector (da); String text = printChars (buffer, 0); DefaultAppleFileSource dafs = new DefaultAppleFileSource (title, text, owner); dafs.setSectors (blocks); DefaultMutableTreeNode node = new DefaultMutableTreeNode (dafs); node.setAllowsChildren (false); headerNode.add (node); } private void linkSpells (String title, DiskAddress da, DefaultMutableTreeNode headerNode) { List blocks = new ArrayList (); blocks.add (da); int level = 1; StringBuilder list = new StringBuilder ("Level " + level + ":\n"); byte[] buffer = owner.getDisk ().readSector (da); String text = HexFormatter.getString (buffer, 0, 512); String[] spells = text.split ("\n"); for (String s : spells) { 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); dafs.setSectors (blocks); DefaultMutableTreeNode node = new DefaultMutableTreeNode (dafs); node.setAllowsChildren (false); headerNode.add (node); } private String printChars (byte[] buffer, int block) { StringBuilder text = new StringBuilder (); for (int i = block * 512; i < (block + 1) * 512; i += 64) { 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 sectors; public ScenarioData (byte[] buffer, int seq, List 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 (totalBlocks); for (int i = dataOffset, max = dataOffset + totalBlocks; i < max; i++) this.sectors.add (sectors.get (i)); } @Override public String toString () { return String.format ("%-15s %3d %3d %3d %3d", typeText[type], dataOffset, totalBlocks, total, dunno); } } }