diff --git a/src/com/bytezone/diskbrowser/wizardry/AbstractImage.java b/src/com/bytezone/diskbrowser/wizardry/AbstractImage.java index 148cc49..d82c488 100755 --- a/src/com/bytezone/diskbrowser/wizardry/AbstractImage.java +++ b/src/com/bytezone/diskbrowser/wizardry/AbstractImage.java @@ -1,11 +1,15 @@ -package com.bytezone.diskbrowser.wizardry; - -import com.bytezone.diskbrowser.applefile.AbstractFile; - -public abstract class AbstractImage extends AbstractFile -{ - public AbstractImage (String name, byte[] buffer) - { - super (name, buffer); - } +package com.bytezone.diskbrowser.wizardry; + +import com.bytezone.diskbrowser.applefile.AbstractFile; + +// -----------------------------------------------------------------------------------// +abstract class AbstractImage extends AbstractFile +// -----------------------------------------------------------------------------------// +{ + // ---------------------------------------------------------------------------------// + AbstractImage (String name, byte[] buffer) + // ---------------------------------------------------------------------------------// + { + super (name, buffer); + } } \ No newline at end of file diff --git a/src/com/bytezone/diskbrowser/wizardry/Character.java b/src/com/bytezone/diskbrowser/wizardry/Character.java index 1da21bb..6e2d44b 100755 --- a/src/com/bytezone/diskbrowser/wizardry/Character.java +++ b/src/com/bytezone/diskbrowser/wizardry/Character.java @@ -1,325 +1,367 @@ -package com.bytezone.diskbrowser.wizardry; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; - -import com.bytezone.diskbrowser.applefile.AbstractFile; -import com.bytezone.diskbrowser.utilities.HexFormatter; - -class Character extends AbstractFile -{ - private final Attributes attributes; - private final Statistics stats; - int scenario; - - private final Collection spellBook = new ArrayList<> (); - private final Collection baggageList = new ArrayList<> (); - - 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" }; - - public Character (String name, byte[] buffer, int scenario) - { - super (name, buffer); - this.scenario = scenario; - - attributes = new Attributes (); - stats = new Statistics (); - - stats.race = races[buffer[34] & 0xFF]; - stats.typeInt = buffer[36] & 0xFF; - stats.type = types[stats.typeInt]; - stats.ageInWeeks = HexFormatter.intValue (buffer[38], buffer[39]); - stats.statusValue = buffer[40]; - stats.status = statuses[stats.statusValue]; - stats.alignment = alignments[buffer[42] & 0xFF]; - - stats.gold = HexFormatter.intValue (buffer[52], buffer[53]) - + HexFormatter.intValue (buffer[54], buffer[55]) * 10000; - stats.experience = HexFormatter.intValue (buffer[124], buffer[125]) - + HexFormatter.intValue (buffer[126], buffer[127]) * 10000; - stats.level = HexFormatter.intValue (buffer[132], buffer[133]); - - stats.hitsLeft = HexFormatter.intValue (buffer[134], buffer[135]); - stats.hitsMax = HexFormatter.intValue (buffer[136], buffer[137]); - stats.armourClass = buffer[176]; - - attributes.strength = (buffer[44] & 0xFF) % 16; - if (attributes.strength < 3) - attributes.strength += 16; - attributes.array[0] = attributes.strength; - - int i1 = (buffer[44] & 0xFF) / 16; - int i2 = (buffer[45] & 0xFF) % 4; - attributes.intelligence = i1 / 2 + i2 * 8; - attributes.array[1] = attributes.intelligence; - - attributes.piety = (buffer[45] & 0xFF) / 4; - attributes.array[2] = attributes.piety; - - attributes.vitality = (buffer[46] & 0xFF) % 16; - if (attributes.vitality < 3) - attributes.vitality += 16; - attributes.array[3] = attributes.vitality; - - int a1 = (buffer[46] & 0xFF) / 16; - int a2 = (buffer[47] & 0xFF) % 4; - attributes.agility = a1 / 2 + a2 * 8; - attributes.array[4] = attributes.agility; - - attributes.luck = (buffer[47] & 0xFF) / 4; - attributes.array[5] = attributes.luck; - } - - public void linkItems (List itemList) - { - boolean equipped; - boolean identified; - int totItems = buffer[58]; - stats.assetValue = 0; - - for (int ptr = 60; totItems > 0; ptr += 8, totItems--) - { - 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 (name + " ItemID : " + itemID + " is outside range 0:" - + (itemList.size () - 1)); - } - } - - public void linkSpells (List spellList) - { - for (int i = 138; i < 145; i++) - for (int bit = 0; bit < 8; bit++) - if (((buffer[i] >>> bit) & 1) == 1) - { - int index = (i - 138) * 8 + bit; - if (index > 0 && index <= spellList.size ()) - spellBook.add (spellList.get (index - 1)); - else - System.out.println ("LinkSpell: " + name + " SpellID : " + index - + " is outside range 1:" + spellList.size ()); - } - } - - @Override - public String getText () - { - StringBuilder text = new StringBuilder (); - - text.append ("Character name ..... " + name); - text.append ("\n\nRace ............... " + stats.race); - text.append ("\nType ............... " + stats.type); - text.append ("\nAlignment .......... " + stats.alignment); - text.append ("\nStatus ............. " + stats.status); - // text.append ("\nType ............... " + stats.typeInt); - // text.append ("\nStatus ............. " + stats.statusValue); - text.append ("\nGold ............... " + String.format ("%,d", stats.gold)); - text.append ("\nExperience ......... " + String.format ("%,d", stats.experience)); - text.append ("\nNext level ......... " + String.format ("%,d", stats.nextLevel)); - text.append ("\nLevel .............. " + stats.level); - text.append ("\nAge in weeks ....... " - + String.format ("%,d (%d)", stats.ageInWeeks, (stats.ageInWeeks / 52))); - text.append ("\nHit points left .... " + stats.hitsLeft); - text.append ("\nMaximum hits ....... " + stats.hitsMax); - text.append ("\nArmour class ....... " + stats.armourClass); - text.append ("\nAsset value ........ " + String.format ("%,d", stats.assetValue)); - text.append ("\nAwards ............. " + isWinner ()); - text.append ("\nOut ................ " + isOut ()); - text.append ("\n\nStrength ........... " + attributes.strength); - text.append ("\nIntelligence ....... " + attributes.intelligence); - text.append ("\nPiety .............. " + attributes.piety); - text.append ("\nVitality ........... " + attributes.vitality); - text.append ("\nAgility ............ " + attributes.agility); - text.append ("\nLuck ............... " + attributes.luck); - - int[] spellPoints = getMageSpellPoints (); - text.append ("\n\nMage spell points .."); - for (int i = 0; i < spellPoints.length; i++) - text.append (" " + spellPoints[i]); - - spellPoints = getPriestSpellPoints (); - text.append ("\nPriest spell points "); - for (int i = 0; i < spellPoints.length; i++) - text.append (" " + spellPoints[i]); - - text.append ("\n\nSpells :"); - for (Spell s : spellBook) - text.append ("\n" + s); - - text.append ("\n\nItems :"); - for (Baggage b : baggageList) - text.append ("\n" + b); - - return text.toString (); - } - - public void linkExperience (ExperienceLevel exp) - { - stats.nextLevel = exp.getExperiencePoints (stats.level); - } - - public int[] getMageSpellPoints () - { - int[] spells = new int[7]; - - for (int i = 0; i < 7; i++) - spells[i] = buffer[146 + i * 2]; - - return spells; - } - - public int[] getPriestSpellPoints () - { - int[] spells = new int[7]; - - for (int i = 0; i < 7; i++) - spells[i] = buffer[160 + i * 2]; - - return spells; - } - - public Long getNextLevel () - { - return stats.nextLevel; - } - - // this is temporary until I have more data - public String isWinner () - { - int v1 = buffer[206]; - int v2 = buffer[207]; - if (v1 == 0x01) - return ">"; - if (v1 == 0x00 && v2 == 0x00) - return ""; - if (v1 == 0x00 && v2 == 0x20) - return "D"; - if (v1 == 0x20 && v2 == 0x20) - return "*D"; - if (v1 == 0x21 && v2 == 0x60) - return ">*DG"; - if (v1 == 0x21 && v2 == 0x28) - return ">*KD"; - return "Unknown : " + v1 + " " + v2; - } - - public boolean isOut () - { - return (buffer[32] == 1); - } - - public String getType () - { - return stats.type; - } - - public String getRace () - { - return stats.race; - } - - public String getAlignment () - { - return stats.alignment; - } - - public Attributes getAttributes () - { - return attributes; - } - - public Statistics getStatistics () - { - return stats; - } - - public Iterator getBaggage () - { - return baggageList.iterator (); - } - - public Iterator getSpells () - { - return spellBook.iterator (); - } - - @Override - public String toString () - { - return name; - } - - public class Baggage - { - public Item item; - public boolean equipped; - public boolean identified; - - public Baggage (Item item, boolean equipped, boolean identified) - { - this.item = item; - this.equipped = equipped; - this.identified = identified; - } - - @Override - public String toString () - { - return String.format ("%s%-15s (%d)", equipped ? "*" : " ", item.getName (), - item.getCost ()); - } - } - - public class Statistics implements Cloneable - { - public String race; - public String type; - public String alignment; - public String status; - public int typeInt; - public int statusValue; - public int gold; - public int experience; - public long nextLevel; - public int level; - public int ageInWeeks; - public int hitsLeft; - public int hitsMax; - public int armourClass; - public int assetValue; - } - - public class Attributes - { - public int strength; - public int intelligence; - public int piety; - public int vitality; - public int agility; - public int luck; - public int[] array; - - public Attributes () - { - array = new int[6]; - } - } +package com.bytezone.diskbrowser.wizardry; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import com.bytezone.diskbrowser.applefile.AbstractFile; +import com.bytezone.diskbrowser.utilities.HexFormatter; + +// -----------------------------------------------------------------------------------// +class Character extends AbstractFile +// -----------------------------------------------------------------------------------// +{ + private final Attributes attributes; + private final Statistics stats; + int scenario; + + private final Collection spellBook = new ArrayList<> (); + private final Collection baggageList = new ArrayList<> (); + + 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" }; + + // ---------------------------------------------------------------------------------// + Character (String name, byte[] buffer, int scenario) + // ---------------------------------------------------------------------------------// + { + super (name, buffer); + this.scenario = scenario; + + attributes = new Attributes (); + stats = new Statistics (); + + stats.race = races[buffer[34] & 0xFF]; + stats.typeInt = buffer[36] & 0xFF; + stats.type = types[stats.typeInt]; + stats.ageInWeeks = HexFormatter.intValue (buffer[38], buffer[39]); + stats.statusValue = buffer[40]; + stats.status = statuses[stats.statusValue]; + stats.alignment = alignments[buffer[42] & 0xFF]; + + stats.gold = HexFormatter.intValue (buffer[52], buffer[53]) + + HexFormatter.intValue (buffer[54], buffer[55]) * 10000; + stats.experience = HexFormatter.intValue (buffer[124], buffer[125]) + + HexFormatter.intValue (buffer[126], buffer[127]) * 10000; + stats.level = HexFormatter.intValue (buffer[132], buffer[133]); + + stats.hitsLeft = HexFormatter.intValue (buffer[134], buffer[135]); + stats.hitsMax = HexFormatter.intValue (buffer[136], buffer[137]); + stats.armourClass = buffer[176]; + + attributes.strength = (buffer[44] & 0xFF) % 16; + if (attributes.strength < 3) + attributes.strength += 16; + attributes.array[0] = attributes.strength; + + int i1 = (buffer[44] & 0xFF) / 16; + int i2 = (buffer[45] & 0xFF) % 4; + attributes.intelligence = i1 / 2 + i2 * 8; + attributes.array[1] = attributes.intelligence; + + attributes.piety = (buffer[45] & 0xFF) / 4; + attributes.array[2] = attributes.piety; + + attributes.vitality = (buffer[46] & 0xFF) % 16; + if (attributes.vitality < 3) + attributes.vitality += 16; + attributes.array[3] = attributes.vitality; + + int a1 = (buffer[46] & 0xFF) / 16; + int a2 = (buffer[47] & 0xFF) % 4; + attributes.agility = a1 / 2 + a2 * 8; + attributes.array[4] = attributes.agility; + + attributes.luck = (buffer[47] & 0xFF) / 4; + attributes.array[5] = attributes.luck; + } + + // ---------------------------------------------------------------------------------// + public void linkItems (List itemList) + // ---------------------------------------------------------------------------------// + { + boolean equipped; + boolean identified; + int totItems = buffer[58]; + stats.assetValue = 0; + + for (int ptr = 60; totItems > 0; ptr += 8, totItems--) + { + 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 (name + " ItemID : " + itemID + " is outside range 0:" + + (itemList.size () - 1)); + } + } + + // ---------------------------------------------------------------------------------// + public void linkSpells (List spellList) + // ---------------------------------------------------------------------------------// + { + for (int i = 138; i < 145; i++) + for (int bit = 0; bit < 8; bit++) + if (((buffer[i] >>> bit) & 1) == 1) + { + int index = (i - 138) * 8 + bit; + if (index > 0 && index <= spellList.size ()) + spellBook.add (spellList.get (index - 1)); + else + System.out.println ("LinkSpell: " + name + " SpellID : " + index + + " is outside range 1:" + spellList.size ()); + } + } + + // ---------------------------------------------------------------------------------// + @Override + public String getText () + // ---------------------------------------------------------------------------------// + { + StringBuilder text = new StringBuilder (); + + text.append ("Character name ..... " + name); + text.append ("\n\nRace ............... " + stats.race); + text.append ("\nType ............... " + stats.type); + text.append ("\nAlignment .......... " + stats.alignment); + text.append ("\nStatus ............. " + stats.status); + // text.append ("\nType ............... " + stats.typeInt); + // text.append ("\nStatus ............. " + stats.statusValue); + text.append ("\nGold ............... " + String.format ("%,d", stats.gold)); + text.append ("\nExperience ......... " + String.format ("%,d", stats.experience)); + text.append ("\nNext level ......... " + String.format ("%,d", stats.nextLevel)); + text.append ("\nLevel .............. " + stats.level); + text.append ("\nAge in weeks ....... " + + String.format ("%,d (%d)", stats.ageInWeeks, (stats.ageInWeeks / 52))); + text.append ("\nHit points left .... " + stats.hitsLeft); + text.append ("\nMaximum hits ....... " + stats.hitsMax); + text.append ("\nArmour class ....... " + stats.armourClass); + text.append ("\nAsset value ........ " + String.format ("%,d", stats.assetValue)); + text.append ("\nAwards ............. " + isWinner ()); + text.append ("\nOut ................ " + isOut ()); + text.append ("\n\nStrength ........... " + attributes.strength); + text.append ("\nIntelligence ....... " + attributes.intelligence); + text.append ("\nPiety .............. " + attributes.piety); + text.append ("\nVitality ........... " + attributes.vitality); + text.append ("\nAgility ............ " + attributes.agility); + text.append ("\nLuck ............... " + attributes.luck); + + int[] spellPoints = getMageSpellPoints (); + text.append ("\n\nMage spell points .."); + for (int i = 0; i < spellPoints.length; i++) + text.append (" " + spellPoints[i]); + + spellPoints = getPriestSpellPoints (); + text.append ("\nPriest spell points "); + for (int i = 0; i < spellPoints.length; i++) + text.append (" " + spellPoints[i]); + + text.append ("\n\nSpells :"); + for (Spell s : spellBook) + text.append ("\n" + s); + + text.append ("\n\nItems :"); + for (Baggage b : baggageList) + text.append ("\n" + b); + + return text.toString (); + } + + // ---------------------------------------------------------------------------------// + public void linkExperience (ExperienceLevel exp) + // ---------------------------------------------------------------------------------// + { + stats.nextLevel = exp.getExperiencePoints (stats.level); + } + + // ---------------------------------------------------------------------------------// + public int[] getMageSpellPoints () + // ---------------------------------------------------------------------------------// + { + int[] spells = new int[7]; + + for (int i = 0; i < 7; i++) + spells[i] = buffer[146 + i * 2]; + + return spells; + } + + // ---------------------------------------------------------------------------------// + public int[] getPriestSpellPoints () + // ---------------------------------------------------------------------------------// + { + int[] spells = new int[7]; + + for (int i = 0; i < 7; i++) + spells[i] = buffer[160 + i * 2]; + + return spells; + } + + // ---------------------------------------------------------------------------------// + public Long getNextLevel () + // ---------------------------------------------------------------------------------// + { + return stats.nextLevel; + } + + // this is temporary until I have more data + // ---------------------------------------------------------------------------------// + public String isWinner () + // ---------------------------------------------------------------------------------// + { + int v1 = buffer[206]; + int v2 = buffer[207]; + if (v1 == 0x01) + return ">"; + if (v1 == 0x00 && v2 == 0x00) + return ""; + if (v1 == 0x00 && v2 == 0x20) + return "D"; + if (v1 == 0x20 && v2 == 0x20) + return "*D"; + if (v1 == 0x21 && v2 == 0x60) + return ">*DG"; + if (v1 == 0x21 && v2 == 0x28) + return ">*KD"; + return "Unknown : " + v1 + " " + v2; + } + + // ---------------------------------------------------------------------------------// + public boolean isOut () + // ---------------------------------------------------------------------------------// + { + return (buffer[32] == 1); + } + + // ---------------------------------------------------------------------------------// + public String getType () + // ---------------------------------------------------------------------------------// + { + return stats.type; + } + + // ---------------------------------------------------------------------------------// + public String getRace () + // ---------------------------------------------------------------------------------// + { + return stats.race; + } + + // ---------------------------------------------------------------------------------// + public String getAlignment () + // ---------------------------------------------------------------------------------// + { + return stats.alignment; + } + + // ---------------------------------------------------------------------------------// + public Attributes getAttributes () + // ---------------------------------------------------------------------------------// + { + return attributes; + } + + // ---------------------------------------------------------------------------------// + public Statistics getStatistics () + // ---------------------------------------------------------------------------------// + { + return stats; + } + + // ---------------------------------------------------------------------------------// + public Iterator getBaggage () + // ---------------------------------------------------------------------------------// + { + return baggageList.iterator (); + } + + // ---------------------------------------------------------------------------------// + public Iterator getSpells () + // ---------------------------------------------------------------------------------// + { + return spellBook.iterator (); + } + + // ---------------------------------------------------------------------------------// + @Override + public String toString () + // ---------------------------------------------------------------------------------// + { + return name; + } + + // ---------------------------------------------------------------------------------// + public class Baggage + // ---------------------------------------------------------------------------------// + { + public Item item; + public boolean equipped; + public boolean identified; + + public Baggage (Item item, boolean equipped, boolean identified) + { + this.item = item; + this.equipped = equipped; + this.identified = identified; + } + + @Override + public String toString () + { + return String.format ("%s%-15s (%d)", equipped ? "*" : " ", item.getName (), + item.getCost ()); + } + } + + // ---------------------------------------------------------------------------------// + public class Statistics implements Cloneable + // ---------------------------------------------------------------------------------// + { + public String race; + public String type; + public String alignment; + public String status; + public int typeInt; + public int statusValue; + public int gold; + public int experience; + public long nextLevel; + public int level; + public int ageInWeeks; + public int hitsLeft; + public int hitsMax; + public int armourClass; + public int assetValue; + } + + public class Attributes + { + public int strength; + public int intelligence; + public int piety; + public int vitality; + public int agility; + public int luck; + public int[] array; + + public Attributes () + { + array = new int[6]; + } + } } \ No newline at end of file diff --git a/src/com/bytezone/diskbrowser/wizardry/CodedMessage.java b/src/com/bytezone/diskbrowser/wizardry/CodedMessage.java index 1ec9cb5..1a8eb7c 100755 --- a/src/com/bytezone/diskbrowser/wizardry/CodedMessage.java +++ b/src/com/bytezone/diskbrowser/wizardry/CodedMessage.java @@ -1,27 +1,33 @@ -package com.bytezone.diskbrowser.wizardry; - -import com.bytezone.diskbrowser.utilities.HexFormatter; - -class CodedMessage extends Message -{ - public static int codeOffset = 185; - - public CodedMessage (byte[] buffer) - { - super (buffer); - } - - @Override - protected String getLine (int offset) - { - int length = buffer[offset] & 0xFF; - byte[] translation = new byte[length]; - codeOffset--; - for (int j = 0; j < length; j++) - { - translation[j] = buffer[offset + 1 + j]; - translation[j] -= codeOffset - j * 3; - } - return HexFormatter.getString (translation, 0, length); - } +package com.bytezone.diskbrowser.wizardry; + +import com.bytezone.diskbrowser.utilities.HexFormatter; + +// -----------------------------------------------------------------------------------// +class CodedMessage extends Message +// -----------------------------------------------------------------------------------// +{ + public static int codeOffset = 185; + + // ---------------------------------------------------------------------------------// + CodedMessage (byte[] buffer) + // ---------------------------------------------------------------------------------// + { + super (buffer); + } + + // ---------------------------------------------------------------------------------// + @Override + protected String getLine (int offset) + // ---------------------------------------------------------------------------------// + { + int length = buffer[offset] & 0xFF; + byte[] translation = new byte[length]; + codeOffset--; + for (int j = 0; j < length; j++) + { + translation[j] = buffer[offset + 1 + j]; + translation[j] -= codeOffset - j * 3; + } + return HexFormatter.getString (translation, 0, length); + } } \ No newline at end of file diff --git a/src/com/bytezone/diskbrowser/wizardry/Dice.java b/src/com/bytezone/diskbrowser/wizardry/Dice.java index 67267c7..c544959 100755 --- a/src/com/bytezone/diskbrowser/wizardry/Dice.java +++ b/src/com/bytezone/diskbrowser/wizardry/Dice.java @@ -1,27 +1,33 @@ -package com.bytezone.diskbrowser.wizardry; - -class Dice -{ - int qty; - int sides; - int bonus; - - public Dice (byte[] buffer, int offset) - { - qty = buffer[offset]; - sides = buffer[offset + 2]; - bonus = buffer[offset + 4]; - } - - @Override - public String toString () - { - if (qty == 0) - return ""; - StringBuilder text = new StringBuilder (); - text.append (String.format ("%dd%d", qty, sides)); - if (bonus > 0) - text.append ("+" + bonus); - return text.toString (); - } +package com.bytezone.diskbrowser.wizardry; + +// -----------------------------------------------------------------------------------// +class Dice +// -----------------------------------------------------------------------------------// +{ + int qty; + int sides; + int bonus; + + // ---------------------------------------------------------------------------------// + Dice (byte[] buffer, int offset) + // ---------------------------------------------------------------------------------// + { + qty = buffer[offset]; + sides = buffer[offset + 2]; + bonus = buffer[offset + 4]; + } + + // ---------------------------------------------------------------------------------// + @Override + public String toString () + // ---------------------------------------------------------------------------------// + { + if (qty == 0) + return ""; + StringBuilder text = new StringBuilder (); + text.append (String.format ("%dd%d", qty, sides)); + if (bonus > 0) + text.append ("+" + bonus); + return text.toString (); + } } \ No newline at end of file diff --git a/src/com/bytezone/diskbrowser/wizardry/DragonData.java b/src/com/bytezone/diskbrowser/wizardry/DragonData.java index 44761e5..018c4d9 100644 --- a/src/com/bytezone/diskbrowser/wizardry/DragonData.java +++ b/src/com/bytezone/diskbrowser/wizardry/DragonData.java @@ -2,15 +2,21 @@ package com.bytezone.diskbrowser.wizardry; import com.bytezone.diskbrowser.applefile.AbstractFile; -public class DragonData extends AbstractFile +// -----------------------------------------------------------------------------------// +class DragonData extends AbstractFile +// -----------------------------------------------------------------------------------// { - public DragonData (String name, byte[] buffer) + // ---------------------------------------------------------------------------------// + DragonData (String name, byte[] buffer) + // ---------------------------------------------------------------------------------// { super (name, buffer); } + // ---------------------------------------------------------------------------------// @Override public String getText () + // ---------------------------------------------------------------------------------// { return "DragonData"; } diff --git a/src/com/bytezone/diskbrowser/wizardry/ExperienceLevel.java b/src/com/bytezone/diskbrowser/wizardry/ExperienceLevel.java index dc8bcf2..349b479 100755 --- a/src/com/bytezone/diskbrowser/wizardry/ExperienceLevel.java +++ b/src/com/bytezone/diskbrowser/wizardry/ExperienceLevel.java @@ -1,44 +1,51 @@ -package com.bytezone.diskbrowser.wizardry; - -import com.bytezone.diskbrowser.applefile.AbstractFile; -import com.bytezone.diskbrowser.utilities.HexFormatter; - -class ExperienceLevel extends AbstractFile -{ - private final long[] expLevels = new long[13]; - - public ExperienceLevel (String name, byte[] buffer) - { - super (name, buffer); - - int seq = 0; - - for (int ptr = 0; ptr < buffer.length; ptr += 6) - { - if (buffer[ptr] == 0) - break; - - long points = - HexFormatter.intValue (buffer[ptr], buffer[ptr + 1]) - + HexFormatter.intValue (buffer[ptr + 2], buffer[ptr + 3]) * 10000 - + HexFormatter.intValue (buffer[ptr + 4], buffer[ptr + 5]) * 100000000L; - expLevels[seq++] = points; - } - } - - public long getExperiencePoints (int level) - { - if (level < 13) - return expLevels[level]; - return (level - 12) * expLevels[0] + expLevels[12]; - } - - @Override - public String getText () - { - StringBuilder line = new StringBuilder (); - for (long exp : expLevels) - line.append (exp + "\n"); - return line.toString (); - } +package com.bytezone.diskbrowser.wizardry; + +import com.bytezone.diskbrowser.applefile.AbstractFile; +import com.bytezone.diskbrowser.utilities.HexFormatter; + +// -----------------------------------------------------------------------------------// +class ExperienceLevel extends AbstractFile +// -----------------------------------------------------------------------------------// +{ + private final long[] expLevels = new long[13]; + + // ---------------------------------------------------------------------------------// + ExperienceLevel (String name, byte[] buffer) + // ---------------------------------------------------------------------------------// + { + super (name, buffer); + + int seq = 0; + + for (int ptr = 0; ptr < buffer.length; ptr += 6) + { + if (buffer[ptr] == 0) + break; + + long points = HexFormatter.intValue (buffer[ptr], buffer[ptr + 1]) + + HexFormatter.intValue (buffer[ptr + 2], buffer[ptr + 3]) * 10000 + + HexFormatter.intValue (buffer[ptr + 4], buffer[ptr + 5]) * 100000000L; + expLevels[seq++] = points; + } + } + + // ---------------------------------------------------------------------------------// + long getExperiencePoints (int level) + // ---------------------------------------------------------------------------------// + { + if (level < 13) + return expLevels[level]; + return (level - 12) * expLevels[0] + expLevels[12]; + } + + // ---------------------------------------------------------------------------------// + @Override + public String getText () + // ---------------------------------------------------------------------------------// + { + StringBuilder line = new StringBuilder (); + for (long exp : expLevels) + line.append (exp + "\n"); + return line.toString (); + } } \ No newline at end of file diff --git a/src/com/bytezone/diskbrowser/wizardry/Header.java b/src/com/bytezone/diskbrowser/wizardry/Header.java index 3841172..b3f352f 100755 --- a/src/com/bytezone/diskbrowser/wizardry/Header.java +++ b/src/com/bytezone/diskbrowser/wizardry/Header.java @@ -1,239 +1,253 @@ -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", "THE RETURN OF WERDNA" }; - - 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; - - if (scenarioID > scenarioNames.length) - System.out.println ("Invalid scenario ID : " + scenarioID + " " + scenarioTitle); - - 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); - - if (scenarioID > 3) - return; - - 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 = buffer[i + line + j * 8] & 0xFF; - 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 = buffer[offset] & 0xFF; - total = buffer[offset + 16] & 0xFF; - totalBlocks = buffer[offset + 32] & 0xFF; - dataOffset = buffer[offset + 48] & 0xFF; - type = seq; - - this.sectors = new ArrayList<> (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); - } - } +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", "THE RETURN OF WERDNA" }; + + 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; + + // ---------------------------------------------------------------------------------// + 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; + + if (scenarioID > scenarioNames.length) + System.out.println ("Invalid scenario ID : " + scenarioID + " " + scenarioTitle); + + 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); + + if (scenarioID > 3) + return; + + 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 = buffer[i + line + j * 8] & 0xFF; + 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 = buffer[offset] & 0xFF; + total = buffer[offset + 16] & 0xFF; + totalBlocks = buffer[offset + 32] & 0xFF; + dataOffset = buffer[offset + 48] & 0xFF; + type = seq; + + this.sectors = new ArrayList<> (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); + } + } } \ No newline at end of file diff --git a/src/com/bytezone/diskbrowser/wizardry/Huffman.java b/src/com/bytezone/diskbrowser/wizardry/Huffman.java index cc162fb..c07bd3d 100644 --- a/src/com/bytezone/diskbrowser/wizardry/Huffman.java +++ b/src/com/bytezone/diskbrowser/wizardry/Huffman.java @@ -7,7 +7,9 @@ import com.bytezone.diskbrowser.applefile.AbstractFile; // link for possible display algorithm: // http://stackoverflow.com/questions/14184655/set-position-for-drawing-binary-tree -public class Huffman extends AbstractFile +// -----------------------------------------------------------------------------------// +class Huffman extends AbstractFile +// -----------------------------------------------------------------------------------// { private static final byte[] mask = { 2, 1 }; // bits: 10 or 01 private static final int[] offset = { 512, 256 }; // offset to left/right nodes @@ -19,12 +21,16 @@ public class Huffman extends AbstractFile private String bufferContents; - public Huffman (String name, byte[] buffer) + // ---------------------------------------------------------------------------------// + Huffman (String name, byte[] buffer) + // ---------------------------------------------------------------------------------// { super (name, buffer); } - public String decodeMessage (byte[] message) + // ---------------------------------------------------------------------------------// + String decodeMessage (byte[] message) + // ---------------------------------------------------------------------------------// { this.message = message; depth = 0; @@ -39,7 +45,9 @@ public class Huffman extends AbstractFile return text.toString (); } + // ---------------------------------------------------------------------------------// private byte getChar () + // ---------------------------------------------------------------------------------// { int treePtr = 0; // start at the root @@ -63,8 +71,10 @@ public class Huffman extends AbstractFile } } + // ---------------------------------------------------------------------------------// @Override public String getText () + // ---------------------------------------------------------------------------------// { if (bufferContents == null) { @@ -75,7 +85,9 @@ public class Huffman extends AbstractFile return bufferContents; } + // ---------------------------------------------------------------------------------// private void walk (int treePtr, String path, StringBuilder text) + // ---------------------------------------------------------------------------------// { for (int currentBit = 1; currentBit >= 0; --currentBit) if ((buffer[treePtr] & mask[currentBit]) == 0) diff --git a/src/com/bytezone/diskbrowser/wizardry/Image.java b/src/com/bytezone/diskbrowser/wizardry/Image.java index 24a073c..1c46c4b 100755 --- a/src/com/bytezone/diskbrowser/wizardry/Image.java +++ b/src/com/bytezone/diskbrowser/wizardry/Image.java @@ -1,59 +1,65 @@ -package com.bytezone.diskbrowser.wizardry; - -import java.awt.image.BufferedImage; -import java.awt.image.DataBuffer; - -class Image extends AbstractImage -{ - public Image (String name, byte[] buffer) - { - super (name, buffer); - - if (buffer[0] == -61 && buffer[1] == -115) - fixSlime (buffer); - - image = new BufferedImage (70, 50, BufferedImage.TYPE_BYTE_GRAY); // width/height - DataBuffer db = image.getRaster ().getDataBuffer (); - int element = 0; - - for (int j = 0; j < 500; j++) - { - int bits = buffer[j] & 0xFF; - for (int m = 0; m < 7; m++) - { - if (bits == 0) - { - element += 7 - m; - break; - } - if ((bits & 1) == 1) - db.setElem (element, 255); - bits >>= 1; - element++; - } - } - } - - private void fixSlime (byte[] buffer) - { - for (int i = 0; i < 208; i++) - buffer[i] = 0; - buffer[124] = -108; - buffer[134] = -43; - buffer[135] = -128; - buffer[144] = -44; - buffer[145] = -126; - buffer[154] = -48; - buffer[155] = -118; - buffer[164] = -64; - buffer[165] = -86; - buffer[174] = -64; - buffer[175] = -86; - buffer[184] = -63; - buffer[185] = -86; - buffer[194] = -44; - buffer[195] = -86; - buffer[204] = -44; - buffer[205] = -126; - } +package com.bytezone.diskbrowser.wizardry; + +import java.awt.image.BufferedImage; +import java.awt.image.DataBuffer; + +// -----------------------------------------------------------------------------------// +class Image extends AbstractImage +// -----------------------------------------------------------------------------------// +{ + // ---------------------------------------------------------------------------------// + Image (String name, byte[] buffer) + // ---------------------------------------------------------------------------------// + { + super (name, buffer); + + if (buffer[0] == -61 && buffer[1] == -115) + fixSlime (buffer); + + image = new BufferedImage (70, 50, BufferedImage.TYPE_BYTE_GRAY); // width/height + DataBuffer db = image.getRaster ().getDataBuffer (); + int element = 0; + + for (int j = 0; j < 500; j++) + { + int bits = buffer[j] & 0xFF; + for (int m = 0; m < 7; m++) + { + if (bits == 0) + { + element += 7 - m; + break; + } + if ((bits & 1) == 1) + db.setElem (element, 255); + bits >>= 1; + element++; + } + } + } + + // ---------------------------------------------------------------------------------// + private void fixSlime (byte[] buffer) + // ---------------------------------------------------------------------------------// + { + for (int i = 0; i < 208; i++) + buffer[i] = 0; + buffer[124] = -108; + buffer[134] = -43; + buffer[135] = -128; + buffer[144] = -44; + buffer[145] = -126; + buffer[154] = -48; + buffer[155] = -118; + buffer[164] = -64; + buffer[165] = -86; + buffer[174] = -64; + buffer[175] = -86; + buffer[184] = -63; + buffer[185] = -86; + buffer[194] = -44; + buffer[195] = -86; + buffer[204] = -44; + buffer[205] = -126; + } } \ No newline at end of file diff --git a/src/com/bytezone/diskbrowser/wizardry/ImageV2.java b/src/com/bytezone/diskbrowser/wizardry/ImageV2.java index 5546124..913acee 100755 --- a/src/com/bytezone/diskbrowser/wizardry/ImageV2.java +++ b/src/com/bytezone/diskbrowser/wizardry/ImageV2.java @@ -1,32 +1,36 @@ -package com.bytezone.diskbrowser.wizardry; - -import java.awt.image.BufferedImage; -import java.awt.image.DataBuffer; - -class ImageV2 extends AbstractImage -{ - public ImageV2 (String name, byte[] buffer) - { - super (name, buffer); - - image = new BufferedImage (70, 48, BufferedImage.TYPE_BYTE_GRAY); // width/height - DataBuffer db = image.getRaster ().getDataBuffer (); - int offset = 0; - int size = 7; - - for (int i = 0; i < 6; i++) - for (int j = 0; j < 10; j++) - for (int k = 7; k >= 0; k--) - { - int element = i * 560 + j * 7 + k * 70; - int bits = buffer[offset++] & 0xFF; - for (int m = size - 1; m >= 0; m--) - { - if ((bits & 1) == 1) - db.setElem (element, 255); - bits >>= 1; - element++; - } - } - } +package com.bytezone.diskbrowser.wizardry; + +import java.awt.image.BufferedImage; +import java.awt.image.DataBuffer; + +// -----------------------------------------------------------------------------------// +class ImageV2 extends AbstractImage +// -----------------------------------------------------------------------------------// +{ + // ---------------------------------------------------------------------------------// + ImageV2 (String name, byte[] buffer) + // ---------------------------------------------------------------------------------// + { + super (name, buffer); + + image = new BufferedImage (70, 48, BufferedImage.TYPE_BYTE_GRAY); // width/height + DataBuffer db = image.getRaster ().getDataBuffer (); + int offset = 0; + int size = 7; + + for (int i = 0; i < 6; i++) + for (int j = 0; j < 10; j++) + for (int k = 7; k >= 0; k--) + { + int element = i * 560 + j * 7 + k * 70; + int bits = buffer[offset++] & 0xFF; + for (int m = size - 1; m >= 0; m--) + { + if ((bits & 1) == 1) + db.setElem (element, 255); + bits >>= 1; + element++; + } + } + } } \ No newline at end of file diff --git a/src/com/bytezone/diskbrowser/wizardry/Item.java b/src/com/bytezone/diskbrowser/wizardry/Item.java index 46d4c5f..c6795de 100755 --- a/src/com/bytezone/diskbrowser/wizardry/Item.java +++ b/src/com/bytezone/diskbrowser/wizardry/Item.java @@ -1,141 +1,163 @@ -package com.bytezone.diskbrowser.wizardry; - -import com.bytezone.diskbrowser.applefile.AbstractFile; -import com.bytezone.diskbrowser.utilities.HexFormatter; - -class Item extends AbstractFile implements Comparable -{ - public final int itemID; - private final int type; - private final long cost; - public int partyOwns; - String genericName; - static int counter = 0; - public final Dice damage; - public final int armourClass; - public final int speed; - - public Item (String name, byte[] buffer) - { - super (name, buffer); - itemID = counter++; - type = buffer[32]; - cost = HexFormatter.intValue (buffer[44], buffer[45]) - + HexFormatter.intValue (buffer[46], buffer[47]) * 10000 - + HexFormatter.intValue (buffer[48], buffer[49]) * 100000000L; - genericName = HexFormatter.getPascalString (buffer, 16); - damage = new Dice (buffer, 66); - armourClass = buffer[62]; - speed = buffer[72]; - } - - @Override - public String getText () - { - StringBuilder text = new StringBuilder (); - - text.append ("Name ......... : " + name); - // 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)"); - - 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 HexFormatter.intValue (buffer[50], buffer[51]); - } - - 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", name)); - 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, name)); - int lo = block == 0 ? 32 : block == 1 ? 46 : 70; - int hi = lo + 24; - if (hi > buffer.length) - hi = buffer.length; - for (int i = lo; i < hi; i++) - line.append (String.format ("%02X ", buffer[i])); - return line.toString (); - } - - @Override - public int compareTo (Item otherItem) - { - Item item = otherItem; - return this.type - item.type; - } +package com.bytezone.diskbrowser.wizardry; + +import com.bytezone.diskbrowser.applefile.AbstractFile; +import com.bytezone.diskbrowser.utilities.HexFormatter; + +// -----------------------------------------------------------------------------------// +class Item extends AbstractFile implements Comparable +// -----------------------------------------------------------------------------------// +{ + public final int itemID; + private final int type; + private final long cost; + public int partyOwns; + String genericName; + static int counter = 0; + public final Dice damage; + public final int armourClass; + public final int speed; + + // ---------------------------------------------------------------------------------// + Item (String name, byte[] buffer) + // ---------------------------------------------------------------------------------// + { + super (name, buffer); + itemID = counter++; + type = buffer[32]; + cost = HexFormatter.intValue (buffer[44], buffer[45]) + + HexFormatter.intValue (buffer[46], buffer[47]) * 10000 + + HexFormatter.intValue (buffer[48], buffer[49]) * 100000000L; + genericName = HexFormatter.getPascalString (buffer, 16); + damage = new Dice (buffer, 66); + armourClass = buffer[62]; + speed = buffer[72]; + } + + // ---------------------------------------------------------------------------------// + @Override + public String getText () + // ---------------------------------------------------------------------------------// + { + StringBuilder text = new StringBuilder (); + + text.append ("Name ......... : " + name); + // 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)"); + + 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 HexFormatter.intValue (buffer[50], buffer[51]); + } + + // ---------------------------------------------------------------------------------// + 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", name)); + 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, name)); + int lo = block == 0 ? 32 : block == 1 ? 46 : 70; + int hi = lo + 24; + if (hi > buffer.length) + hi = buffer.length; + for (int i = lo; i < hi; i++) + line.append (String.format ("%02X ", buffer[i])); + return line.toString (); + } + + // ---------------------------------------------------------------------------------// + @Override + public int compareTo (Item otherItem) + // ---------------------------------------------------------------------------------// + { + Item item = otherItem; + return this.type - item.type; + } } \ No newline at end of file diff --git a/src/com/bytezone/diskbrowser/wizardry/MazeAddress.java b/src/com/bytezone/diskbrowser/wizardry/MazeAddress.java index bde1650..0b4c00b 100755 --- a/src/com/bytezone/diskbrowser/wizardry/MazeAddress.java +++ b/src/com/bytezone/diskbrowser/wizardry/MazeAddress.java @@ -1,21 +1,27 @@ -package com.bytezone.diskbrowser.wizardry; - -class MazeAddress -{ - public final int level; - public final int row; - public final int column; - - public MazeAddress (int level, int row, int column) - { - this.level = level; - this.row = row; - this.column = column; - } - - @Override - public String toString () - { - return level + "/" + row + "/" + column; - } +package com.bytezone.diskbrowser.wizardry; + +// -----------------------------------------------------------------------------------// +class MazeAddress +// -----------------------------------------------------------------------------------// +{ + public final int level; + public final int row; + public final int column; + + // ---------------------------------------------------------------------------------// + MazeAddress (int level, int row, int column) + // ---------------------------------------------------------------------------------// + { + this.level = level; + this.row = row; + this.column = column; + } + + // ---------------------------------------------------------------------------------// + @Override + public String toString () + // ---------------------------------------------------------------------------------// + { + return level + "/" + row + "/" + column; + } } \ No newline at end of file diff --git a/src/com/bytezone/diskbrowser/wizardry/MazeCell.java b/src/com/bytezone/diskbrowser/wizardry/MazeCell.java index 32b39aa..2ea96d6 100755 --- a/src/com/bytezone/diskbrowser/wizardry/MazeCell.java +++ b/src/com/bytezone/diskbrowser/wizardry/MazeCell.java @@ -1,328 +1,370 @@ -package com.bytezone.diskbrowser.wizardry; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.util.List; - -import com.bytezone.diskbrowser.utilities.HexFormatter; - -class MazeCell -{ - static Dimension cellSize = new Dimension (22, 22); // size in pixels - - boolean northWall; - boolean southWall; - boolean eastWall; - boolean westWall; - - boolean northDoor; - boolean southDoor; - boolean eastDoor; - boolean westDoor; - - boolean darkness; - - boolean stairs; - boolean pit; - boolean spinner; - boolean chute; - boolean elevator; - boolean monsterLair; - boolean rock; - boolean teleport; - boolean spellsBlocked; - - int elevatorFrom; - int elevatorTo; - - int messageType; - int monsterID = -1; - int itemID; - - int unknown; - - MazeAddress address; - MazeAddress addressTo; // if teleport/stairs/chute - - public Message message; - public List monsters; - public Item itemRequired; - public Item itemObtained; - - public MazeCell (MazeAddress address) - { - this.address = address; - } - - public void draw (Graphics2D g, int x, int y) - { - g.setColor (Color.BLACK); - g.fillRect (x, y, 22, 22); - - g.setColor (Color.WHITE); - - if (westWall) - drawWest (g, x, y); - if (eastWall) - drawEast (g, x, y); - if (northWall) - drawNorth (g, x, y); - if (southWall) - drawSouth (g, x, y); - - g.setColor (Color.RED); - - if (westDoor) - drawWest (g, x, y); - if (eastDoor) - drawEast (g, x, y); - if (northDoor) - drawNorth (g, x, y); - if (southDoor) - drawSouth (g, x, y); - - g.setColor (Color.GREEN); - - if (westDoor && westWall) - drawWest (g, x, y); - if (eastDoor && eastWall) - drawEast (g, x, y); - if (northDoor && northWall) - drawNorth (g, x, y); - if (southDoor && southWall) - drawSouth (g, x, y); - - g.setColor (Color.WHITE); - - if (monsterLair) - drawMonsterLair (g, x, y); - - if (stairs) - if (address.level < addressTo.level) - drawStairsDown (g, x, y); - else - drawStairsUp (g, x, y); - else if (message != null) - drawChar (g, x, y, "M", Color.RED); - else if (pit) - drawPit (g, x, y); - else if (chute) - drawChute (g, x, y); - else if (spinner) - g.drawString ("S", x + 8, y + 16); - else if (teleport) - drawTeleport (g, x, y); - else if (darkness) - drawDarkness (g, x, y); - else if (rock) - drawRock (g, x, y); - else if (elevator) - drawElevator (g, x, y, (elevatorTo - elevatorFrom + 1) / 2); - else if (monsterID >= 0) - drawMonster (g, x, y); - else if (spellsBlocked) - drawSpellsBlocked (g, x, y); - else if (unknown != 0) - drawChar (g, x, y, HexFormatter.format1 (unknown), Color.GRAY); - } - - public void drawWest (Graphics2D g, int x, int y) - { - g.drawLine (x + 1, y + 1, x + 1, y + cellSize.height - 1); - } - - private void drawEast (Graphics2D g, int x, int y) - { - g.drawLine (x + cellSize.width - 1, y + 1, x + cellSize.width - 1, - y + cellSize.height - 1); - } - - private void drawNorth (Graphics2D g, int x, int y) - { - g.drawLine (x + 1, y + 1, x + cellSize.width - 1, y + 1); - } - - private void drawSouth (Graphics2D g, int x, int y) - { - g.drawLine (x + 1, y + cellSize.height - 1, x + cellSize.width - 1, - y + cellSize.height - 1); - } - - public void drawStairsUp (Graphics2D g, int x, int y) - { - g.drawLine (x + 6, y + 18, x + 6, y + 14); - g.drawLine (x + 6, y + 14, x + 10, y + 14); - g.drawLine (x + 10, y + 14, x + 10, y + 10); - g.drawLine (x + 10, y + 10, x + 14, y + 10); - g.drawLine (x + 14, y + 10, x + 14, y + 6); - g.drawLine (x + 14, y + 6, x + 18, y + 6); - } - - public void drawStairsDown (Graphics2D g, int x, int y) - { - g.drawLine (x + 4, y + 7, x + 8, y + 7); - g.drawLine (x + 8, y + 7, x + 8, y + 11); - g.drawLine (x + 8, y + 11, x + 12, y + 11); - g.drawLine (x + 12, y + 11, x + 12, y + 15); - g.drawLine (x + 12, y + 15, x + 16, y + 15); - g.drawLine (x + 16, y + 15, x + 16, y + 19); - } - - public void drawPit (Graphics2D g, int x, int y) - { - g.drawLine (x + 5, y + 14, x + 5, y + 19); - g.drawLine (x + 5, y + 19, x + 17, y + 19); - g.drawLine (x + 17, y + 14, x + 17, y + 19); - } - - public void drawChute (Graphics2D g, int x, int y) - { - g.drawLine (x + 6, y + 6, x + 10, y + 6); - g.drawLine (x + 10, y + 6, x + 18, y + 18); - } - - public void drawElevator (Graphics2D g, int x, int y, int rows) - { - for (int i = 0; i < rows; i++) - { - g.drawOval (x + 7, y + i * 5 + 5, 2, 2); - g.drawOval (x + 14, y + i * 5 + 5, 2, 2); - } - } - - public void drawMonsterLair (Graphics2D g, int x, int y) - { - g.setColor (Color.YELLOW); - g.fillOval (x + 4, y + 4, 2, 2); - g.setColor (Color.WHITE); - } - - public void drawTeleport (Graphics2D g, int x, int y) - { - g.setColor (Color.GREEN); - g.fillOval (x + 8, y + 8, 8, 8); - g.setColor (Color.WHITE); - } - - public void drawSpellsBlocked (Graphics2D g, int x, int y) - { - g.setColor (Color.YELLOW); - g.fillOval (x + 8, y + 8, 8, 8); - g.setColor (Color.WHITE); - } - - public void drawMonster (Graphics2D g, int x, int y) - { - g.setColor (Color.RED); - g.fillOval (x + 8, y + 8, 8, 8); - g.setColor (Color.WHITE); - } - - public void drawDarkness (Graphics2D g, int x, int y) - { - g.setColor (Color.gray); - for (int h = 0; h < 15; h += 7) - for (int offset = 0; offset < 15; offset += 7) - g.drawOval (x + offset + 4, y + h + 4, 1, 1); - g.setColor (Color.white); - } - - public void drawRock (Graphics2D g, int x, int y) - { - for (int h = 0; h < 15; h += 7) - for (int offset = 0; offset < 15; offset += 7) - g.drawOval (x + offset + 4, y + h + 4, 1, 1); - } - - public void drawChar (Graphics2D g, int x, int y, String c, Color colour) - { - g.setColor (colour); - g.fillRect (x + 7, y + 6, 11, 11); - g.setColor (Color.WHITE); - g.drawString (c, x + 8, y + 16); - } - - public void drawHotDogStand (Graphics2D g, int x, int y) - { - g.drawRect (x + 5, y + 11, 12, 6); - g.drawOval (x + 6, y + 18, 3, 3); - g.drawOval (x + 13, y + 18, 3, 3); - g.drawLine (x + 8, y + 6, x + 8, y + 10); - g.drawLine (x + 14, y + 6, x + 14, y + 10); - g.drawLine (x + 5, y + 5, x + 17, y + 5); - } - - public String getTooltipText () - { - StringBuilder sign = new StringBuilder ("
");
-    sign.append (" ");
-    sign.append (address.row + "N ");
-    sign.append (address.column + "E 
"); - - if (message != null) - sign.append (message.toHTMLString ()); - - if (elevator) - sign.append (" Elevator: L" + elevatorFrom + "-L" + elevatorTo + " "); - if (stairs) - { - sign.append (" Stairs to "); - if (addressTo.level == 0) - sign.append ("castle "); - else - { - sign.append ("level " + addressTo.level + " "); - } - } - if (teleport) - { - sign.append (" Teleport to "); - if (addressTo.level == 0) - sign.append ("castle "); - else - { - sign.append ("L" + addressTo.level + " " + addressTo.row + "N " + addressTo.column - + "E "); - } - } - if (pit) - sign.append (" Pit"); - if (spinner) - sign.append (" Spinner "); - if (chute) - sign.append (" Chute"); - if (darkness) - sign.append (" Darkness "); - if (rock) - sign.append (" Rock "); - if (spellsBlocked) - sign.append (" Spells fizzle out "); - if (monsterID >= 0) - if (monsters == null || monsterID >= monsters.size ()) - sign.append (" Monster "); - else - { - Monster monster = monsters.get (monsterID); - sign.append (" " + monster.getRealName () + " "); - while (monster.partnerOdds == 100) - { - monster = monsters.get (monster.partnerID); - sign.append ("
 " + monster.getRealName () + " "); - } - } - if (itemRequired != null) - { - sign.append (" Requires: "); - sign.append (itemRequired.getName () + " "); - } - - if (itemObtained != null) - { - sign.append (" Obtain: "); - sign.append (itemObtained.getName () + " "); - } - sign.append ("
"); - return sign.toString (); - } +package com.bytezone.diskbrowser.wizardry; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.util.List; + +import com.bytezone.diskbrowser.utilities.HexFormatter; + +// -----------------------------------------------------------------------------------// +class MazeCell +// -----------------------------------------------------------------------------------// +{ + static Dimension cellSize = new Dimension (22, 22); // size in pixels + + boolean northWall; + boolean southWall; + boolean eastWall; + boolean westWall; + + boolean northDoor; + boolean southDoor; + boolean eastDoor; + boolean westDoor; + + boolean darkness; + + boolean stairs; + boolean pit; + boolean spinner; + boolean chute; + boolean elevator; + boolean monsterLair; + boolean rock; + boolean teleport; + boolean spellsBlocked; + + int elevatorFrom; + int elevatorTo; + + int messageType; + int monsterID = -1; + int itemID; + + int unknown; + + MazeAddress address; + MazeAddress addressTo; // if teleport/stairs/chute + + public Message message; + public List monsters; + public Item itemRequired; + public Item itemObtained; + + // ---------------------------------------------------------------------------------// + MazeCell (MazeAddress address) + // ---------------------------------------------------------------------------------// + { + this.address = address; + } + + // ---------------------------------------------------------------------------------// + void draw (Graphics2D g, int x, int y) + // ---------------------------------------------------------------------------------// + { + g.setColor (Color.BLACK); + g.fillRect (x, y, 22, 22); + + g.setColor (Color.WHITE); + + if (westWall) + drawWest (g, x, y); + if (eastWall) + drawEast (g, x, y); + if (northWall) + drawNorth (g, x, y); + if (southWall) + drawSouth (g, x, y); + + g.setColor (Color.RED); + + if (westDoor) + drawWest (g, x, y); + if (eastDoor) + drawEast (g, x, y); + if (northDoor) + drawNorth (g, x, y); + if (southDoor) + drawSouth (g, x, y); + + g.setColor (Color.GREEN); + + if (westDoor && westWall) + drawWest (g, x, y); + if (eastDoor && eastWall) + drawEast (g, x, y); + if (northDoor && northWall) + drawNorth (g, x, y); + if (southDoor && southWall) + drawSouth (g, x, y); + + g.setColor (Color.WHITE); + + if (monsterLair) + drawMonsterLair (g, x, y); + + if (stairs) + if (address.level < addressTo.level) + drawStairsDown (g, x, y); + else + drawStairsUp (g, x, y); + else if (message != null) + drawChar (g, x, y, "M", Color.RED); + else if (pit) + drawPit (g, x, y); + else if (chute) + drawChute (g, x, y); + else if (spinner) + g.drawString ("S", x + 8, y + 16); + else if (teleport) + drawTeleport (g, x, y); + else if (darkness) + drawDarkness (g, x, y); + else if (rock) + drawRock (g, x, y); + else if (elevator) + drawElevator (g, x, y, (elevatorTo - elevatorFrom + 1) / 2); + else if (monsterID >= 0) + drawMonster (g, x, y); + else if (spellsBlocked) + drawSpellsBlocked (g, x, y); + else if (unknown != 0) + drawChar (g, x, y, HexFormatter.format1 (unknown), Color.GRAY); + } + + // ---------------------------------------------------------------------------------// + void drawWest (Graphics2D g, int x, int y) + // ---------------------------------------------------------------------------------// + { + g.drawLine (x + 1, y + 1, x + 1, y + cellSize.height - 1); + } + + // ---------------------------------------------------------------------------------// + void drawEast (Graphics2D g, int x, int y) + // ---------------------------------------------------------------------------------// + { + g.drawLine (x + cellSize.width - 1, y + 1, x + cellSize.width - 1, + y + cellSize.height - 1); + } + + // ---------------------------------------------------------------------------------// + void drawNorth (Graphics2D g, int x, int y) + // ---------------------------------------------------------------------------------// + { + g.drawLine (x + 1, y + 1, x + cellSize.width - 1, y + 1); + } + + // ---------------------------------------------------------------------------------// + void drawSouth (Graphics2D g, int x, int y) + // ---------------------------------------------------------------------------------// + { + g.drawLine (x + 1, y + cellSize.height - 1, x + cellSize.width - 1, + y + cellSize.height - 1); + } + + // ---------------------------------------------------------------------------------// + void drawStairsUp (Graphics2D g, int x, int y) + // ---------------------------------------------------------------------------------// + { + g.drawLine (x + 6, y + 18, x + 6, y + 14); + g.drawLine (x + 6, y + 14, x + 10, y + 14); + g.drawLine (x + 10, y + 14, x + 10, y + 10); + g.drawLine (x + 10, y + 10, x + 14, y + 10); + g.drawLine (x + 14, y + 10, x + 14, y + 6); + g.drawLine (x + 14, y + 6, x + 18, y + 6); + } + + // ---------------------------------------------------------------------------------// + void drawStairsDown (Graphics2D g, int x, int y) + // ---------------------------------------------------------------------------------// + { + g.drawLine (x + 4, y + 7, x + 8, y + 7); + g.drawLine (x + 8, y + 7, x + 8, y + 11); + g.drawLine (x + 8, y + 11, x + 12, y + 11); + g.drawLine (x + 12, y + 11, x + 12, y + 15); + g.drawLine (x + 12, y + 15, x + 16, y + 15); + g.drawLine (x + 16, y + 15, x + 16, y + 19); + } + + // ---------------------------------------------------------------------------------// + void drawPit (Graphics2D g, int x, int y) + // ---------------------------------------------------------------------------------// + { + g.drawLine (x + 5, y + 14, x + 5, y + 19); + g.drawLine (x + 5, y + 19, x + 17, y + 19); + g.drawLine (x + 17, y + 14, x + 17, y + 19); + } + + // ---------------------------------------------------------------------------------// + void drawChute (Graphics2D g, int x, int y) + // ---------------------------------------------------------------------------------// + { + g.drawLine (x + 6, y + 6, x + 10, y + 6); + g.drawLine (x + 10, y + 6, x + 18, y + 18); + } + + // ---------------------------------------------------------------------------------// + void drawElevator (Graphics2D g, int x, int y, int rows) + // ---------------------------------------------------------------------------------// + { + for (int i = 0; i < rows; i++) + { + g.drawOval (x + 7, y + i * 5 + 5, 2, 2); + g.drawOval (x + 14, y + i * 5 + 5, 2, 2); + } + } + + // ---------------------------------------------------------------------------------// + void drawMonsterLair (Graphics2D g, int x, int y) + // ---------------------------------------------------------------------------------// + { + g.setColor (Color.YELLOW); + g.fillOval (x + 4, y + 4, 2, 2); + g.setColor (Color.WHITE); + } + + // ---------------------------------------------------------------------------------// + void drawTeleport (Graphics2D g, int x, int y) + // ---------------------------------------------------------------------------------// + { + g.setColor (Color.GREEN); + g.fillOval (x + 8, y + 8, 8, 8); + g.setColor (Color.WHITE); + } + + // ---------------------------------------------------------------------------------// + void drawSpellsBlocked (Graphics2D g, int x, int y) + // ---------------------------------------------------------------------------------// + { + g.setColor (Color.YELLOW); + g.fillOval (x + 8, y + 8, 8, 8); + g.setColor (Color.WHITE); + } + + // ---------------------------------------------------------------------------------// + void drawMonster (Graphics2D g, int x, int y) + // ---------------------------------------------------------------------------------// + { + g.setColor (Color.RED); + g.fillOval (x + 8, y + 8, 8, 8); + g.setColor (Color.WHITE); + } + + // ---------------------------------------------------------------------------------// + void drawDarkness (Graphics2D g, int x, int y) + // ---------------------------------------------------------------------------------// + { + g.setColor (Color.gray); + for (int h = 0; h < 15; h += 7) + for (int offset = 0; offset < 15; offset += 7) + g.drawOval (x + offset + 4, y + h + 4, 1, 1); + g.setColor (Color.white); + } + + // ---------------------------------------------------------------------------------// + void drawRock (Graphics2D g, int x, int y) + // ---------------------------------------------------------------------------------// + { + for (int h = 0; h < 15; h += 7) + for (int offset = 0; offset < 15; offset += 7) + g.drawOval (x + offset + 4, y + h + 4, 1, 1); + } + + // ---------------------------------------------------------------------------------// + void drawChar (Graphics2D g, int x, int y, String c, Color colour) + // ---------------------------------------------------------------------------------// + { + g.setColor (colour); + g.fillRect (x + 7, y + 6, 11, 11); + g.setColor (Color.WHITE); + g.drawString (c, x + 8, y + 16); + } + + // ---------------------------------------------------------------------------------// + void drawHotDogStand (Graphics2D g, int x, int y) + // ---------------------------------------------------------------------------------// + { + g.drawRect (x + 5, y + 11, 12, 6); + g.drawOval (x + 6, y + 18, 3, 3); + g.drawOval (x + 13, y + 18, 3, 3); + g.drawLine (x + 8, y + 6, x + 8, y + 10); + g.drawLine (x + 14, y + 6, x + 14, y + 10); + g.drawLine (x + 5, y + 5, x + 17, y + 5); + } + + // ---------------------------------------------------------------------------------// + String getTooltipText () + // ---------------------------------------------------------------------------------// + { + StringBuilder sign = new StringBuilder ("
");
+    sign.append (" ");
+    sign.append (address.row + "N ");
+    sign.append (address.column + "E 
"); + + if (message != null) + sign.append (message.toHTMLString ()); + + if (elevator) + sign.append (" Elevator: L" + elevatorFrom + "-L" + elevatorTo + " "); + if (stairs) + { + sign.append (" Stairs to "); + if (addressTo.level == 0) + sign.append ("castle "); + else + { + sign.append ("level " + addressTo.level + " "); + } + } + if (teleport) + { + sign.append (" Teleport to "); + if (addressTo.level == 0) + sign.append ("castle "); + else + { + sign.append ("L" + addressTo.level + " " + addressTo.row + "N " + addressTo.column + + "E "); + } + } + if (pit) + sign.append (" Pit"); + if (spinner) + sign.append (" Spinner "); + if (chute) + sign.append (" Chute"); + if (darkness) + sign.append (" Darkness "); + if (rock) + sign.append (" Rock "); + if (spellsBlocked) + sign.append (" Spells fizzle out "); + if (monsterID >= 0) + if (monsters == null || monsterID >= monsters.size ()) + sign.append (" Monster "); + else + { + Monster monster = monsters.get (monsterID); + sign.append (" " + monster.getRealName () + " "); + while (monster.partnerOdds == 100) + { + monster = monsters.get (monster.partnerID); + sign.append ("
 " + monster.getRealName () + " "); + } + } + if (itemRequired != null) + { + sign.append (" Requires: "); + sign.append (itemRequired.getName () + " "); + } + + if (itemObtained != null) + { + sign.append (" Obtain: "); + sign.append (itemObtained.getName () + " "); + } + sign.append ("
"); + return sign.toString (); + } } \ No newline at end of file diff --git a/src/com/bytezone/diskbrowser/wizardry/MazeGridV5.java b/src/com/bytezone/diskbrowser/wizardry/MazeGridV5.java index cc8a733..def96ba 100644 --- a/src/com/bytezone/diskbrowser/wizardry/MazeGridV5.java +++ b/src/com/bytezone/diskbrowser/wizardry/MazeGridV5.java @@ -12,7 +12,9 @@ import com.bytezone.common.Utility; import com.bytezone.diskbrowser.applefile.AbstractFile; import com.bytezone.diskbrowser.utilities.HexFormatter; -public class MazeGridV5 extends AbstractFile +// -----------------------------------------------------------------------------------// +class MazeGridV5 extends AbstractFile +// -----------------------------------------------------------------------------------// { private final MessageBlock messageBlock; List grids = new ArrayList<> (); @@ -21,7 +23,9 @@ public class MazeGridV5 extends AbstractFile int maxX = 0; int maxY = 0; - public MazeGridV5 (String name, byte[] buffer, MessageBlock messageBlock) + // ---------------------------------------------------------------------------------// + MazeGridV5 (String name, byte[] buffer, MessageBlock messageBlock) + // ---------------------------------------------------------------------------------// { super (name, buffer); @@ -45,8 +49,10 @@ public class MazeGridV5 extends AbstractFile } } + // ---------------------------------------------------------------------------------// @Override public BufferedImage getImage () + // ---------------------------------------------------------------------------------// { Dimension cellSize = new Dimension (22, 22); int fudge = 30; @@ -80,7 +86,9 @@ public class MazeGridV5 extends AbstractFile return image; } + // ---------------------------------------------------------------------------------// private MazeCell getLayout (int gridNo, int row, int column) + // ---------------------------------------------------------------------------------// { MazeAddress address = new MazeAddress (0, row, column); MazeCell cell = new MazeCell (address); @@ -103,8 +111,10 @@ public class MazeGridV5 extends AbstractFile return cell; } + // ---------------------------------------------------------------------------------// @Override public String getHexDump () + // ---------------------------------------------------------------------------------// { StringBuilder text = new StringBuilder (super.getHexDump ()); @@ -187,7 +197,9 @@ public class MazeGridV5 extends AbstractFile return text.toString (); } + // ---------------------------------------------------------------------------------// private class MazeGrid + // ---------------------------------------------------------------------------------// { MazeCell[][] grid; int xOffset; diff --git a/src/com/bytezone/diskbrowser/wizardry/MazeLevel.java b/src/com/bytezone/diskbrowser/wizardry/MazeLevel.java index 19fd007..30fce55 100755 --- a/src/com/bytezone/diskbrowser/wizardry/MazeLevel.java +++ b/src/com/bytezone/diskbrowser/wizardry/MazeLevel.java @@ -1,488 +1,520 @@ -package com.bytezone.diskbrowser.wizardry; - -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.awt.RenderingHints; -import java.awt.image.BufferedImage; -import java.util.ArrayList; -import java.util.List; - -import com.bytezone.diskbrowser.applefile.AbstractFile; -import com.bytezone.diskbrowser.utilities.HexFormatter; - -class MazeLevel extends AbstractFile -{ - public final int level; - private List messages; - private List monsters; - private List items; - - public MazeLevel (byte[] buffer, int level) - { - super ("Level " + level, buffer); - this.level = level; - } - - @Override - public String getHexDump () - { - StringBuilder text = new StringBuilder (); - - text.append ("West walls/doors\n\n"); - text.append (HexFormatter.format (buffer, 0, 120)); - addWalls (text, 0); - - text.append ("\nSouth walls/doors\n\n"); - text.append (HexFormatter.format (buffer, 120, 120)); - addWalls (text, 120); - - text.append ("\nEast walls/doors\n\n"); - text.append (HexFormatter.format (buffer, 240, 120)); - addWalls (text, 240); - - text.append ("\nNorth walls/doors\n\n"); - text.append (HexFormatter.format (buffer, 360, 120)); - addWalls (text, 360); - - text.append ("\nEncounters\n\n"); - text.append (HexFormatter.format (buffer, 480, 80)); - addEncounters (text, 480); - - text.append ("\nExtras\n\n"); - text.append (HexFormatter.format (buffer, 560, 200)); - addExtras (text, 560); - - text.append ("\nIndex\n\n"); - text.append ( - String.format ("%04X: %s%n", 760, HexFormatter.getHexString (buffer, 760, 8))); - - text.append ("\nTable\n\n"); - text.append (HexFormatter.format (buffer, 768, 96)); - - text.append ("\n\n 0 1 2 3 4 5 6 7 8 9 A B C D E F\n"); - text.append (String.format ("%04X: ", 760)); - for (int i = 0; i < 8; i++) - { - int val = buffer[760 + i] & 0xFF; - text.append (String.format ("%X:%X ", val % 16, val / 16)); - } - - String[] extras = - { "", "Stairs", "Pit", "Chute", "Spinner", "Darkness", "Teleport", "Ouch", - "Elevator", "Rock/Water", "Fizzle", "Message/Item", "Monster" }; - - List messageList = new ArrayList<> (); - List monsterList = new ArrayList<> (); - - text.append ("\n\nValue Index Contains Table\n"); - for (int j = 0; j < 16; j++) - { - String extraText = ""; - int val = buffer[760 + j / 2] & 0xFF; - String extra = (j % 2) == 0 ? extras[val % 16] : extras[val / 16]; - MazeAddress address = getAddress (j); - int cellFlag = (j % 2) == 0 ? val % 16 : val / 16; - if (cellFlag == 11) - { - extraText = "Msg:" + String.format ("%04X ", address.row); - messageList.add (address); // to print at the end - - int messageType = address.column; - if (messageType == 2) - { - extraText += "Obtained: "; - if (items != null) - extraText += items.get (address.level).getName (); - } - - if (messageType == 5) - { - extraText += "Requires: "; - if (items != null) - extraText += items.get (address.level).getName (); - } - - if (messageType == 4) - { - extraText += "Unknown"; - } - } - - if (cellFlag == 12) - { - monsterList.add (address); - extraText = "Encounter: "; - if (monsters != null) - extraText += monsters.get (address.column).realName; - } - - text.append (String.format (" %X --> %X %-15s %04X %04X %04X %s%n", j, - cellFlag, extra, address.level, address.row, address.column, extraText)); - } - - text.append ("\n\nRest\n\n"); - text.append (HexFormatter.format (buffer, 864, buffer.length - 864)); - - text.append ("\n"); - for (MazeAddress address : messageList) - { - Message message = getMessage (address.row); - if (message != null) - { - text.append (String.format ("%nMessage: %04X (%d)%n", address.row, address.row)); - text.append (message.getText ()); - text.append ("\n"); - } - } - - for (MazeAddress address : monsterList) - { - Monster monster = getMonster (address.column); - if (monster != null) - { - text.append (String.format ("%nMonster: %04X%n", address.column)); - text.append (monster.getText ()); - text.append ("\n"); - } - } - - return text.toString (); - } - - private void addWalls (StringBuilder text, int ptr) - { - text.append ("\n\n"); - for (int i = 0; i < 20; i++) - text.append (String.format (" Col %2d: %s%n", i, - HexFormatter.getHexString (buffer, ptr + i * 6, 6))); - } - - private void addEncounters (StringBuilder text, int ptr) - { - text.append ("\n\n"); - for (int i = 0; i < 20; i++) - { - text.append (String.format (" Col %2d: %s ", i, - HexFormatter.getHexString (buffer, ptr + i * 4, 4))); - StringBuilder bitString = new StringBuilder (); - for (int j = 2; j >= 0; j--) - { - byte b = buffer[ptr + i * 4 + j]; - String s = ("0000000" + Integer.toBinaryString (0xFF & b)) - .replaceAll (".*(.{8})$", "$1"); - bitString.append (s); - // text.append (s); - // text.append (" "); - } - - String bitsReversed = bitString.reverse ().toString (); - bitsReversed = bitsReversed.replace ("1", " 1"); - bitsReversed = bitsReversed.replace ("0", " "); - text.append (bitsReversed.substring (0, 40)); - text.append (" : "); - text.append (bitsReversed.substring (40)); - text.append ("\n"); - } - } - - private void addExtras (StringBuilder text, int ptr) - { - text.append ("\n\n"); - for (int i = 0; i < 20; i++) - { - text.append (String.format (" Col %2d: ", i)); - for (int j = 0; j < 10; j++) - { - int val = buffer[ptr + i * 10 + j] & 0xFF; - int left = val / 16; // 0:F - int right = val % 16; // 0:F - text.append (String.format ("%X:%X ", right, left)); - } - text.append ("\n"); - } - } - - @Override - public BufferedImage getImage () - { - Dimension cellSize = new Dimension (22, 22); - image = new BufferedImage (20 * cellSize.width + 1, 20 * cellSize.height + 1, - BufferedImage.TYPE_USHORT_555_RGB); - Graphics2D g = image.createGraphics (); - g.setRenderingHint (RenderingHints.KEY_ANTIALIASING, - RenderingHints.VALUE_ANTIALIAS_ON); - - for (int row = 0; row < 20; row++) - for (int column = 0; column < 20; column++) - { - MazeCell cell = getLocation (row, column); - int x = column * cellSize.width; - int y = image.getHeight () - (row + 1) * cellSize.height - 1; - cell.draw (g, x, y); - } - return image; - } - - public void setMessages (List messages) - { - this.messages = messages; - } - - public void setMonsters (List monsters) - { - this.monsters = monsters; - } - - public void setItems (List items) - { - this.items = items; - } - - public MazeCell getLocation (int row, int column) - { - MazeAddress address = new MazeAddress (level, row, column); - MazeCell cell = new MazeCell (address); - - // doors and walls - int BYTES_PER_COL = 6; // 20 / 4 = 5 bytes + 1 wasted - int CELLS_PER_BYTE = 4; // 2 bits each - int BITS_PER_ROW = 2; - - int offset = column * BYTES_PER_COL + row / CELLS_PER_BYTE; - - int value = buffer[offset] & 0xFF; - value >>>= (row % CELLS_PER_BYTE) * BITS_PER_ROW; // push 0, 2, 4, 6 bits - cell.westWall = ((value & 1) == 1); // use rightmost bit - value >>>= 1; // push 1 bit - cell.westDoor = ((value & 1) == 1); // use rightmost bit - - value = buffer[offset + 120] & 0xFF; - value >>>= (row % CELLS_PER_BYTE) * BITS_PER_ROW; - cell.southWall = ((value & 1) == 1); - value >>>= 1; - cell.southDoor = ((value & 1) == 1); - - value = buffer[offset + 240] & 0xFF; - value >>>= (row % CELLS_PER_BYTE) * BITS_PER_ROW; - cell.eastWall = ((value & 1) == 1); - value >>>= 1; - cell.eastDoor = ((value & 1) == 1); - - value = buffer[offset + 360] & 0xFF; - value >>>= (row % CELLS_PER_BYTE) * BITS_PER_ROW; - cell.northWall = ((value & 1) == 1); - value >>>= 1; - cell.northDoor = ((value & 1) == 1); - - // monster table - BYTES_PER_COL = 4; // 3 bytes + 1 wasted - CELLS_PER_BYTE = 8; // 1 bit each - BITS_PER_ROW = 1; - - offset = column * BYTES_PER_COL + row / CELLS_PER_BYTE; // 4 bytes/column, 1 bit/row - value = buffer[offset + 480] & 0xFF; - value >>>= row % 8; - cell.monsterLair = ((value & 1) == 1); - - // square extra - - offset = column * 10 + row / 2; // 10 bytes/column, 4 bits/row - value = buffer[offset + 560] & 0xFF; - int b = (row % 2 == 0) ? value % 16 : value / 16; // 0:F - - int c = buffer[760 + b / 2] & 0xFF; // 760:767 - int cellFlag = (b % 2 == 0) ? c % 16 : c / 16; - - switch (cellFlag) - { - case 0: // normal - break; - - case 1: - cell.stairs = true; - cell.addressTo = getAddress (b); - break; - - case 2: - cell.pit = true; - break; - - case 3: - cell.chute = true; - cell.addressTo = getAddress (b); - break; - - case 4: - cell.spinner = true; - break; - - case 5: - cell.darkness = true; - break; - - case 6: - cell.teleport = true; - cell.addressTo = getAddress (b); - break; - - case 7: // ouchy - cell.unknown = cellFlag; - break; - - case 8: - cell.elevator = true; - MazeAddress elevatorAddress = getAddress (b); - cell.elevatorTo = elevatorAddress.row; - // HexFormatter.intValue (buffer[800 + b * 2], buffer[801 + b * 2]); - cell.elevatorFrom = elevatorAddress.column; - // HexFormatter.intValue (buffer[832 + b * 2], buffer[833 + b * 2]); - break; - - case 9: // rock/water - cell.rock = true; - break; - - case 10: - cell.spellsBlocked = true; - break; - - case 11: - MazeAddress messageAddress = getAddress (b); - // int messageNum = HexFormatter.intValue (buffer[800 + b * 2], buffer[801 + b * 2]); - - Message m = getMessage (messageAddress.row); - if (m != null) - cell.message = m; - - cell.messageType = messageAddress.column; - // HexFormatter.intValue (buffer[832 + b * 2], buffer[833 + b * 2]); - - int itemID = -1; - - if (cell.messageType == 2 && items != null) // obtain Item - { - // itemID = HexFormatter.intValue (buffer[768 + b * 2], buffer[769 + b * 2]); - itemID = messageAddress.level; - cell.itemObtained = items.get (itemID); - } - - if (cell.messageType == 5 && items != null) // requires Item - { - // itemID = HexFormatter.intValue (buffer[768 + b * 2], buffer[769 + b * 2]); - itemID = messageAddress.level; - cell.itemRequired = items.get (itemID); - } - - if (cell.messageType == 4) - { - // value = HexFormatter.intValue (buffer[768 + b * 2], buffer[769 + b * 2]); - itemID = messageAddress.level; - if (value <= 100) - { - cell.monsterID = value; - cell.monsters = monsters; - } - else - { - int val = (value - 64536) * -1; - System.out.println ("Value : " + val); - // this gives Index error: 20410, Size 104 in Wizardry_III/legacy2.dsk - if (items != null && val < items.size ()) - cell.itemObtained = items.get (val); // check this - if (cell.itemObtained == null) - System.out.printf ("Item %d not found%n", val); - } - } - break; - - case 12: - MazeAddress monsterAddress = getAddress (b); - // cell.monsterID = HexFormatter.intValue (buffer[832 + b * 2], buffer[833 + b * 2]); - cell.monsterID = monsterAddress.column; - cell.monsters = monsters; - break; - - default: - System.out.println ("Unknown extra: " + cellFlag); - cell.unknown = cellFlag; - break; - } - - return cell; - } - - private MazeAddress getAddress (int b) // 0:F - { - int x = b * 2; - return new MazeAddress (HexFormatter.intValue (buffer[768 + x], buffer[769 + x]), - HexFormatter.intValue (buffer[800 + x], buffer[801 + x]), - HexFormatter.intValue (buffer[832 + x], buffer[833 + x])); - } - - private Message getMessage (int messageNo) - { - if (messages == null) - return null; - - for (Message m : messages) - if (m.match (messageNo)) - return m; - - return null; - } - - private Monster getMonster (int monsterNo) - { - if (monsters == null) - return null; - - for (Monster m : monsters) - if (m.match (monsterNo)) - return m; - - return null; - } - - public int getRows () - { - return 20; - } - - public int getColumns () - { - return 20; - } - /* - * Pascal code decompiled by Tom Ewers - * - * TWALL = (OPEN, WALL, DOOR, HIDEDOOR); - - TSQUARE = (NORMAL, STAIRS, PIT, CHUTE, SPINNER, DARK, TRANSFER, - OUCHY, BUTTONZ, ROCKWATE, FIZZLE, SCNMSG, ENCOUNTE); - - TMAZE = RECORD - W : PACKED ARRAY[ 0..19] OF PACKED ARRAY[ 0..19] OF TWALL; - S : PACKED ARRAY[ 0..19] OF PACKED ARRAY[ 0..19] OF TWALL; - E : PACKED ARRAY[ 0..19] OF PACKED ARRAY[ 0..19] OF TWALL; - N : PACKED ARRAY[ 0..19] OF PACKED ARRAY[ 0..19] OF TWALL; - - FIGHTS : PACKED ARRAY[ 0..19] OF PACKED ARRAY[ 0..19] OF 0..1; - - SQREXTRA : PACKED ARRAY[ 0..19] OF PACKED ARRAY[ 0..19] OF 0..15; - - SQRETYPE : PACKED ARRAY[ 0..15] OF TSQUARE; - - AUX0 : PACKED ARRAY[ 0..15] OF INTEGER; - AUX1 : PACKED ARRAY[ 0..15] OF INTEGER; - AUX2 : PACKED ARRAY[ 0..15] OF INTEGER; - - ENMYCALC : PACKED ARRAY[ 1..3] OF RECORD - MINENEMY : INTEGER; - MULTWORS : INTEGER; - WORSE01 : INTEGER; - RANGE0N : INTEGER; - PERCWORS : INTEGER; - END; - END; - */ +package com.bytezone.diskbrowser.wizardry; + +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.image.BufferedImage; +import java.util.ArrayList; +import java.util.List; + +import com.bytezone.diskbrowser.applefile.AbstractFile; +import com.bytezone.diskbrowser.utilities.HexFormatter; + +// -----------------------------------------------------------------------------------// +class MazeLevel extends AbstractFile +// -----------------------------------------------------------------------------------// +{ + public final int level; + private List messages; + private List monsters; + private List items; + + // ---------------------------------------------------------------------------------// + public MazeLevel (byte[] buffer, int level) + // ---------------------------------------------------------------------------------// + { + super ("Level " + level, buffer); + this.level = level; + } + + // ---------------------------------------------------------------------------------// + @Override + public String getHexDump () + // ---------------------------------------------------------------------------------// + { + StringBuilder text = new StringBuilder (); + + text.append ("West walls/doors\n\n"); + text.append (HexFormatter.format (buffer, 0, 120)); + addWalls (text, 0); + + text.append ("\nSouth walls/doors\n\n"); + text.append (HexFormatter.format (buffer, 120, 120)); + addWalls (text, 120); + + text.append ("\nEast walls/doors\n\n"); + text.append (HexFormatter.format (buffer, 240, 120)); + addWalls (text, 240); + + text.append ("\nNorth walls/doors\n\n"); + text.append (HexFormatter.format (buffer, 360, 120)); + addWalls (text, 360); + + text.append ("\nEncounters\n\n"); + text.append (HexFormatter.format (buffer, 480, 80)); + addEncounters (text, 480); + + text.append ("\nExtras\n\n"); + text.append (HexFormatter.format (buffer, 560, 200)); + addExtras (text, 560); + + text.append ("\nIndex\n\n"); + text.append ( + String.format ("%04X: %s%n", 760, HexFormatter.getHexString (buffer, 760, 8))); + + text.append ("\nTable\n\n"); + text.append (HexFormatter.format (buffer, 768, 96)); + + text.append ("\n\n 0 1 2 3 4 5 6 7 8 9 A B C D E F\n"); + text.append (String.format ("%04X: ", 760)); + for (int i = 0; i < 8; i++) + { + int val = buffer[760 + i] & 0xFF; + text.append (String.format ("%X:%X ", val % 16, val / 16)); + } + + String[] extras = + { "", "Stairs", "Pit", "Chute", "Spinner", "Darkness", "Teleport", "Ouch", + "Elevator", "Rock/Water", "Fizzle", "Message/Item", "Monster" }; + + List messageList = new ArrayList<> (); + List monsterList = new ArrayList<> (); + + text.append ("\n\nValue Index Contains Table\n"); + for (int j = 0; j < 16; j++) + { + String extraText = ""; + int val = buffer[760 + j / 2] & 0xFF; + String extra = (j % 2) == 0 ? extras[val % 16] : extras[val / 16]; + MazeAddress address = getAddress (j); + int cellFlag = (j % 2) == 0 ? val % 16 : val / 16; + if (cellFlag == 11) + { + extraText = "Msg:" + String.format ("%04X ", address.row); + messageList.add (address); // to print at the end + + int messageType = address.column; + if (messageType == 2) + { + extraText += "Obtained: "; + if (items != null) + extraText += items.get (address.level).getName (); + } + + if (messageType == 5) + { + extraText += "Requires: "; + if (items != null) + extraText += items.get (address.level).getName (); + } + + if (messageType == 4) + { + extraText += "Unknown"; + } + } + + if (cellFlag == 12) + { + monsterList.add (address); + extraText = "Encounter: "; + if (monsters != null) + extraText += monsters.get (address.column).realName; + } + + text.append (String.format (" %X --> %X %-15s %04X %04X %04X %s%n", j, + cellFlag, extra, address.level, address.row, address.column, extraText)); + } + + text.append ("\n\nRest\n\n"); + text.append (HexFormatter.format (buffer, 864, buffer.length - 864)); + + text.append ("\n"); + for (MazeAddress address : messageList) + { + Message message = getMessage (address.row); + if (message != null) + { + text.append (String.format ("%nMessage: %04X (%d)%n", address.row, address.row)); + text.append (message.getText ()); + text.append ("\n"); + } + } + + for (MazeAddress address : monsterList) + { + Monster monster = getMonster (address.column); + if (monster != null) + { + text.append (String.format ("%nMonster: %04X%n", address.column)); + text.append (monster.getText ()); + text.append ("\n"); + } + } + + return text.toString (); + } + + // ---------------------------------------------------------------------------------// + private void addWalls (StringBuilder text, int ptr) + // ---------------------------------------------------------------------------------// + { + text.append ("\n\n"); + for (int i = 0; i < 20; i++) + text.append (String.format (" Col %2d: %s%n", i, + HexFormatter.getHexString (buffer, ptr + i * 6, 6))); + } + + // ---------------------------------------------------------------------------------// + private void addEncounters (StringBuilder text, int ptr) + // ---------------------------------------------------------------------------------// + { + text.append ("\n\n"); + for (int i = 0; i < 20; i++) + { + text.append (String.format (" Col %2d: %s ", i, + HexFormatter.getHexString (buffer, ptr + i * 4, 4))); + StringBuilder bitString = new StringBuilder (); + for (int j = 2; j >= 0; j--) + { + byte b = buffer[ptr + i * 4 + j]; + String s = ("0000000" + Integer.toBinaryString (0xFF & b)) + .replaceAll (".*(.{8})$", "$1"); + bitString.append (s); + // text.append (s); + // text.append (" "); + } + + String bitsReversed = bitString.reverse ().toString (); + bitsReversed = bitsReversed.replace ("1", " 1"); + bitsReversed = bitsReversed.replace ("0", " "); + text.append (bitsReversed.substring (0, 40)); + text.append (" : "); + text.append (bitsReversed.substring (40)); + text.append ("\n"); + } + } + + // ---------------------------------------------------------------------------------// + private void addExtras (StringBuilder text, int ptr) + // ---------------------------------------------------------------------------------// + { + text.append ("\n\n"); + for (int i = 0; i < 20; i++) + { + text.append (String.format (" Col %2d: ", i)); + for (int j = 0; j < 10; j++) + { + int val = buffer[ptr + i * 10 + j] & 0xFF; + int left = val / 16; // 0:F + int right = val % 16; // 0:F + text.append (String.format ("%X:%X ", right, left)); + } + text.append ("\n"); + } + } + + // ---------------------------------------------------------------------------------// + @Override + public BufferedImage getImage () + // ---------------------------------------------------------------------------------// + { + Dimension cellSize = new Dimension (22, 22); + image = new BufferedImage (20 * cellSize.width + 1, 20 * cellSize.height + 1, + BufferedImage.TYPE_USHORT_555_RGB); + Graphics2D g = image.createGraphics (); + g.setRenderingHint (RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + + for (int row = 0; row < 20; row++) + for (int column = 0; column < 20; column++) + { + MazeCell cell = getLocation (row, column); + int x = column * cellSize.width; + int y = image.getHeight () - (row + 1) * cellSize.height - 1; + cell.draw (g, x, y); + } + return image; + } + + // ---------------------------------------------------------------------------------// + public void setMessages (List messages) + // ---------------------------------------------------------------------------------// + { + this.messages = messages; + } + + // ---------------------------------------------------------------------------------// + public void setMonsters (List monsters) + // ---------------------------------------------------------------------------------// + { + this.monsters = monsters; + } + + // ---------------------------------------------------------------------------------// + public void setItems (List items) + // ---------------------------------------------------------------------------------// + { + this.items = items; + } + + // ---------------------------------------------------------------------------------// + public MazeCell getLocation (int row, int column) + // ---------------------------------------------------------------------------------// + { + MazeAddress address = new MazeAddress (level, row, column); + MazeCell cell = new MazeCell (address); + + // doors and walls + int BYTES_PER_COL = 6; // 20 / 4 = 5 bytes + 1 wasted + int CELLS_PER_BYTE = 4; // 2 bits each + int BITS_PER_ROW = 2; + + int offset = column * BYTES_PER_COL + row / CELLS_PER_BYTE; + + int value = buffer[offset] & 0xFF; + value >>>= (row % CELLS_PER_BYTE) * BITS_PER_ROW; // push 0, 2, 4, 6 bits + cell.westWall = ((value & 1) == 1); // use rightmost bit + value >>>= 1; // push 1 bit + cell.westDoor = ((value & 1) == 1); // use rightmost bit + + value = buffer[offset + 120] & 0xFF; + value >>>= (row % CELLS_PER_BYTE) * BITS_PER_ROW; + cell.southWall = ((value & 1) == 1); + value >>>= 1; + cell.southDoor = ((value & 1) == 1); + + value = buffer[offset + 240] & 0xFF; + value >>>= (row % CELLS_PER_BYTE) * BITS_PER_ROW; + cell.eastWall = ((value & 1) == 1); + value >>>= 1; + cell.eastDoor = ((value & 1) == 1); + + value = buffer[offset + 360] & 0xFF; + value >>>= (row % CELLS_PER_BYTE) * BITS_PER_ROW; + cell.northWall = ((value & 1) == 1); + value >>>= 1; + cell.northDoor = ((value & 1) == 1); + + // monster table + BYTES_PER_COL = 4; // 3 bytes + 1 wasted + CELLS_PER_BYTE = 8; // 1 bit each + BITS_PER_ROW = 1; + + offset = column * BYTES_PER_COL + row / CELLS_PER_BYTE; // 4 bytes/column, 1 bit/row + value = buffer[offset + 480] & 0xFF; + value >>>= row % 8; + cell.monsterLair = ((value & 1) == 1); + + // square extra + + offset = column * 10 + row / 2; // 10 bytes/column, 4 bits/row + value = buffer[offset + 560] & 0xFF; + int b = (row % 2 == 0) ? value % 16 : value / 16; // 0:F + + int c = buffer[760 + b / 2] & 0xFF; // 760:767 + int cellFlag = (b % 2 == 0) ? c % 16 : c / 16; + + switch (cellFlag) + { + case 0: // normal + break; + + case 1: + cell.stairs = true; + cell.addressTo = getAddress (b); + break; + + case 2: + cell.pit = true; + break; + + case 3: + cell.chute = true; + cell.addressTo = getAddress (b); + break; + + case 4: + cell.spinner = true; + break; + + case 5: + cell.darkness = true; + break; + + case 6: + cell.teleport = true; + cell.addressTo = getAddress (b); + break; + + case 7: // ouchy + cell.unknown = cellFlag; + break; + + case 8: + cell.elevator = true; + MazeAddress elevatorAddress = getAddress (b); + cell.elevatorTo = elevatorAddress.row; + // HexFormatter.intValue (buffer[800 + b * 2], buffer[801 + b * 2]); + cell.elevatorFrom = elevatorAddress.column; + // HexFormatter.intValue (buffer[832 + b * 2], buffer[833 + b * 2]); + break; + + case 9: // rock/water + cell.rock = true; + break; + + case 10: + cell.spellsBlocked = true; + break; + + case 11: + MazeAddress messageAddress = getAddress (b); + // int messageNum = HexFormatter.intValue (buffer[800 + b * 2], buffer[801 + b * 2]); + + Message m = getMessage (messageAddress.row); + if (m != null) + cell.message = m; + + cell.messageType = messageAddress.column; + // HexFormatter.intValue (buffer[832 + b * 2], buffer[833 + b * 2]); + + int itemID = -1; + + if (cell.messageType == 2 && items != null) // obtain Item + { + // itemID = HexFormatter.intValue (buffer[768 + b * 2], buffer[769 + b * 2]); + itemID = messageAddress.level; + cell.itemObtained = items.get (itemID); + } + + if (cell.messageType == 5 && items != null) // requires Item + { + // itemID = HexFormatter.intValue (buffer[768 + b * 2], buffer[769 + b * 2]); + itemID = messageAddress.level; + cell.itemRequired = items.get (itemID); + } + + if (cell.messageType == 4) + { + // value = HexFormatter.intValue (buffer[768 + b * 2], buffer[769 + b * 2]); + itemID = messageAddress.level; + if (value <= 100) + { + cell.monsterID = value; + cell.monsters = monsters; + } + else + { + int val = (value - 64536) * -1; + System.out.println ("Value : " + val); + // this gives Index error: 20410, Size 104 in Wizardry_III/legacy2.dsk + if (items != null && val < items.size ()) + cell.itemObtained = items.get (val); // check this + if (cell.itemObtained == null) + System.out.printf ("Item %d not found%n", val); + } + } + break; + + case 12: + MazeAddress monsterAddress = getAddress (b); + // cell.monsterID = HexFormatter.intValue (buffer[832 + b * 2], buffer[833 + b * 2]); + cell.monsterID = monsterAddress.column; + cell.monsters = monsters; + break; + + default: + System.out.println ("Unknown extra: " + cellFlag); + cell.unknown = cellFlag; + break; + } + + return cell; + } + + // ---------------------------------------------------------------------------------// + private MazeAddress getAddress (int b) // 0:F + // ---------------------------------------------------------------------------------// + { + int x = b * 2; + return new MazeAddress (HexFormatter.intValue (buffer[768 + x], buffer[769 + x]), + HexFormatter.intValue (buffer[800 + x], buffer[801 + x]), + HexFormatter.intValue (buffer[832 + x], buffer[833 + x])); + } + + // ---------------------------------------------------------------------------------// + private Message getMessage (int messageNo) + // ---------------------------------------------------------------------------------// + { + if (messages == null) + return null; + + for (Message m : messages) + if (m.match (messageNo)) + return m; + + return null; + } + + // ---------------------------------------------------------------------------------// + private Monster getMonster (int monsterNo) + // ---------------------------------------------------------------------------------// + { + if (monsters == null) + return null; + + for (Monster m : monsters) + if (m.match (monsterNo)) + return m; + + return null; + } + + // ---------------------------------------------------------------------------------// + public int getRows () + // ---------------------------------------------------------------------------------// + { + return 20; + } + + // ---------------------------------------------------------------------------------// + public int getColumns () + // ---------------------------------------------------------------------------------// + { + return 20; + } + /* + * Pascal code decompiled by Tom Ewers + * + * TWALL = (OPEN, WALL, DOOR, HIDEDOOR); + + TSQUARE = (NORMAL, STAIRS, PIT, CHUTE, SPINNER, DARK, TRANSFER, + OUCHY, BUTTONZ, ROCKWATE, FIZZLE, SCNMSG, ENCOUNTE); + + TMAZE = RECORD + W : PACKED ARRAY[ 0..19] OF PACKED ARRAY[ 0..19] OF TWALL; + S : PACKED ARRAY[ 0..19] OF PACKED ARRAY[ 0..19] OF TWALL; + E : PACKED ARRAY[ 0..19] OF PACKED ARRAY[ 0..19] OF TWALL; + N : PACKED ARRAY[ 0..19] OF PACKED ARRAY[ 0..19] OF TWALL; + + FIGHTS : PACKED ARRAY[ 0..19] OF PACKED ARRAY[ 0..19] OF 0..1; + + SQREXTRA : PACKED ARRAY[ 0..19] OF PACKED ARRAY[ 0..19] OF 0..15; + + SQRETYPE : PACKED ARRAY[ 0..15] OF TSQUARE; + + AUX0 : PACKED ARRAY[ 0..15] OF INTEGER; + AUX1 : PACKED ARRAY[ 0..15] OF INTEGER; + AUX2 : PACKED ARRAY[ 0..15] OF INTEGER; + + ENMYCALC : PACKED ARRAY[ 1..3] OF RECORD + MINENEMY : INTEGER; + MULTWORS : INTEGER; + WORSE01 : INTEGER; + RANGE0N : INTEGER; + PERCWORS : INTEGER; + END; + END; + */ } \ No newline at end of file diff --git a/src/com/bytezone/diskbrowser/wizardry/Message.java b/src/com/bytezone/diskbrowser/wizardry/Message.java index 2b2866d..726c35c 100755 --- a/src/com/bytezone/diskbrowser/wizardry/Message.java +++ b/src/com/bytezone/diskbrowser/wizardry/Message.java @@ -1,71 +1,85 @@ -package com.bytezone.diskbrowser.wizardry; - -import java.util.ArrayList; -import java.util.List; - -import com.bytezone.diskbrowser.applefile.AbstractFile; - -abstract class Message extends AbstractFile -{ - private static int nextId = 0; - protected String message; - private final int id; - private int totalLines; - List lines = new ArrayList<> (); - - public Message (byte[] buffer) - { - super ("Message " + nextId, buffer); - this.id = nextId; - - int recordLength = 42; - StringBuilder text = new StringBuilder (); - - for (int ptr = 0; ptr < buffer.length; ptr += recordLength) - { - nextId++; - totalLines++; - String line = getLine (ptr); - text.append (line + "\n"); - lines.add (line); - } - text.deleteCharAt (text.length () - 1); - message = text.toString (); - } - - protected abstract String getLine (int offset); - - public boolean match (int messageNum) - { - if (id == messageNum) - return true; - - // this code is to allow for a bug in scenario #1 - if (messageNum > id && messageNum < (id + totalLines)) - return true; - - return false; - } - - @Override - public String getText () - { - return message; - } - - public String toHTMLString () - { - StringBuilder message = new StringBuilder (); - for (String line : lines) - message.append (" " + line + " 
"); - if (message.length () > 0) - for (int i = 0; i < 4; i++) - message.deleteCharAt (message.length () - 1); // remove
tag - return message.toString (); - } - - public static void resetMessageId () - { - nextId = 0; - } +package com.bytezone.diskbrowser.wizardry; + +import java.util.ArrayList; +import java.util.List; + +import com.bytezone.diskbrowser.applefile.AbstractFile; + +// -----------------------------------------------------------------------------------// +abstract class Message extends AbstractFile +// -----------------------------------------------------------------------------------// +{ + private static int nextId = 0; + protected String message; + private final int id; + private int totalLines; + List lines = new ArrayList<> (); + + // ---------------------------------------------------------------------------------// + Message (byte[] buffer) + // ---------------------------------------------------------------------------------// + { + super ("Message " + nextId, buffer); + this.id = nextId; + + int recordLength = 42; + StringBuilder text = new StringBuilder (); + + for (int ptr = 0; ptr < buffer.length; ptr += recordLength) + { + nextId++; + totalLines++; + String line = getLine (ptr); + text.append (line + "\n"); + lines.add (line); + } + text.deleteCharAt (text.length () - 1); + message = text.toString (); + } + + // ---------------------------------------------------------------------------------// + protected abstract String getLine (int offset); + // ---------------------------------------------------------------------------------// + + // ---------------------------------------------------------------------------------// + public boolean match (int messageNum) + // ---------------------------------------------------------------------------------// + { + if (id == messageNum) + return true; + + // this code is to allow for a bug in scenario #1 + if (messageNum > id && messageNum < (id + totalLines)) + return true; + + return false; + } + + // ---------------------------------------------------------------------------------// + @Override + public String getText () + // ---------------------------------------------------------------------------------// + { + return message; + } + + // ---------------------------------------------------------------------------------// + public String toHTMLString () + // ---------------------------------------------------------------------------------// + { + StringBuilder message = new StringBuilder (); + for (String line : lines) + message.append (" " + line + " 
"); + if (message.length () > 0) + for (int i = 0; i < 4; i++) + message.deleteCharAt (message.length () - 1); // remove
tag + return message.toString (); + } + + // ---------------------------------------------------------------------------------// + public static void resetMessageId () + // ---------------------------------------------------------------------------------// + { + nextId = 0; + } } \ No newline at end of file diff --git a/src/com/bytezone/diskbrowser/wizardry/MessageBlock.java b/src/com/bytezone/diskbrowser/wizardry/MessageBlock.java index f4f95bf..a5f1845 100644 --- a/src/com/bytezone/diskbrowser/wizardry/MessageBlock.java +++ b/src/com/bytezone/diskbrowser/wizardry/MessageBlock.java @@ -7,7 +7,9 @@ import java.util.List; import com.bytezone.common.Utility; import com.bytezone.diskbrowser.applefile.AbstractFile; -public class MessageBlock extends AbstractFile implements Iterable +// -----------------------------------------------------------------------------------// +class MessageBlock extends AbstractFile implements Iterable +// -----------------------------------------------------------------------------------// { private final int indexOffset; private final int indexLength; @@ -15,7 +17,9 @@ public class MessageBlock extends AbstractFile implements Iterable messageDataBlocks = new ArrayList<> (); - public MessageBlock (byte[] buffer, Huffman huffman) + // ---------------------------------------------------------------------------------// + MessageBlock (byte[] buffer, Huffman huffman) + // ---------------------------------------------------------------------------------// { super ("bollocks", buffer); @@ -35,7 +39,9 @@ public class MessageBlock extends AbstractFile implements Iterable getMessageLines (int messageNo) + // ---------------------------------------------------------------------------------// { List lines = new ArrayList<> (); @@ -72,7 +80,9 @@ public class MessageBlock extends AbstractFile implements Iterable iterator () + // ---------------------------------------------------------------------------------// { return messageDataBlocks.iterator (); } diff --git a/src/com/bytezone/diskbrowser/wizardry/MessageDataBlock.java b/src/com/bytezone/diskbrowser/wizardry/MessageDataBlock.java index 107ecfc..dd2bc30 100644 --- a/src/com/bytezone/diskbrowser/wizardry/MessageDataBlock.java +++ b/src/com/bytezone/diskbrowser/wizardry/MessageDataBlock.java @@ -6,7 +6,9 @@ import java.util.List; import com.bytezone.common.Utility; import com.bytezone.diskbrowser.applefile.AbstractFile; -public class MessageDataBlock extends AbstractFile +// -----------------------------------------------------------------------------------// +class MessageDataBlock extends AbstractFile +// -----------------------------------------------------------------------------------// { final int firstMessageNo; final int lastMessageNo; @@ -16,8 +18,9 @@ public class MessageDataBlock extends AbstractFile private final Huffman huffman; - public MessageDataBlock (String name, byte[] buffer, int firstMessageNo, - Huffman huffman) + // ---------------------------------------------------------------------------------// + MessageDataBlock (String name, byte[] buffer, int firstMessageNo, Huffman huffman) + // ---------------------------------------------------------------------------------// { super (name, buffer); @@ -75,7 +78,9 @@ public class MessageDataBlock extends AbstractFile this.name += " - " + lastMessageNo; } + // ---------------------------------------------------------------------------------// byte[] getMessage (int messageNo) + // ---------------------------------------------------------------------------------// { for (Message message : messages) if (message.msgNo == messageNo) @@ -87,7 +92,9 @@ public class MessageDataBlock extends AbstractFile return null; } + // ---------------------------------------------------------------------------------// String getText (int messageNo) + // ---------------------------------------------------------------------------------// { for (Message message : messages) if (message.msgNo == messageNo) @@ -99,8 +106,10 @@ public class MessageDataBlock extends AbstractFile return null; } + // ---------------------------------------------------------------------------------// @Override public String getText () + // ---------------------------------------------------------------------------------// { if (messages.size () == 0) return "No Messages"; @@ -128,8 +137,10 @@ public class MessageDataBlock extends AbstractFile return text.toString (); } + // ---------------------------------------------------------------------------------// @Override public String toString () + // ---------------------------------------------------------------------------------// { StringBuilder text = new StringBuilder (); @@ -145,7 +156,9 @@ public class MessageDataBlock extends AbstractFile return text.toString (); } + // ---------------------------------------------------------------------------------// class Message + // ---------------------------------------------------------------------------------// { final int msgNo; final int offset; diff --git a/src/com/bytezone/diskbrowser/wizardry/Monster.java b/src/com/bytezone/diskbrowser/wizardry/Monster.java index 7972d0d..998c6f9 100755 --- a/src/com/bytezone/diskbrowser/wizardry/Monster.java +++ b/src/com/bytezone/diskbrowser/wizardry/Monster.java @@ -1,284 +1,309 @@ -package com.bytezone.diskbrowser.wizardry; - -import java.awt.image.BufferedImage; -import java.util.ArrayList; -import java.util.List; - -import com.bytezone.diskbrowser.applefile.AbstractFile; -import com.bytezone.diskbrowser.utilities.HexFormatter; - -class Monster extends AbstractFile implements Comparable -{ - public final String genericName; - public final String realName; - public final int monsterID; - List monsters; - Reward goldReward; - Reward chestReward; - - public final int type; - public final int imageID; - int rewardTable1; - int rewardTable2; - public final int partnerID; - public final int partnerOdds; - public final int armourClass; - public final int speed; - public final int mageSpellLevel; - public final int priestSpellLevel; - int levelDrain; - int bonus1; - int bonus2; - int bonus3; - int resistance; - int abilities; - public final Dice groupSize, hitPoints; - List damage = new ArrayList<> (); - - static int counter = 0; - static boolean debug = true; - static int[] pwr = { 0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 0, 0, 0, 0, 0 }; - static int[] weight1 = { 0, 1, 2, 4, 8, 16, 32, 64, 253, 506, 0 }; - static int[] weight2 = { 0, 60, 120, 180, 300, 540, 1020, 0 }; - - public static String[] monsterClass = - { "Fighter", "Mage", "Priest", "Thief", "Midget", "Giant", "Mythical", "Dragon", - "Animal", "Were", "Undead", "Demon", "Insect", "Enchanted" }; - - private static int[] experience = { 55, 235, 415, 230, 380, 620, 840, 520, 550, 350, // 00-09 - 475, 515, 920, 600, 735, 520, 795, 780, 990, 795, // 10-19 - 1360, 1320, 1275, 680, 960, 600, 755, 1120, 2075, - 870, // 20-29 - 960, 1120, 1120, 2435, 1080, 2280, 975, 875, 1135, - 1200, // 30-39 - 620, 740, 1460, 1245, 960, 1405, 1040, 1220, 1520, - 1000, // 40-49 - 960, 2340, 2160, 2395, 790, 1140, 1235, 1790, 1720, - 2240, // 50-59 - 1475, 1540, 1720, 1900, 1240, 1220, 1020, 20435, - 5100, 3515, // 60-69 - 2115, 2920, 2060, 2140, 1400, 1640, 1280, 4450, - 42840, 3300, // 70-79 - 40875, 5000, 3300, 2395, 1935, 1600, 3330, 44090, - 40840, 5200, // 80-89 - 4155, 3000, 9200, 3160, 7460, 7320, 15880, 1600, - 2200, 1000, 1900 // 90-100 - }; - - public Monster (String name, byte[] buffer, List rewards, - List monsters) - { - super (name, buffer); - - realName = name; - genericName = HexFormatter.getPascalString (buffer, 0); - this.monsterID = counter++; - this.monsters = monsters; - goldReward = rewards.get (buffer[136]); - chestReward = rewards.get (buffer[138]); - goldReward.addMonster (this, 0); - chestReward.addMonster (this, 1); - - imageID = buffer[64]; - type = buffer[78]; - armourClass = buffer[80]; - speed = buffer[82]; - levelDrain = buffer[132]; - bonus1 = buffer[134]; - rewardTable1 = buffer[136]; - rewardTable2 = buffer[138]; - partnerID = buffer[140]; - partnerOdds = buffer[142]; - mageSpellLevel = buffer[144]; - priestSpellLevel = buffer[146]; - bonus2 = buffer[150]; - bonus3 = buffer[152]; - resistance = buffer[154]; - abilities = buffer[156]; - groupSize = new Dice (buffer, 66); - hitPoints = new Dice (buffer, 72); - - for (int i = 0, ptr = 84; i < 8; i++, ptr += 6) - { - if (buffer[ptr] == 0) - break; - damage.add (new Dice (buffer, ptr)); - } - } - - @Override - public String getText () - { - StringBuilder text = new StringBuilder (); - - // these values definitely affect the damage a monster does (when breathing?) - int exp2 = ((buffer[72] & 0xFF) * (buffer[74] & 0xFF) - 1) * 20; - int exp3 = weight2[speed]; // 1-6 - int exp4 = (10 - armourClass) * 40; - int exp5 = getBonus (35, mageSpellLevel); - int exp6 = getBonus (35, priestSpellLevel); - int exp10 = getBonus (200, levelDrain); - int exp8 = getBonus (90, bonus1); - int exp7 = weight1[bonus3 / 10] * 80; - int exp11 = bonus2 > 0 ? exp2 + 20 : 0; - int exp12 = getBonus (35, Integer.bitCount (resistance & 0x7E)); - int exp9 = getBonus (40, Integer.bitCount (abilities & 0x7F)); - - text.append ("ID .............. " + monsterID); - text.append ("\nMonster name .... " + realName); - text.append ("\nGeneric name .... " + genericName); - - text.append ("\n\nImage ID ........ " + imageID); - text.append ("\nGroup size ...... " + groupSize); - text.append ("\nHit points ...... " + hitPoints); - if (debug) - text.append (" " + exp2); - - text.append ("\n\nMonster class ... " + type + " " + monsterClass[type]); - text.append ("\nArmour class .... " + armourClass); - if (debug) - text.append (" " + exp4); - text.append ("\nSpeed ........... " + speed); - if (debug) - text.append (" " + exp3); - - text.append ("\n\nDamage .......... " + getDamage ()); - - text.append ("\n\nLevel drain ..... " + levelDrain); - if (debug) - text.append (" " + exp10); - text.append ("\nExtra hit pts? .. " + bonus1); - if (debug) - text.append (" " + exp8); - - text.append ("\n\nPartner ID ...... " + partnerID); - if (partnerOdds > 0) - text.append (" " + monsters.get (partnerID).name); - text.append ("\nPartner odds .... " + partnerOdds + "%"); - - text.append ("\n\nMage level ...... " + mageSpellLevel); - if (debug) - text.append (" " + exp5); - text.append ("\nPriest level .... " + priestSpellLevel); - if (debug) - text.append (" " + exp6); - - text.append ("\n\nExperience bonus " + bonus2); - if (debug) - text.append (" " + exp11); - text.append ("\nExperience bonus " + bonus3); - if (debug) - text.append (" " + exp7); - - text.append ("\n\nResistance ...... " + String.format ("%02X", resistance)); - if (debug) - text.append (" " + exp12); - text.append ("\nAbilities ....... " + String.format ("%02X", abilities)); - if (debug) - text.append (" " + exp9); - - text.append ("\n\nExperience ...... " + (exp2 + exp3 + exp4 + exp5 + exp6 + exp7 - + exp8 + exp9 + exp10 + exp11 + exp12)); - - text.append ("\n\n===== Gold reward ======"); - // text.append ("\nTable ........... " + rewardTable1); - text.append ("\n" + goldReward.getText (false)); - text.append ("===== Chest reward ====="); - // text.append ("\nTable ........... " + rewardTable2); - text.append ("\n" + chestReward.getText (false)); - - while (text.charAt (text.length () - 1) == 10) - text.deleteCharAt (text.length () - 1); - - return text.toString (); - } - - public int getExperience () - { - // these values definitely affect the damage a monster does (when breathing?) - int exp2 = ((buffer[72] & 0xFF) * (buffer[74] & 0xFF) - 1) * 20; - int exp3 = weight2[speed]; - int exp4 = (10 - armourClass) * 40; - int exp5 = getBonus (35, mageSpellLevel); - int exp6 = getBonus (35, priestSpellLevel); - int exp10 = getBonus (200, levelDrain); - int exp8 = getBonus (90, bonus1); - int exp7 = weight1[bonus3 / 10] * 80; - int exp11 = bonus2 > 0 ? exp2 + 20 : 0; - int exp12 = getBonus (35, Integer.bitCount (resistance & 0x7E)); - int exp9 = getBonus (40, Integer.bitCount (abilities & 0x7F)); - return exp2 + exp3 + exp4 + exp5 + exp6 + exp7 + exp8 + exp9 + exp10 + exp11 + exp12; - } - - private int getBonus (int base, int value) - { - return base * pwr[value]; - } - - public void setImage (BufferedImage image) - { - this.image = image; - } - - @Override - public String getName () - { - return realName; - } - - public String getRealName () - { - return realName; - } - - public String getDamage () - { - StringBuilder text = new StringBuilder (); - for (Dice d : damage) - text.append (d + ", "); - text.deleteCharAt (text.length () - 1); - text.deleteCharAt (text.length () - 1); - return text.toString (); - } - - public String getDump (int block) - { - StringBuilder line = - new StringBuilder (String.format ("%3d %-16s", monsterID, realName)); - int lo = block == 0 ? 64 : block == 1 ? 88 : block == 2 ? 112 : 136; - int hi = lo + 24; - if (hi > buffer.length) - hi = buffer.length; - for (int i = lo; i < hi; i++) - line.append (String.format ("%02X ", buffer[i])); - if (block == 3) - { - int exp = getExperience (); - line.append (String.format (" %,6d", exp)); - if (exp != experience[monsterID]) - line.append (String.format (" %,6d", experience[monsterID])); - } - return line.toString (); - } - - public boolean match (int monsterID) - { - return this.monsterID == monsterID; - } - - @Override - public int compareTo (Monster other) // where is this used? - { - if (this.type == other.type) - return 0; - if (this.type < other.type) - return -1; - return 1; - } - - @Override - public String toString () - { - return realName; - } +package com.bytezone.diskbrowser.wizardry; + +import java.awt.image.BufferedImage; +import java.util.ArrayList; +import java.util.List; + +import com.bytezone.diskbrowser.applefile.AbstractFile; +import com.bytezone.diskbrowser.utilities.HexFormatter; + +// -----------------------------------------------------------------------------------// +class Monster extends AbstractFile implements Comparable +// -----------------------------------------------------------------------------------// +{ + public final String genericName; + public final String realName; + public final int monsterID; + List monsters; + Reward goldReward; + Reward chestReward; + + public final int type; + public final int imageID; + int rewardTable1; + int rewardTable2; + public final int partnerID; + public final int partnerOdds; + public final int armourClass; + public final int speed; + public final int mageSpellLevel; + public final int priestSpellLevel; + int levelDrain; + int bonus1; + int bonus2; + int bonus3; + int resistance; + int abilities; + public final Dice groupSize, hitPoints; + List damage = new ArrayList<> (); + + static int counter = 0; + static boolean debug = true; + static int[] pwr = { 0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 0, 0, 0, 0, 0 }; + static int[] weight1 = { 0, 1, 2, 4, 8, 16, 32, 64, 253, 506, 0 }; + static int[] weight2 = { 0, 60, 120, 180, 300, 540, 1020, 0 }; + + public static String[] monsterClass = + { "Fighter", "Mage", "Priest", "Thief", "Midget", "Giant", "Mythical", "Dragon", + "Animal", "Were", "Undead", "Demon", "Insect", "Enchanted" }; + + private static int[] experience = { 55, 235, 415, 230, 380, 620, 840, 520, 550, 350, // 00-09 + 475, 515, 920, 600, 735, 520, 795, 780, 990, 795, // 10-19 + 1360, 1320, 1275, 680, 960, 600, 755, 1120, 2075, + 870, // 20-29 + 960, 1120, 1120, 2435, 1080, 2280, 975, 875, 1135, + 1200, // 30-39 + 620, 740, 1460, 1245, 960, 1405, 1040, 1220, 1520, + 1000, // 40-49 + 960, 2340, 2160, 2395, 790, 1140, 1235, 1790, 1720, + 2240, // 50-59 + 1475, 1540, 1720, 1900, 1240, 1220, 1020, 20435, + 5100, 3515, // 60-69 + 2115, 2920, 2060, 2140, 1400, 1640, 1280, 4450, + 42840, 3300, // 70-79 + 40875, 5000, 3300, 2395, 1935, 1600, 3330, 44090, + 40840, 5200, // 80-89 + 4155, 3000, 9200, 3160, 7460, 7320, 15880, 1600, + 2200, 1000, 1900 // 90-100 + }; + + // ---------------------------------------------------------------------------------// + Monster (String name, byte[] buffer, List rewards, List monsters) + // ---------------------------------------------------------------------------------// + { + super (name, buffer); + + realName = name; + genericName = HexFormatter.getPascalString (buffer, 0); + this.monsterID = counter++; + this.monsters = monsters; + goldReward = rewards.get (buffer[136]); + chestReward = rewards.get (buffer[138]); + goldReward.addMonster (this, 0); + chestReward.addMonster (this, 1); + + imageID = buffer[64]; + type = buffer[78]; + armourClass = buffer[80]; + speed = buffer[82]; + levelDrain = buffer[132]; + bonus1 = buffer[134]; + rewardTable1 = buffer[136]; + rewardTable2 = buffer[138]; + partnerID = buffer[140]; + partnerOdds = buffer[142]; + mageSpellLevel = buffer[144]; + priestSpellLevel = buffer[146]; + bonus2 = buffer[150]; + bonus3 = buffer[152]; + resistance = buffer[154]; + abilities = buffer[156]; + groupSize = new Dice (buffer, 66); + hitPoints = new Dice (buffer, 72); + + for (int i = 0, ptr = 84; i < 8; i++, ptr += 6) + { + if (buffer[ptr] == 0) + break; + damage.add (new Dice (buffer, ptr)); + } + } + + // ---------------------------------------------------------------------------------// + @Override + public String getText () + // ---------------------------------------------------------------------------------// + { + StringBuilder text = new StringBuilder (); + + // these values definitely affect the damage a monster does (when breathing?) + int exp2 = ((buffer[72] & 0xFF) * (buffer[74] & 0xFF) - 1) * 20; + int exp3 = weight2[speed]; // 1-6 + int exp4 = (10 - armourClass) * 40; + int exp5 = getBonus (35, mageSpellLevel); + int exp6 = getBonus (35, priestSpellLevel); + int exp10 = getBonus (200, levelDrain); + int exp8 = getBonus (90, bonus1); + int exp7 = weight1[bonus3 / 10] * 80; + int exp11 = bonus2 > 0 ? exp2 + 20 : 0; + int exp12 = getBonus (35, Integer.bitCount (resistance & 0x7E)); + int exp9 = getBonus (40, Integer.bitCount (abilities & 0x7F)); + + text.append ("ID .............. " + monsterID); + text.append ("\nMonster name .... " + realName); + text.append ("\nGeneric name .... " + genericName); + + text.append ("\n\nImage ID ........ " + imageID); + text.append ("\nGroup size ...... " + groupSize); + text.append ("\nHit points ...... " + hitPoints); + if (debug) + text.append (" " + exp2); + + text.append ("\n\nMonster class ... " + type + " " + monsterClass[type]); + text.append ("\nArmour class .... " + armourClass); + if (debug) + text.append (" " + exp4); + text.append ("\nSpeed ........... " + speed); + if (debug) + text.append (" " + exp3); + + text.append ("\n\nDamage .......... " + getDamage ()); + + text.append ("\n\nLevel drain ..... " + levelDrain); + if (debug) + text.append (" " + exp10); + text.append ("\nExtra hit pts? .. " + bonus1); + if (debug) + text.append (" " + exp8); + + text.append ("\n\nPartner ID ...... " + partnerID); + if (partnerOdds > 0) + text.append (" " + monsters.get (partnerID).name); + text.append ("\nPartner odds .... " + partnerOdds + "%"); + + text.append ("\n\nMage level ...... " + mageSpellLevel); + if (debug) + text.append (" " + exp5); + text.append ("\nPriest level .... " + priestSpellLevel); + if (debug) + text.append (" " + exp6); + + text.append ("\n\nExperience bonus " + bonus2); + if (debug) + text.append (" " + exp11); + text.append ("\nExperience bonus " + bonus3); + if (debug) + text.append (" " + exp7); + + text.append ("\n\nResistance ...... " + String.format ("%02X", resistance)); + if (debug) + text.append (" " + exp12); + text.append ("\nAbilities ....... " + String.format ("%02X", abilities)); + if (debug) + text.append (" " + exp9); + + text.append ("\n\nExperience ...... " + (exp2 + exp3 + exp4 + exp5 + exp6 + exp7 + + exp8 + exp9 + exp10 + exp11 + exp12)); + + text.append ("\n\n===== Gold reward ======"); + // text.append ("\nTable ........... " + rewardTable1); + text.append ("\n" + goldReward.getText (false)); + text.append ("===== Chest reward ====="); + // text.append ("\nTable ........... " + rewardTable2); + text.append ("\n" + chestReward.getText (false)); + + while (text.charAt (text.length () - 1) == 10) + text.deleteCharAt (text.length () - 1); + + return text.toString (); + } + + // ---------------------------------------------------------------------------------// + public int getExperience () + // ---------------------------------------------------------------------------------// + { + // these values definitely affect the damage a monster does (when breathing?) + int exp2 = ((buffer[72] & 0xFF) * (buffer[74] & 0xFF) - 1) * 20; + int exp3 = weight2[speed]; + int exp4 = (10 - armourClass) * 40; + int exp5 = getBonus (35, mageSpellLevel); + int exp6 = getBonus (35, priestSpellLevel); + int exp10 = getBonus (200, levelDrain); + int exp8 = getBonus (90, bonus1); + int exp7 = weight1[bonus3 / 10] * 80; + int exp11 = bonus2 > 0 ? exp2 + 20 : 0; + int exp12 = getBonus (35, Integer.bitCount (resistance & 0x7E)); + int exp9 = getBonus (40, Integer.bitCount (abilities & 0x7F)); + return exp2 + exp3 + exp4 + exp5 + exp6 + exp7 + exp8 + exp9 + exp10 + exp11 + exp12; + } + + // ---------------------------------------------------------------------------------// + private int getBonus (int base, int value) + // ---------------------------------------------------------------------------------// + { + return base * pwr[value]; + } + + // ---------------------------------------------------------------------------------// + public void setImage (BufferedImage image) + // ---------------------------------------------------------------------------------// + { + this.image = image; + } + + // ---------------------------------------------------------------------------------// + @Override + public String getName () + // ---------------------------------------------------------------------------------// + { + return realName; + } + + // ---------------------------------------------------------------------------------// + public String getRealName () + // ---------------------------------------------------------------------------------// + { + return realName; + } + + // ---------------------------------------------------------------------------------// + public String getDamage () + // ---------------------------------------------------------------------------------// + { + StringBuilder text = new StringBuilder (); + for (Dice d : damage) + text.append (d + ", "); + text.deleteCharAt (text.length () - 1); + text.deleteCharAt (text.length () - 1); + return text.toString (); + } + + // ---------------------------------------------------------------------------------// + public String getDump (int block) + // ---------------------------------------------------------------------------------// + { + StringBuilder line = + new StringBuilder (String.format ("%3d %-16s", monsterID, realName)); + int lo = block == 0 ? 64 : block == 1 ? 88 : block == 2 ? 112 : 136; + int hi = lo + 24; + if (hi > buffer.length) + hi = buffer.length; + for (int i = lo; i < hi; i++) + line.append (String.format ("%02X ", buffer[i])); + if (block == 3) + { + int exp = getExperience (); + line.append (String.format (" %,6d", exp)); + if (exp != experience[monsterID]) + line.append (String.format (" %,6d", experience[monsterID])); + } + return line.toString (); + } + + // ---------------------------------------------------------------------------------// + public boolean match (int monsterID) + // ---------------------------------------------------------------------------------// + { + return this.monsterID == monsterID; + } + + // ---------------------------------------------------------------------------------// + @Override + public int compareTo (Monster other) // where is this used? + // ---------------------------------------------------------------------------------// + { + if (this.type == other.type) + return 0; + if (this.type < other.type) + return -1; + return 1; + } + + // ---------------------------------------------------------------------------------// + @Override + public String toString () + // ---------------------------------------------------------------------------------// + { + return realName; + } } \ No newline at end of file diff --git a/src/com/bytezone/diskbrowser/wizardry/PlainMessage.java b/src/com/bytezone/diskbrowser/wizardry/PlainMessage.java index 5cb3cd8..a292413 100755 --- a/src/com/bytezone/diskbrowser/wizardry/PlainMessage.java +++ b/src/com/bytezone/diskbrowser/wizardry/PlainMessage.java @@ -1,18 +1,24 @@ -package com.bytezone.diskbrowser.wizardry; - -import com.bytezone.diskbrowser.utilities.HexFormatter; - -class PlainMessage extends Message -{ - public PlainMessage (byte[] buffer) - { - super (buffer); - } - - @Override - protected String getLine (int offset) - { - int length = buffer[offset] & 0xFF; - return HexFormatter.getString (buffer, offset + 1, length); - } +package com.bytezone.diskbrowser.wizardry; + +import com.bytezone.diskbrowser.utilities.HexFormatter; + +// -----------------------------------------------------------------------------------// +class PlainMessage extends Message +// -----------------------------------------------------------------------------------// +{ + // ---------------------------------------------------------------------------------// + PlainMessage (byte[] buffer) + // ---------------------------------------------------------------------------------// + { + super (buffer); + } + + // ---------------------------------------------------------------------------------// + @Override + protected String getLine (int offset) + // ---------------------------------------------------------------------------------// + { + int length = buffer[offset] & 0xFF; + return HexFormatter.getString (buffer, offset + 1, length); + } } \ No newline at end of file diff --git a/src/com/bytezone/diskbrowser/wizardry/Relocator.java b/src/com/bytezone/diskbrowser/wizardry/Relocator.java index f3453d3..9086449 100644 --- a/src/com/bytezone/diskbrowser/wizardry/Relocator.java +++ b/src/com/bytezone/diskbrowser/wizardry/Relocator.java @@ -9,7 +9,9 @@ import com.bytezone.diskbrowser.disk.Disk; import com.bytezone.diskbrowser.disk.DiskAddress; import com.bytezone.diskbrowser.utilities.HexFormatter; +// -----------------------------------------------------------------------------------// public class Relocator extends AbstractFile +// -----------------------------------------------------------------------------------// { private final int checkByte; private final List diskRecords = new ArrayList<> (); @@ -17,7 +19,9 @@ public class Relocator extends AbstractFile private final int[] diskBlocks = new int[0x800]; private final int[] diskOffsets = new int[0x800]; + // ---------------------------------------------------------------------------------// public Relocator (String name, byte[] buffer) + // ---------------------------------------------------------------------------------// { super (name, buffer); @@ -37,7 +41,9 @@ public class Relocator extends AbstractFile addLogicalBlock ((byte) diskRecord.diskNumber, diskSegment); } + // ---------------------------------------------------------------------------------// private void addLogicalBlock (byte disk, DiskSegment diskSegment) + // ---------------------------------------------------------------------------------// { int lo = diskSegment.logicalBlock; int hi = diskSegment.logicalBlock + diskSegment.segmentLength; @@ -50,7 +56,9 @@ public class Relocator extends AbstractFile } } + // ---------------------------------------------------------------------------------// public void createNewBuffer (Disk[] dataDisks) + // ---------------------------------------------------------------------------------// { AppleDisk master = (AppleDisk) dataDisks[0]; // byte[] key1 = { 0x55, 0x55, 0x15, 0x55 }; @@ -78,8 +86,10 @@ public class Relocator extends AbstractFile } } + // ---------------------------------------------------------------------------------// @Override public String getText () + // ---------------------------------------------------------------------------------// { StringBuilder text = new StringBuilder (); @@ -149,7 +159,9 @@ public class Relocator extends AbstractFile return text.toString (); } + // ---------------------------------------------------------------------------------// private class DiskRecord + // ---------------------------------------------------------------------------------// { int diskNumber; int totDiskSegments; @@ -202,7 +214,9 @@ public class Relocator extends AbstractFile } } + // ---------------------------------------------------------------------------------// private class DiskSegment + // ---------------------------------------------------------------------------------// { int logicalBlock; int physicalBlock; diff --git a/src/com/bytezone/diskbrowser/wizardry/Reward.java b/src/com/bytezone/diskbrowser/wizardry/Reward.java index 8a40c30..d5313df 100755 --- a/src/com/bytezone/diskbrowser/wizardry/Reward.java +++ b/src/com/bytezone/diskbrowser/wizardry/Reward.java @@ -1,141 +1,155 @@ -package com.bytezone.diskbrowser.wizardry; - -import java.util.ArrayList; -import java.util.List; - -import com.bytezone.diskbrowser.applefile.AbstractFile; - -class Reward extends AbstractFile -{ - static String[] types = { "gold", "item" }; - static final int SEGMENT_LENGTH = 18; - int id; - int totalElements; - List elements; - List items; - List goldMonsters = new ArrayList<> (); - List chestMonsters = new ArrayList<> (); - - public Reward (String name, byte[] buffer, int id, List items) - { - super (name, buffer); - this.id = id; - this.items = items; - totalElements = buffer[4]; - elements = new ArrayList<> (totalElements); - - for (int i = 0; i < totalElements; i++) - { - byte[] buffer2 = new byte[SEGMENT_LENGTH]; - System.arraycopy (buffer, i * SEGMENT_LENGTH, buffer2, 0, SEGMENT_LENGTH); - elements.add (new RewardElement (buffer2)); - } - } - - public void addMonster (Monster monster, int location) - { - if (location == 0) - goldMonsters.add (monster); - else - chestMonsters.add (monster); - } - - @Override - public String getText () - { - return getText (true); - } - - public String getText (boolean showLinks) - { - StringBuilder text = new StringBuilder (); - for (RewardElement re : elements) - text.append (re.getDetail () + "\n"); - - if (showLinks) - { - if (goldMonsters.size () > 0) - { - text.append ("Without chest:\n\n"); - for (Monster m : goldMonsters) - text.append (" " + m + "\n"); - text.append ("\n"); - } - if (chestMonsters.size () > 0) - { - text.append ("With chest:\n\n"); - for (Monster m : chestMonsters) - text.append (" " + m + "\n"); - } - } - return text.toString (); - } - - public String getDump () - { - StringBuilder text = new StringBuilder (); - int seq = 0; - for (RewardElement re : elements) - { - text.append (seq++ == 0 ? String.format ("%02X : ", id) : " "); - text.append (re + "\n"); - } - - return text.toString (); - } - - private class RewardElement - { - int type; - int odds; - byte[] buffer; - - public RewardElement (byte[] buffer) - { - this.buffer = buffer; - type = buffer[8]; - odds = buffer[6]; - } - - @Override - public String toString () - { - StringBuilder text = new StringBuilder (); - for (int i = 0; i < SEGMENT_LENGTH; i += 2) - text.append (String.format ("%3d ", buffer[i] & 0xFF)); - return text.toString (); - } - - public String getDetail () - { - StringBuilder text = new StringBuilder (); - text.append ("Odds ............ " + odds + "%\n"); - - switch (type) - { - case 0: - text.append ("Gold ............ " + buffer[10] + "d" + buffer[12] + "\n"); - break; - case 1: - int lo = buffer[10] & 0xFF; - int qty = buffer[16] & 0xFF; - boolean title = true; - String[] lineItem = new String[4]; - for (int i = lo, max = lo + qty; i <= max; i += lineItem.length) - { - String lineTitle = title ? "Items ..........." : ""; - title = false; - for (int j = 0; j < lineItem.length; j++) - lineItem[j] = i + j <= max ? items.get (i + j).getName () : ""; - text.append (String.format ("%-17s %-16s %-16s %-16s %-16s%n", lineTitle, - lineItem[0], lineItem[1], lineItem[2], lineItem[3])); - } - break; - default: - System.out.println ("Unknown reward type " + type); - } - - return text.toString (); - } - } +package com.bytezone.diskbrowser.wizardry; + +import java.util.ArrayList; +import java.util.List; + +import com.bytezone.diskbrowser.applefile.AbstractFile; + +// -----------------------------------------------------------------------------------// +class Reward extends AbstractFile +// -----------------------------------------------------------------------------------// +{ + static String[] types = { "gold", "item" }; + static final int SEGMENT_LENGTH = 18; + int id; + int totalElements; + List elements; + List items; + List goldMonsters = new ArrayList<> (); + List chestMonsters = new ArrayList<> (); + + // ---------------------------------------------------------------------------------// + Reward (String name, byte[] buffer, int id, List items) + // ---------------------------------------------------------------------------------// + { + super (name, buffer); + this.id = id; + this.items = items; + totalElements = buffer[4]; + elements = new ArrayList<> (totalElements); + + for (int i = 0; i < totalElements; i++) + { + byte[] buffer2 = new byte[SEGMENT_LENGTH]; + System.arraycopy (buffer, i * SEGMENT_LENGTH, buffer2, 0, SEGMENT_LENGTH); + elements.add (new RewardElement (buffer2)); + } + } + + // ---------------------------------------------------------------------------------// + public void addMonster (Monster monster, int location) + // ---------------------------------------------------------------------------------// + { + if (location == 0) + goldMonsters.add (monster); + else + chestMonsters.add (monster); + } + + // ---------------------------------------------------------------------------------// + @Override + public String getText () + // ---------------------------------------------------------------------------------// + { + return getText (true); + } + + // ---------------------------------------------------------------------------------// + public String getText (boolean showLinks) + // ---------------------------------------------------------------------------------// + { + StringBuilder text = new StringBuilder (); + for (RewardElement re : elements) + text.append (re.getDetail () + "\n"); + + if (showLinks) + { + if (goldMonsters.size () > 0) + { + text.append ("Without chest:\n\n"); + for (Monster m : goldMonsters) + text.append (" " + m + "\n"); + text.append ("\n"); + } + if (chestMonsters.size () > 0) + { + text.append ("With chest:\n\n"); + for (Monster m : chestMonsters) + text.append (" " + m + "\n"); + } + } + return text.toString (); + } + + // ---------------------------------------------------------------------------------// + public String getDump () + // ---------------------------------------------------------------------------------// + { + StringBuilder text = new StringBuilder (); + int seq = 0; + for (RewardElement re : elements) + { + text.append (seq++ == 0 ? String.format ("%02X : ", id) : " "); + text.append (re + "\n"); + } + + return text.toString (); + } + + // ---------------------------------------------------------------------------------// + private class RewardElement + // ---------------------------------------------------------------------------------// + { + int type; + int odds; + byte[] buffer; + + public RewardElement (byte[] buffer) + { + this.buffer = buffer; + type = buffer[8]; + odds = buffer[6]; + } + + @Override + public String toString () + { + StringBuilder text = new StringBuilder (); + for (int i = 0; i < SEGMENT_LENGTH; i += 2) + text.append (String.format ("%3d ", buffer[i] & 0xFF)); + return text.toString (); + } + + public String getDetail () + { + StringBuilder text = new StringBuilder (); + text.append ("Odds ............ " + odds + "%\n"); + + switch (type) + { + case 0: + text.append ("Gold ............ " + buffer[10] + "d" + buffer[12] + "\n"); + break; + case 1: + int lo = buffer[10] & 0xFF; + int qty = buffer[16] & 0xFF; + boolean title = true; + String[] lineItem = new String[4]; + for (int i = lo, max = lo + qty; i <= max; i += lineItem.length) + { + String lineTitle = title ? "Items ..........." : ""; + title = false; + for (int j = 0; j < lineItem.length; j++) + lineItem[j] = i + j <= max ? items.get (i + j).getName () : ""; + text.append (String.format ("%-17s %-16s %-16s %-16s %-16s%n", lineTitle, + lineItem[0], lineItem[1], lineItem[2], lineItem[3])); + } + break; + default: + System.out.println ("Unknown reward type " + type); + } + + return text.toString (); + } + } } \ No newline at end of file diff --git a/src/com/bytezone/diskbrowser/wizardry/Spell.java b/src/com/bytezone/diskbrowser/wizardry/Spell.java index bd3b10c..9b46040 100755 --- a/src/com/bytezone/diskbrowser/wizardry/Spell.java +++ b/src/com/bytezone/diskbrowser/wizardry/Spell.java @@ -1,369 +1,408 @@ -package com.bytezone.diskbrowser.wizardry; - -import com.bytezone.diskbrowser.applefile.AbstractFile; - -class Spell extends AbstractFile -{ - private final SpellType spellType; - private SpellThrown whenCast; - private final int level; - private String translation; - private SpellTarget target; - private String description; - - public enum SpellType { - MAGE, PRIEST - }; - - public enum SpellTarget { - PERSON, PARTY, MONSTER, MONSTER_GROUP, ALL_MONSTERS, VARIABLE, NONE, CASTER - }; - - public enum SpellThrown { - COMBAT, ANY_TIME, LOOTING, CAMP, COMBAT_OR_CAMP - }; - - private static int lastSpellFound = -1; - - private Spell (String spellName, SpellType type, int level, byte[] buffer) - { - super (spellName, buffer); - this.spellType = type; - this.level = level; - - if (lastSpellFound + 1 < spellNames.length && spellName.equals (spellNames[lastSpellFound + 1])) - setSpell (++lastSpellFound); - else - { - for (int i = 0; i < spellNames.length; i++) - if (spellName.equals (spellNames[i])) - { - setSpell (i); - lastSpellFound = i; - break; - } - } - } - - private void setSpell (int spellNo) - { - this.translation = translations[spellNo]; - this.description = descriptions[spellNo]; - this.whenCast = when[spellNo]; - this.target = affects[spellNo]; - } - - public static Spell getSpell (String spellName, SpellType type, int level, byte[] buffer) - { - return new Spell (spellName, type, level, buffer); - } - - public String getName () - { - return name; - } - - public SpellType getType () - { - return spellType; - } - - public int getLevel () - { - return level; - } - - public String getTranslation () - { - return translation; - } - - @Override - public String getText () - { - return description; - } - - public String getWhenCast () - { - switch (whenCast) - { - case COMBAT: - return "Combat"; - case LOOTING: - return "Looting"; - case ANY_TIME: - return "Any time"; - case CAMP: - return "Camp"; - case COMBAT_OR_CAMP: - return "Combat or camp"; - default: - return "?"; - } - - } - - public String getArea () - { - switch (target) - { - case PERSON: - return "1 Person"; - case PARTY: - return "Entire party"; - case MONSTER: - return "1 Monster"; - case MONSTER_GROUP: - return "1 Monster group"; - case ALL_MONSTERS: - return "All monsters"; - case VARIABLE: - return "Variable"; - case NONE: - return "None"; - case CASTER: - return "Caster"; - default: - return "?"; - } - - } - - public String toHTMLTable () - { - StringBuilder text = new StringBuilder ("\n"); - - text.append (" \n \n"); - text.append (" \n \n"); - - text.append (" \n \n"); - text.append (" \n \n"); - - text.append (" \n \n"); - text.append (" \n \n"); - - text.append (" \n \n"); - text.append (" \n \n"); - - text.append (" \n \n"); - text.append (" \n \n"); - - text.append (" \n \n"); - text.append (" \n \n"); - - text.append ("
Spell name" + name + "
Translation" + translation + "
Spell level" + level + "
Spell type" + getWhenCast () + "
Area of effect" + getArea () + "
Description" + getText () + "
"); - return text.toString (); - } - - @Override - public String toString () - { - StringBuilder text = new StringBuilder (name); - while (text.length () < 14) - text.append (" "); - if (spellType == SpellType.PRIEST) - text.append ("P"); - else - text.append ("M"); - text.append (level); - while (text.length () < 20) - text.append (" "); - text.append (translation); - while (text.length () < 40) - text.append (" "); - text.append (getArea ()); - while (text.length () < 60) - text.append (" "); - text.append (getWhenCast ()); - return text.toString (); - } - - private static String[] spellNames = - { "KALKI", "DIOS", "BADIOS", "MILWA", "PORFIC", "MATU", "CALFO", "MANIFO", "MONTINO", - "LOMILWA", "DIALKO", "LATUMAPIC", "BAMATU", "DIAL", "BADIAL", "LATUMOFIS", "MAPORFIC", - "DIALMA", "BADIALMA", "LITOKAN", "KANDI", "DI", "BADI", "LORTO", "MADI", "MABADI", - "LOKTOFEIT", "MALIKTO", "KADORTO", - - "HALITO", "MOGREF", "KATINO", "DUMAPIC", "DILTO", "SOPIC", "MAHALITO", "MOLITO", - "MORLIS", "DALTO", "LAHALITO", "MAMORLIS", "MAKANITO", "MADALTO", "LAKANITO", "ZILWAN", - "MASOPIC", "HAMAN", "MALOR", "MAHAMAN", "TILTOWAIT" }; - - private static String[] translations = - { "Blessings", "Heal", "Harm", "Light", "Shield", "Blessing & zeal", "X-ray vision", - "Statue", "Still air", "More light", "Softness/supple", "Identification", "Prayer", - "Heal (more)", "Hurt (more)", "Cure poison", "Shield (big)", "Heal (greatly)", - "Hurt (greatly)", "Flame tower", "Location", "Life", "Death", "Blades", "Healing", - "Harm (incredibly)", "Recall", "The Word of Death", "Resurrection", - - "Little Fire", "Body Iron", "Bad Air", "Clarity", "Darkness", "Glass", "Big fire", - "Spark storm", "Fear", "Blizzard blast", "Flame storm", "Terror", "Deadly air", "Frost", - "Suffocation", "Dispell", "Big glass", "Change", "Apport", "Great change", - "(untranslatable)" }; - - private static SpellThrown[] when = - { SpellThrown.COMBAT, SpellThrown.ANY_TIME, SpellThrown.COMBAT, SpellThrown.ANY_TIME, - SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.LOOTING, SpellThrown.COMBAT, - SpellThrown.COMBAT, SpellThrown.ANY_TIME, SpellThrown.ANY_TIME, SpellThrown.COMBAT, - SpellThrown.COMBAT, SpellThrown.ANY_TIME, SpellThrown.COMBAT, SpellThrown.ANY_TIME, - SpellThrown.ANY_TIME, SpellThrown.ANY_TIME, SpellThrown.COMBAT, SpellThrown.COMBAT, - SpellThrown.CAMP, SpellThrown.CAMP, SpellThrown.COMBAT, SpellThrown.COMBAT, - SpellThrown.ANY_TIME, SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.COMBAT, - SpellThrown.ANY_TIME, - - SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.CAMP, - SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.COMBAT, - SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.COMBAT, - SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.COMBAT, - SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.COMBAT_OR_CAMP, SpellThrown.COMBAT, - SpellThrown.COMBAT, }; - - private static SpellTarget[] affects = - { SpellTarget.PARTY, SpellTarget.PERSON, SpellTarget.MONSTER, SpellTarget.PARTY, - SpellTarget.CASTER, SpellTarget.PARTY, SpellTarget.CASTER, SpellTarget.MONSTER_GROUP, - SpellTarget.MONSTER_GROUP, SpellTarget.PARTY, SpellTarget.PERSON, SpellTarget.PARTY, - SpellTarget.PARTY, SpellTarget.PERSON, SpellTarget.MONSTER, SpellTarget.PERSON, - SpellTarget.PARTY, SpellTarget.PERSON, SpellTarget.MONSTER, SpellTarget.PARTY, - SpellTarget.PERSON, SpellTarget.PERSON, SpellTarget.MONSTER, SpellTarget.MONSTER_GROUP, - SpellTarget.PERSON, SpellTarget.MONSTER, SpellTarget.PARTY, SpellTarget.MONSTER_GROUP, - SpellTarget.PERSON, - - SpellTarget.MONSTER, SpellTarget.CASTER, SpellTarget.MONSTER_GROUP, SpellTarget.NONE, - SpellTarget.MONSTER_GROUP, SpellTarget.CASTER, SpellTarget.MONSTER_GROUP, - SpellTarget.MONSTER_GROUP, SpellTarget.MONSTER_GROUP, SpellTarget.MONSTER_GROUP, - SpellTarget.MONSTER_GROUP, SpellTarget.ALL_MONSTERS, SpellTarget.ALL_MONSTERS, - SpellTarget.MONSTER_GROUP, SpellTarget.MONSTER_GROUP, SpellTarget.MONSTER, - SpellTarget.PARTY, SpellTarget.VARIABLE, SpellTarget.PARTY, SpellTarget.PARTY, - SpellTarget.ALL_MONSTERS }; - - private static String[] descriptions = - { - "KALKI reduces the AC of all party members by one, and thus makes" - + " them harder to hit.", - "DIOS restores from one to eight hit points of damage from a party" - + "member. It will not bring dead back to life.", - "BADIOS causes one to eight hit points of damage to a monster, and" - + " may kill it. It is the reverse of dios. Note the BA prefix which" - + " means 'not'.", - "MILWA causes a softly glowing light to follow the party, allowing" - + " them to see further into the maze, and also revealing all secret" - + " doors. See also LOMILWA. This spell lasts only a short while.", - "PORFIC lowers the AC of the caster considerably. The effects last" - + " for the duration of combat.", - "MATU has the same effects as KALKI, but at double the strength.", - "CALFO allows the caster to determine the exact nature of a trap" - + " on a chest 95% of the time.", - "MANIFO causes some of the monsters in a group to become stiff as" - + " statues for one or more melee rounds. The chance of success," - + " and the duration of the effects, depend on the power of the" - + " target monsters.", - "MONTINO causes the air around a group of monsters to stop" - + " transmitting sound. Like MANIFO, only some of the monsters will" - + " be affected, and for varying lengths of time. Monsters and" - + " Party members under the influence of this spell cannot cast" - + " spells, as they cannot utter the spell words!", - "LOMILWA is a MILWA spell with a much longer life span. Note that" - + " when this spell, or MILWA are active, the Q option while" - + " moving through the maze is active. If Q)UICK PLOTTING is on," - + " only the square you are in, and the next two squares, will" - + " plot. Normally you might see five or six squares ahead with" - + " LOMILWA on. Quick Plotting lets you move fast through known" - + " areas. Note that it will be turned off when you enter camp or" - + " combat mode.", - "DIALKO cures paralysis, and removes the effects of MANIFO and" - + " KATINO from one member of the party.", - "LATUMAPIC makes it readily apparent exactly what the opposing" + " monsters really are.", - "BAMATU has the effects of MATU at twice the effectiveness.", - "DIAL restores two to 16 hit points of damage, and is similar to" + " DIOS.", - "BADIAL causes two to 16 hit points of damage in the same way as" + " BADIOS.", - "LATUMOFIS makes a poisoned person whole and fit again. Note that" - + " poison causes a person to lose hit points steadily during" - + " movement and combat.", - "MAPORFIC is an improved PORFIC, with effects that last for the" + " entire expedition.", - "DIALMA restores three to 24 hit points.", - "BADIALMA causes three to 24 hit points of damage.", - "LITOKAN causes a pillar of flame to strike a group of monsters," - + " doing three to 24 hits of damage to each. However, as with" - + " many spells that affect entire groups, there is a chance that" - + " individual monsters will be able to avoid or minimise its" - + " effects. And some monsters will be resistant to it.", - "KANDI allows the user to locate characters in the maze. It tells on" - + " which level, and in which rough area the dead one can be found.", - "DI causes a dead person to be resurrected. However, the renewed" - + " character has but one hit point. Also, this spell is not as" - + " effective or as safe as using the Temple.", - "BADI gives the affected monster a coronary attack. It may or may" - + " not cause death to occur.", - "LORTO causes sharp blades to slice through a group, causing six to" - + " 36 points of damage.", - "MADI causes all hit points to be restored and cures any condition" + " but death.", - "MABADI causes all but one to eight hit points to be removed from" + " the target.", - "LOKTOFEIT causes all party members to be teleported back to the" - + " castle, minus all their equipment and most of their gold. There" - + " is also a good chance this spell will not function.", - "MALIKTO causes 12 to 72 hit points of damage to all monsters. None" - + " can escape or minimise its effects.", - "KADORTO restores the dead to life as does DI, but also restores all" - + " hit points. However, it has the same drawbacks as the DI spell." - + " KADORTO can be used to resurrect people even if they are ashes.", - - "HALITO causes a flame ball the size of a baseball to hit a monster," - + " doing from one to eight points of damage.", - "MOGREF reduces the caster's AC by two. The effect lasts the entire" + " encounter.", - "KATINO causes most of the monsters in a group to fall asleep." - + " Katino only effects normal, animal or humanoid monsters. The" - + " chance of the spell affecting an individual monster, and the" - + " duration of the effect, is inversely proportional to the power" - + " of the monster. While asleep, monsters are easier to hit and" - + " successful strikes do double damage.", - "DUMAPIC informs you of the party's exact displacement from the" - + " stairs to the castle, vertically, and North and East, and also" - + " tells you what direction you are facing.", - - "DILTO causes one group of monsters to be enveloped in darkness," - + " which reduces their ability to defend against your attacks.", - "SOPIC causes the caster to become transparent. This means that" - + " he is harder to see, and thus his AC is reduced by four.", - - "MAHALITO causes a fiery explosion in a monster group, doing four" - + " to 24 hit points of damage. As with other similar spells," - + " monsters may be able to minimise the damage done.", - "MOLITO causes sparks to fly out and damage about half of the" - + " monsters in a group. Three to 18 hit points of damage are done" - + " with no chance of avoiding the sparks.", - "MORLIS causes one group of monsters to fear the party greatly. The" - + " effects are the same as a double strength DILTO spell.", - "DALTO is similar to MAHALITO except that cold replaces flames." - + " Also, six to 36 hit points of damage are done.", - "LAHALITO is an improved MAHALITO, doing the same damage as DALTO.", - "MAMORLIS is similar to MORLIS, except that all monster groups are" + " affected.", - "Any monsters of less than eigth level (i.e. about 35-40 hit points)" - + " are killed by this spell outright.", - "An improved DALTO causing eight to 64 hit points of damage.", - "All monsters in the group affected by this spell die. Of course," - + " there is a chance that some of the monsters will not be affected.", - "This spell will destroy any one monster that is of the Undead" + " variety", - "This spell duplicates the effects of SOPIC for the entire party.", - "This spell is indeed terrible, and may backfire on the caster." - + " First, to even cast it, you must be of the thirteenth level or" - + " higher, and casting it will cost you one level of experience." - + " The effects of HAMAN are random, and usually help the party.", - "This spell's effects depend on the situation the party is in when it" - + " is cast.Basically, MALOR will teleport the entire party from one" - + " location to another. When used in melee, the teleport is random," - + " but when used in camp, where there is more chance for concentration" - + ", it can be used to move the party anywhere in the maze. Be warned," - + " however, that if you teleport outside of the maze, or into an" - + " area that is solid rock, you will be lost forever, so this spell" - + " is to be used with the greatest of care. Combat use of MALOR will" - + " never put you outside of the maze, but it may move you deeper in," - + " so it should be used only in panic situations.", - "The same restrictions and qualifications apply to this spell as do" - + " to HAMAN. However, the effects are even greater. Generally these" - + " spells are only used when there is no other hope for survival.", - "The effect of this spell can be described as similar to that of a" - + " nuclear fusion explosion. Luckily the party is shielded from its" - + " effects. Unluckily (for them) the monsters are not. This spell" - + " will do from 10-100 hit points of damage." }; +package com.bytezone.diskbrowser.wizardry; + +import com.bytezone.diskbrowser.applefile.AbstractFile; + +// -----------------------------------------------------------------------------------// +class Spell extends AbstractFile +// -----------------------------------------------------------------------------------// +{ + private final SpellType spellType; + private SpellThrown whenCast; + private final int level; + private String translation; + private SpellTarget target; + private String description; + + public enum SpellType + { + MAGE, PRIEST + }; + + public enum SpellTarget + { + PERSON, PARTY, MONSTER, MONSTER_GROUP, ALL_MONSTERS, VARIABLE, NONE, CASTER + }; + + public enum SpellThrown + { + COMBAT, ANY_TIME, LOOTING, CAMP, COMBAT_OR_CAMP + }; + + private static int lastSpellFound = -1; + + // ---------------------------------------------------------------------------------// + private Spell (String spellName, SpellType type, int level, byte[] buffer) + // ---------------------------------------------------------------------------------// + { + super (spellName, buffer); + this.spellType = type; + this.level = level; + + if (lastSpellFound + 1 < spellNames.length + && spellName.equals (spellNames[lastSpellFound + 1])) + setSpell (++lastSpellFound); + else + { + for (int i = 0; i < spellNames.length; i++) + if (spellName.equals (spellNames[i])) + { + setSpell (i); + lastSpellFound = i; + break; + } + } + } + + // ---------------------------------------------------------------------------------// + private void setSpell (int spellNo) + // ---------------------------------------------------------------------------------// + { + this.translation = translations[spellNo]; + this.description = descriptions[spellNo]; + this.whenCast = when[spellNo]; + this.target = affects[spellNo]; + } + + // ---------------------------------------------------------------------------------// + public static Spell getSpell (String spellName, SpellType type, int level, + byte[] buffer) + // ---------------------------------------------------------------------------------// + { + return new Spell (spellName, type, level, buffer); + } + + // ---------------------------------------------------------------------------------// + @Override + public String getName () + // ---------------------------------------------------------------------------------// + { + return name; + } + + // ---------------------------------------------------------------------------------// + public SpellType getType () + // ---------------------------------------------------------------------------------// + { + return spellType; + } + + // ---------------------------------------------------------------------------------// + public int getLevel () + // ---------------------------------------------------------------------------------// + { + return level; + } + + // ---------------------------------------------------------------------------------// + public String getTranslation () + // ---------------------------------------------------------------------------------// + { + return translation; + } + + // ---------------------------------------------------------------------------------// + @Override + public String getText () + // ---------------------------------------------------------------------------------// + { + return description; + } + + // ---------------------------------------------------------------------------------// + public String getWhenCast () + // ---------------------------------------------------------------------------------// + { + switch (whenCast) + { + case COMBAT: + return "Combat"; + case LOOTING: + return "Looting"; + case ANY_TIME: + return "Any time"; + case CAMP: + return "Camp"; + case COMBAT_OR_CAMP: + return "Combat or camp"; + default: + return "?"; + } + + } + + // ---------------------------------------------------------------------------------// + public String getArea () + // ---------------------------------------------------------------------------------// + { + switch (target) + { + case PERSON: + return "1 Person"; + case PARTY: + return "Entire party"; + case MONSTER: + return "1 Monster"; + case MONSTER_GROUP: + return "1 Monster group"; + case ALL_MONSTERS: + return "All monsters"; + case VARIABLE: + return "Variable"; + case NONE: + return "None"; + case CASTER: + return "Caster"; + default: + return "?"; + } + } + + // ---------------------------------------------------------------------------------// + public String toHTMLTable () + // ---------------------------------------------------------------------------------// + { + StringBuilder text = new StringBuilder ("\n"); + + text.append (" \n \n"); + text.append (" \n \n"); + + text.append (" \n \n"); + text.append (" \n \n"); + + text.append (" \n \n"); + text.append (" \n \n"); + + text.append (" \n \n"); + text.append (" \n \n"); + + text.append (" \n \n"); + text.append (" \n \n"); + + text.append (" \n \n"); + text.append (" \n \n"); + + text.append ("
Spell name" + name + "
Translation" + translation + "
Spell level" + level + "
Spell type" + getWhenCast () + "
Area of effect" + getArea () + "
Description" + getText () + "
"); + return text.toString (); + } + + // ---------------------------------------------------------------------------------// + @Override + public String toString () + // ---------------------------------------------------------------------------------// + { + StringBuilder text = new StringBuilder (name); + while (text.length () < 14) + text.append (" "); + if (spellType == SpellType.PRIEST) + text.append ("P"); + else + text.append ("M"); + text.append (level); + while (text.length () < 20) + text.append (" "); + text.append (translation); + while (text.length () < 40) + text.append (" "); + text.append (getArea ()); + while (text.length () < 60) + text.append (" "); + text.append (getWhenCast ()); + return text.toString (); + } + + private static String[] spellNames = + { "KALKI", "DIOS", "BADIOS", "MILWA", "PORFIC", "MATU", "CALFO", "MANIFO", + "MONTINO", "LOMILWA", "DIALKO", "LATUMAPIC", "BAMATU", "DIAL", "BADIAL", + "LATUMOFIS", "MAPORFIC", "DIALMA", "BADIALMA", "LITOKAN", "KANDI", "DI", "BADI", + "LORTO", "MADI", "MABADI", "LOKTOFEIT", "MALIKTO", "KADORTO", + + "HALITO", "MOGREF", "KATINO", "DUMAPIC", "DILTO", "SOPIC", "MAHALITO", "MOLITO", + "MORLIS", "DALTO", "LAHALITO", "MAMORLIS", "MAKANITO", "MADALTO", "LAKANITO", + "ZILWAN", "MASOPIC", "HAMAN", "MALOR", "MAHAMAN", "TILTOWAIT" }; + + private static String[] translations = + { "Blessings", "Heal", "Harm", "Light", "Shield", "Blessing & zeal", "X-ray vision", + "Statue", "Still air", "More light", "Softness/supple", "Identification", + "Prayer", "Heal (more)", "Hurt (more)", "Cure poison", "Shield (big)", + "Heal (greatly)", "Hurt (greatly)", "Flame tower", "Location", "Life", "Death", + "Blades", "Healing", "Harm (incredibly)", "Recall", "The Word of Death", + "Resurrection", + + "Little Fire", "Body Iron", "Bad Air", "Clarity", "Darkness", "Glass", "Big fire", + "Spark storm", "Fear", "Blizzard blast", "Flame storm", "Terror", "Deadly air", + "Frost", "Suffocation", "Dispell", "Big glass", "Change", "Apport", + "Great change", "(untranslatable)" }; + + private static SpellThrown[] when = + { SpellThrown.COMBAT, SpellThrown.ANY_TIME, SpellThrown.COMBAT, + SpellThrown.ANY_TIME, SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.LOOTING, + SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.ANY_TIME, + SpellThrown.ANY_TIME, SpellThrown.COMBAT, SpellThrown.COMBAT, + SpellThrown.ANY_TIME, SpellThrown.COMBAT, SpellThrown.ANY_TIME, + SpellThrown.ANY_TIME, SpellThrown.ANY_TIME, SpellThrown.COMBAT, + SpellThrown.COMBAT, SpellThrown.CAMP, SpellThrown.CAMP, SpellThrown.COMBAT, + SpellThrown.COMBAT, SpellThrown.ANY_TIME, SpellThrown.COMBAT, SpellThrown.COMBAT, + SpellThrown.COMBAT, SpellThrown.ANY_TIME, + + SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.CAMP, + SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.COMBAT, + SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.COMBAT, + SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.COMBAT, + SpellThrown.COMBAT, SpellThrown.COMBAT, SpellThrown.COMBAT_OR_CAMP, + SpellThrown.COMBAT, SpellThrown.COMBAT, }; + + private static SpellTarget[] affects = + { SpellTarget.PARTY, SpellTarget.PERSON, SpellTarget.MONSTER, SpellTarget.PARTY, + SpellTarget.CASTER, SpellTarget.PARTY, SpellTarget.CASTER, + SpellTarget.MONSTER_GROUP, SpellTarget.MONSTER_GROUP, SpellTarget.PARTY, + SpellTarget.PERSON, SpellTarget.PARTY, SpellTarget.PARTY, SpellTarget.PERSON, + SpellTarget.MONSTER, SpellTarget.PERSON, SpellTarget.PARTY, SpellTarget.PERSON, + SpellTarget.MONSTER, SpellTarget.PARTY, SpellTarget.PERSON, SpellTarget.PERSON, + SpellTarget.MONSTER, SpellTarget.MONSTER_GROUP, SpellTarget.PERSON, + SpellTarget.MONSTER, SpellTarget.PARTY, SpellTarget.MONSTER_GROUP, + SpellTarget.PERSON, + + SpellTarget.MONSTER, SpellTarget.CASTER, SpellTarget.MONSTER_GROUP, + SpellTarget.NONE, SpellTarget.MONSTER_GROUP, SpellTarget.CASTER, + SpellTarget.MONSTER_GROUP, SpellTarget.MONSTER_GROUP, SpellTarget.MONSTER_GROUP, + SpellTarget.MONSTER_GROUP, SpellTarget.MONSTER_GROUP, SpellTarget.ALL_MONSTERS, + SpellTarget.ALL_MONSTERS, SpellTarget.MONSTER_GROUP, SpellTarget.MONSTER_GROUP, + SpellTarget.MONSTER, SpellTarget.PARTY, SpellTarget.VARIABLE, SpellTarget.PARTY, + SpellTarget.PARTY, SpellTarget.ALL_MONSTERS }; + + private static String[] descriptions = + { "KALKI reduces the AC of all party members by one, and thus makes" + + " them harder to hit.", + "DIOS restores from one to eight hit points of damage from a party" + + "member. It will not bring dead back to life.", + "BADIOS causes one to eight hit points of damage to a monster, and" + + " may kill it. It is the reverse of dios. Note the BA prefix which" + + " means 'not'.", + "MILWA causes a softly glowing light to follow the party, allowing" + + " them to see further into the maze, and also revealing all secret" + + " doors. See also LOMILWA. This spell lasts only a short while.", + "PORFIC lowers the AC of the caster considerably. The effects last" + + " for the duration of combat.", + "MATU has the same effects as KALKI, but at double the strength.", + "CALFO allows the caster to determine the exact nature of a trap" + + " on a chest 95% of the time.", + "MANIFO causes some of the monsters in a group to become stiff as" + + " statues for one or more melee rounds. The chance of success," + + " and the duration of the effects, depend on the power of the" + + " target monsters.", + "MONTINO causes the air around a group of monsters to stop" + + " transmitting sound. Like MANIFO, only some of the monsters will" + + " be affected, and for varying lengths of time. Monsters and" + + " Party members under the influence of this spell cannot cast" + + " spells, as they cannot utter the spell words!", + "LOMILWA is a MILWA spell with a much longer life span. Note that" + + " when this spell, or MILWA are active, the Q option while" + + " moving through the maze is active. If Q)UICK PLOTTING is on," + + " only the square you are in, and the next two squares, will" + + " plot. Normally you might see five or six squares ahead with" + + " LOMILWA on. Quick Plotting lets you move fast through known" + + " areas. Note that it will be turned off when you enter camp or" + + " combat mode.", + "DIALKO cures paralysis, and removes the effects of MANIFO and" + + " KATINO from one member of the party.", + "LATUMAPIC makes it readily apparent exactly what the opposing" + + " monsters really are.", + "BAMATU has the effects of MATU at twice the effectiveness.", + "DIAL restores two to 16 hit points of damage, and is similar to" + " DIOS.", + "BADIAL causes two to 16 hit points of damage in the same way as" + " BADIOS.", + "LATUMOFIS makes a poisoned person whole and fit again. Note that" + + " poison causes a person to lose hit points steadily during" + + " movement and combat.", + "MAPORFIC is an improved PORFIC, with effects that last for the" + + " entire expedition.", + "DIALMA restores three to 24 hit points.", + "BADIALMA causes three to 24 hit points of damage.", + "LITOKAN causes a pillar of flame to strike a group of monsters," + + " doing three to 24 hits of damage to each. However, as with" + + " many spells that affect entire groups, there is a chance that" + + " individual monsters will be able to avoid or minimise its" + + " effects. And some monsters will be resistant to it.", + "KANDI allows the user to locate characters in the maze. It tells on" + + " which level, and in which rough area the dead one can be found.", + "DI causes a dead person to be resurrected. However, the renewed" + + " character has but one hit point. Also, this spell is not as" + + " effective or as safe as using the Temple.", + "BADI gives the affected monster a coronary attack. It may or may" + + " not cause death to occur.", + "LORTO causes sharp blades to slice through a group, causing six to" + + " 36 points of damage.", + "MADI causes all hit points to be restored and cures any condition" + + " but death.", + "MABADI causes all but one to eight hit points to be removed from" + + " the target.", + "LOKTOFEIT causes all party members to be teleported back to the" + + " castle, minus all their equipment and most of their gold. There" + + " is also a good chance this spell will not function.", + "MALIKTO causes 12 to 72 hit points of damage to all monsters. None" + + " can escape or minimise its effects.", + "KADORTO restores the dead to life as does DI, but also restores all" + + " hit points. However, it has the same drawbacks as the DI spell." + + " KADORTO can be used to resurrect people even if they are ashes.", + + "HALITO causes a flame ball the size of a baseball to hit a monster," + + " doing from one to eight points of damage.", + "MOGREF reduces the caster's AC by two. The effect lasts the entire" + + " encounter.", + "KATINO causes most of the monsters in a group to fall asleep." + + " Katino only effects normal, animal or humanoid monsters. The" + + " chance of the spell affecting an individual monster, and the" + + " duration of the effect, is inversely proportional to the power" + + " of the monster. While asleep, monsters are easier to hit and" + + " successful strikes do double damage.", + "DUMAPIC informs you of the party's exact displacement from the" + + " stairs to the castle, vertically, and North and East, and also" + + " tells you what direction you are facing.", + + "DILTO causes one group of monsters to be enveloped in darkness," + + " which reduces their ability to defend against your attacks.", + "SOPIC causes the caster to become transparent. This means that" + + " he is harder to see, and thus his AC is reduced by four.", + + "MAHALITO causes a fiery explosion in a monster group, doing four" + + " to 24 hit points of damage. As with other similar spells," + + " monsters may be able to minimise the damage done.", + "MOLITO causes sparks to fly out and damage about half of the" + + " monsters in a group. Three to 18 hit points of damage are done" + + " with no chance of avoiding the sparks.", + "MORLIS causes one group of monsters to fear the party greatly. The" + + " effects are the same as a double strength DILTO spell.", + "DALTO is similar to MAHALITO except that cold replaces flames." + + " Also, six to 36 hit points of damage are done.", + "LAHALITO is an improved MAHALITO, doing the same damage as DALTO.", + "MAMORLIS is similar to MORLIS, except that all monster groups are" + + " affected.", + "Any monsters of less than eigth level (i.e. about 35-40 hit points)" + + " are killed by this spell outright.", + "An improved DALTO causing eight to 64 hit points of damage.", + "All monsters in the group affected by this spell die. Of course," + + " there is a chance that some of the monsters will not be affected.", + "This spell will destroy any one monster that is of the Undead" + " variety", + "This spell duplicates the effects of SOPIC for the entire party.", + "This spell is indeed terrible, and may backfire on the caster." + + " First, to even cast it, you must be of the thirteenth level or" + + " higher, and casting it will cost you one level of experience." + + " The effects of HAMAN are random, and usually help the party.", + "This spell's effects depend on the situation the party is in when it" + + " is cast.Basically, MALOR will teleport the entire party from one" + + " location to another. When used in melee, the teleport is random," + + " but when used in camp, where there is more chance for concentration" + + ", it can be used to move the party anywhere in the maze. Be warned," + + " however, that if you teleport outside of the maze, or into an" + + " area that is solid rock, you will be lost forever, so this spell" + + " is to be used with the greatest of care. Combat use of MALOR will" + + " never put you outside of the maze, but it may move you deeper in," + + " so it should be used only in panic situations.", + "The same restrictions and qualifications apply to this spell as do" + + " to HAMAN. However, the effects are even greater. Generally these" + + " spells are only used when there is no other hope for survival.", + "The effect of this spell can be described as similar to that of a" + + " nuclear fusion explosion. Luckily the party is shielded from its" + + " effects. Unluckily (for them) the monsters are not. This spell" + + " will do from 10-100 hit points of damage." }; } \ No newline at end of file diff --git a/src/com/bytezone/diskbrowser/wizardry/Wiz4Image.java b/src/com/bytezone/diskbrowser/wizardry/Wiz4Image.java index 0d27116..d7436b0 100644 --- a/src/com/bytezone/diskbrowser/wizardry/Wiz4Image.java +++ b/src/com/bytezone/diskbrowser/wizardry/Wiz4Image.java @@ -3,9 +3,13 @@ package com.bytezone.diskbrowser.wizardry; import java.awt.image.BufferedImage; import java.awt.image.DataBuffer; +// -----------------------------------------------------------------------------------// public class Wiz4Image extends AbstractImage +// -----------------------------------------------------------------------------------// { + // ---------------------------------------------------------------------------------// public Wiz4Image (String name, byte[] buffer, int rows, int cols) // 5, 6 + // ---------------------------------------------------------------------------------// { super (name, buffer); diff --git a/src/com/bytezone/diskbrowser/wizardry/Wiz4Monsters.java b/src/com/bytezone/diskbrowser/wizardry/Wiz4Monsters.java index 98a4068..4545db8 100644 --- a/src/com/bytezone/diskbrowser/wizardry/Wiz4Monsters.java +++ b/src/com/bytezone/diskbrowser/wizardry/Wiz4Monsters.java @@ -6,12 +6,16 @@ import java.util.List; import com.bytezone.diskbrowser.applefile.AbstractFile; import com.bytezone.diskbrowser.utilities.HexFormatter; +// -----------------------------------------------------------------------------------// public class Wiz4Monsters extends AbstractFile +// -----------------------------------------------------------------------------------// { final List images = new ArrayList<> (); final List blocks = new ArrayList<> (); + // ---------------------------------------------------------------------------------// public Wiz4Monsters (String name, byte[] buffer) + // ---------------------------------------------------------------------------------// { super (name, buffer); @@ -30,8 +34,10 @@ public class Wiz4Monsters extends AbstractFile } } + // ---------------------------------------------------------------------------------// @Override public String getText () + // ---------------------------------------------------------------------------------// { StringBuilder text = new StringBuilder (); diff --git a/src/com/bytezone/diskbrowser/wizardry/Wiz5Monsters.java b/src/com/bytezone/diskbrowser/wizardry/Wiz5Monsters.java index c99573a..b42ad57 100644 --- a/src/com/bytezone/diskbrowser/wizardry/Wiz5Monsters.java +++ b/src/com/bytezone/diskbrowser/wizardry/Wiz5Monsters.java @@ -8,12 +8,16 @@ import com.bytezone.common.Utility; import com.bytezone.diskbrowser.applefile.AbstractFile; import com.bytezone.diskbrowser.utilities.HexFormatter; -public class Wiz5Monsters extends AbstractFile implements Iterable +// -----------------------------------------------------------------------------------// +class Wiz5Monsters extends AbstractFile implements Iterable +// -----------------------------------------------------------------------------------// { private static final int BLOCK_SIZE = 512; private final List monsters = new ArrayList<> (); - public Wiz5Monsters (String name, byte[] buffer) + // ---------------------------------------------------------------------------------// + Wiz5Monsters (String name, byte[] buffer) + // ---------------------------------------------------------------------------------// { super (name, buffer); @@ -56,14 +60,18 @@ public class Wiz5Monsters extends AbstractFile implements Iterable iterator () + // ---------------------------------------------------------------------------------// { return monsters.iterator (); } + // ---------------------------------------------------------------------------------// @Override public String getText () + // ---------------------------------------------------------------------------------// { StringBuilder text = new StringBuilder (); @@ -90,7 +98,9 @@ public class Wiz5Monsters extends AbstractFile implements Iterable dataBuffers = new ArrayList<> (); @@ -151,7 +161,9 @@ public class Wiz5Monsters extends AbstractFile implements Iterable disks = new ArrayList<> (); @@ -26,7 +28,9 @@ public class Wizardry4BootDisk extends PascalDisk private Huffman huffman; private final int version; + // ---------------------------------------------------------------------------------// public Wizardry4BootDisk (AppleDisk[] dataDisks) + // ---------------------------------------------------------------------------------// { super (dataDisks[0]); @@ -133,8 +137,10 @@ public class Wizardry4BootDisk extends PascalDisk } } + // ---------------------------------------------------------------------------------// private void linkMonsterImages4 (DefaultMutableTreeNode monstersNode, FileEntry fileEntry) + // ---------------------------------------------------------------------------------// { List pictureBlocks = fileEntry.getSectors (); @@ -151,8 +157,10 @@ public class Wizardry4BootDisk extends PascalDisk } } + // ---------------------------------------------------------------------------------// private void linkMonsterImages5 (DefaultMutableTreeNode monstersNode, FileEntry fileEntry) + // ---------------------------------------------------------------------------------// { List pictureBlocks = fileEntry.getSectors (); @@ -169,7 +177,9 @@ public class Wizardry4BootDisk extends PascalDisk } } + // ---------------------------------------------------------------------------------// private void linkMazeLevels4 (DefaultMutableTreeNode scenarioNode, FileEntry fileEntry) + // ---------------------------------------------------------------------------------// { ScenarioData mazeData = scenarioHeader.data.get (Header.MAZE_AREA); @@ -191,7 +201,9 @@ public class Wizardry4BootDisk extends PascalDisk } } + // ---------------------------------------------------------------------------------// private void linkMazeLevels5 (DefaultMutableTreeNode scenarioNode, FileEntry fileEntry) + // ---------------------------------------------------------------------------------// { byte[] buffer = fileEntry.getDataSource ().buffer; List blocks = fileEntry.getSectors (); @@ -221,7 +233,9 @@ public class Wizardry4BootDisk extends PascalDisk afs.setSectors (allMazeBlocks); } + // ---------------------------------------------------------------------------------// private void linkBlock1 (DefaultMutableTreeNode scenarioNode, FileEntry fileEntry) + // ---------------------------------------------------------------------------------// { byte[] buffer = fileEntry.getDataSource ().buffer; List blocks = fileEntry.getSectors (); @@ -248,7 +262,9 @@ public class Wizardry4BootDisk extends PascalDisk afs.setSectors (allBlocks); } + // ---------------------------------------------------------------------------------// private void linkBlock2 (DefaultMutableTreeNode scenarioNode, FileEntry fileEntry) + // ---------------------------------------------------------------------------------// { byte[] buffer = fileEntry.getDataSource ().buffer; List blocks = fileEntry.getSectors (); @@ -275,7 +291,9 @@ public class Wizardry4BootDisk extends PascalDisk afs.setSectors (allBlocks); } + // ---------------------------------------------------------------------------------// private void linkOracle (DefaultMutableTreeNode scenarioNode, FileEntry fileEntry) + // ---------------------------------------------------------------------------------// { byte[] buffer = fileEntry.getDataSource ().buffer; List blocks = fileEntry.getSectors (); @@ -309,8 +327,10 @@ public class Wizardry4BootDisk extends PascalDisk afs.setSectors (allOracleBlocks); } + // ---------------------------------------------------------------------------------// private void addToNode (AbstractFile af, DefaultMutableTreeNode node, List blocks) + // ---------------------------------------------------------------------------------// { DefaultAppleFileSource dafs = new DefaultAppleFileSource (af.getName (), af, this, blocks); @@ -319,8 +339,10 @@ public class Wizardry4BootDisk extends PascalDisk node.add (childNode); } + // ---------------------------------------------------------------------------------// private DefaultMutableTreeNode linkNode (String name, String text, DefaultMutableTreeNode parent) + // ---------------------------------------------------------------------------------// { DefaultAppleFileSource afs = new DefaultAppleFileSource (name, text, this); DefaultMutableTreeNode node = new DefaultMutableTreeNode (afs); @@ -328,7 +350,9 @@ public class Wizardry4BootDisk extends PascalDisk return node; } + // ---------------------------------------------------------------------------------// public static boolean isWizardryIVorV (Disk disk, boolean debug) + // ---------------------------------------------------------------------------------// { // Wizardry IV or V boot code byte[] header = { 0x00, (byte) 0xEA, (byte) 0xA9, 0x60, (byte) 0x8D, 0x01, 0x08 }; diff --git a/src/com/bytezone/diskbrowser/wizardry/WizardryScenarioDisk.java b/src/com/bytezone/diskbrowser/wizardry/WizardryScenarioDisk.java index ed6672b..75f60b2 100755 --- a/src/com/bytezone/diskbrowser/wizardry/WizardryScenarioDisk.java +++ b/src/com/bytezone/diskbrowser/wizardry/WizardryScenarioDisk.java @@ -1,602 +1,650 @@ -package com.bytezone.diskbrowser.wizardry; - -import java.awt.Color; -import java.util.ArrayList; -import java.util.List; - -import javax.swing.tree.DefaultMutableTreeNode; -import javax.swing.tree.DefaultTreeModel; - -import com.bytezone.diskbrowser.applefile.AbstractFile; -import com.bytezone.diskbrowser.applefile.AppleFileSource; -import com.bytezone.diskbrowser.disk.DefaultAppleFileSource; -import com.bytezone.diskbrowser.disk.DefaultDataSource; -import com.bytezone.diskbrowser.disk.Disk; -import com.bytezone.diskbrowser.disk.DiskAddress; -import com.bytezone.diskbrowser.disk.SectorType; -import com.bytezone.diskbrowser.gui.DataSource; -import com.bytezone.diskbrowser.pascal.PascalDisk; -import com.bytezone.diskbrowser.utilities.HexFormatter; -import com.bytezone.diskbrowser.wizardry.Character.Attributes; -import com.bytezone.diskbrowser.wizardry.Character.Statistics; -import com.bytezone.diskbrowser.wizardry.Header.ScenarioData; -import com.bytezone.diskbrowser.wizardry.Spell.SpellType; - -public class WizardryScenarioDisk extends PascalDisk -{ - public Header scenarioHeader; - - public List images; - public List items; - public List characters; - public List spells; - public List messages; - public List monsters; - public List levels; - List experiences; - List rewards; - - // 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); - SectorType itemSector = new SectorType ("Items", Color.blue); - SectorType characterSector = new SectorType ("Characters", Color.magenta); - SectorType spellSector = new SectorType ("Spells", Color.orange); - SectorType messageSector = new SectorType ("Messages", Color.cyan); - SectorType imageSector = new SectorType ("Images", Color.red); - SectorType experienceSector = new SectorType ("Experience", Color.darkGray); - SectorType treasureSector = new SectorType ("Treasure", Color.pink); - - public WizardryScenarioDisk (Disk disk) - { - super (disk); - - if (false) - { - sectorTypesList.add (mazeSector); - sectorTypesList.add (monsterSector); - sectorTypesList.add (itemSector); - sectorTypesList.add (characterSector); - sectorTypesList.add (spellSector); - sectorTypesList.add (messageSector); - sectorTypesList.add (imageSector); - sectorTypesList.add (experienceSector); - sectorTypesList.add (treasureSector); - } - - 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); - - scenarioHeader = new Header (dataNode, this); - - // 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 (); - List sectors = afs.getSectors (); - - extractItems (linkNode ("Items", "Items string", dataNode), sectors); - extractRewards (linkNode ("Rewards", "Treasure string", dataNode), sectors); - extractMonsters (linkNode ("Monsters", "Monsters string", dataNode), sectors); - 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); - 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 (Character c : characters) - { - c.linkItems (items); - c.linkSpells (spells); - int type = c.getStatistics ().typeInt; - c.linkExperience (experiences.get (type)); - } - } - - 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 isWizardryFormat (Disk disk, boolean debug) - { - byte[] buffer = disk.readSector (2); - int totalFiles = HexFormatter.intValue (buffer[16], buffer[17]); - if (totalFiles != 3) - return false; - - for (int i = 1, ptr = 32; i <= totalFiles; i++, ptr += 26) - { - String text = HexFormatter.getPascalString (buffer, ptr); - if (!text.equals ("SCENARIO.DATA") && !text.equals ("SCENARIO.MESGS") - && !text.equals ("WIZARDRY.CODE")) - return false; - } - return true; - } - - @Override - public AppleFileSource getFile (String fileName) - { - // System.out.println ("Wizardry disk looking for : " + fileName); - return null; - } - - public String getCatalogText () - { - return null; - } - - @Override - public List getFileSectors (int fileNo) - { - return null; - } - - @Override - public DataSource getFile (int fileNo) - { - return null; - } - - private void extractRewards (DefaultMutableTreeNode node, List sectors) - { - List nodeSectors = new ArrayList<> (); - ScenarioData sd = scenarioHeader.data.get (Header.TREASURE_TABLE_AREA); - rewards = new ArrayList<> (sd.total); - int max = sd.totalBlocks / 2; - - int seq = 0; - for (int i = 0; i < max; i++) - { - List blocks = getTwoBlocks (sd, i, sectors); - nodeSectors.addAll (blocks); - byte[] buffer = disk.readSectors (blocks); - seq = addReward (buffer, blocks, node, seq); - } - - StringBuilder text = new StringBuilder (); - for (Reward t : rewards) - text.append (t.getDump () + "\n"); - - DefaultAppleFileSource afs = (DefaultAppleFileSource) node.getUserObject (); - afs.setSectors (nodeSectors); - DefaultDataSource dds = (DefaultDataSource) afs.getDataSource (); - dds.text = text.toString (); - } - - private int addReward (byte[] buffer, List blocks, - DefaultMutableTreeNode node, int seq) - { - int recLen = 168; - for (int ptr = 0; ptr < 1008; ptr += recLen) - { - byte[] data2 = new byte[recLen]; - System.arraycopy (buffer, ptr, data2, 0, recLen); - - Reward tt = new Reward ("Type " + seq, data2, seq++, items); - rewards.add (tt); - addToNode (tt, node, blocks, treasureSector); - } - return seq; - } - - private void extractCharacters (DefaultMutableTreeNode node, List sectors) - { - List nodeSectors = new ArrayList<> (); - ScenarioData sd = scenarioHeader.data.get (Header.CHARACTER_AREA); - characters = new ArrayList<> (sd.total); - int max = sd.totalBlocks / 2; - if (max < sd.total) - System.out.println ("Characters short in Wizardry disk"); - - for (int i = 0; i < max; i++) - { - List blocks = getTwoBlocks (sd, i, sectors); - nodeSectors.addAll (blocks); - byte[] buffer = disk.readSectors (blocks); - addCharacters (buffer, blocks, node); - } - - StringBuilder text = new StringBuilder (); - text.append ("Name Age Align Race Type " - + "HP St In Pi Vi Ag Lu Status\n"); - text.append ("------------- ---- -------- -------- ---------- " - + "-- -- -- -- -- -- -- ------\n"); - for (Character 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 *" : "")); - } - - DefaultAppleFileSource afs = (DefaultAppleFileSource) node.getUserObject (); - afs.setSectors (nodeSectors); - DefaultDataSource dds = (DefaultDataSource) afs.getDataSource (); - dds.text = text.toString (); - } - - private void addCharacters (byte[] buffer, List blocks, - DefaultMutableTreeNode node) - { - int recLen = 208; - for (int ptr = 0; ptr < 832; ptr += recLen) - { - int nameLength = buffer[ptr] & 0xFF; - if (nameLength == 0xC3 || buffer[ptr + 40] == 0x07) - continue; - String name = HexFormatter.getString (buffer, ptr + 1, nameLength); - - byte[] data2 = new byte[recLen]; - System.arraycopy (buffer, ptr, data2, 0, recLen); - - Character c = new Character (name, data2, scenarioHeader.scenarioID); - characters.add (c); - addToNode (c, node, blocks, characterSector); - } - } - - private void extractMonsters (DefaultMutableTreeNode node, List sectors) - { - List nodeSectors = new ArrayList<> (); - ScenarioData sd = scenarioHeader.data.get (Header.MONSTER_AREA); - monsters = new ArrayList<> (sd.total); - int max = sd.totalBlocks / 2; - - for (int i = 0; i < max; i++) - { - List blocks = getTwoBlocks (sd, i, sectors); - nodeSectors.addAll (blocks); - byte[] buffer = disk.readSectors (blocks); - addMonsters (buffer, blocks, node); - } - - StringBuilder text = new StringBuilder (); - for (int block = 0; block < 4; block++) - { - text.append (" ID Name\n"); - text.append ("--- ---------------"); - for (int i = 0; i < 24; i++) - text.append (" --"); - text.append ("\n"); - for (Monster m : monsters) - text.append (m.getDump (block) + "\n"); - text.append ("\n"); - } - DefaultAppleFileSource afs = (DefaultAppleFileSource) node.getUserObject (); - afs.setSectors (nodeSectors); - DefaultDataSource dds = (DefaultDataSource) afs.getDataSource (); - dds.text = text.toString (); - } - - private void addMonsters (byte[] buffer, List blocks, - DefaultMutableTreeNode node) - { - int recLen = 158; - for (int ptr = 0; ptr < 948; ptr += recLen) - { - int nameLength = buffer[ptr + 32] & 0xFF; - if (nameLength == 0 || nameLength == 255) - break; - String itemName = HexFormatter.getString (buffer, ptr + 33, nameLength); - - byte[] data2 = new byte[recLen]; - System.arraycopy (buffer, ptr, data2, 0, recLen); - - Monster m = new Monster (itemName, data2, rewards, monsters); - monsters.add (m); - addToNode (m, node, blocks, monsterSector); - } - } - - private void extractItems (DefaultMutableTreeNode node, List sectors) - { - List nodeSectors = new ArrayList<> (); - ScenarioData sd = scenarioHeader.data.get (Header.ITEM_AREA); - items = new ArrayList<> (sd.total); - int max = sd.totalBlocks / 2; - - for (int i = 0; i < max; i++) - { - List blocks = getTwoBlocks (sd, i, sectors); - nodeSectors.addAll (blocks); - byte[] buffer = disk.readSectors (blocks); - addItems (buffer, blocks, node); - } - - StringBuilder text = new StringBuilder (); - for (int block = 0; block < 3; block++) - { - text.append (" ID Name\n"); - text.append ("--- ---------------"); - for (int i = 0; i < 24; i++) - text.append (" --"); - text.append ("\n"); - for (Item item : items) - text.append (item.getDump (block) + "\n"); - text.append ("\n"); - } - DefaultAppleFileSource afs = (DefaultAppleFileSource) node.getUserObject (); - afs.setSectors (nodeSectors); - DefaultDataSource dds = (DefaultDataSource) afs.getDataSource (); - dds.text = text.toString (); - } - - private void addItems (byte[] buffer, List blocks, - DefaultMutableTreeNode node) - { - int recLen = 78; - for (int ptr = 0; ptr < 1014; ptr += recLen) - { - if (buffer[ptr] == 0) - break; - String itemName = HexFormatter.getPascalString (buffer, ptr); - - byte[] data2 = new byte[recLen]; - System.arraycopy (buffer, ptr, data2, 0, recLen); - - Item i = new Item (itemName, data2); - items.add (i); - addToNode (i, node, blocks, itemSector); - } - } - - private void extractSpells (DefaultMutableTreeNode node, List sectors) - { - spells = new ArrayList<> (); - List blocks = new ArrayList<> (2); - int offset = scenarioHeader.scenarioID <= 2 ? 4 : 1; - blocks.add (sectors.get (offset)); - blocks.add (sectors.get (offset + 1)); - - SpellType spellType = SpellType.MAGE; - for (DiskAddress da : blocks) - { - byte[] buffer = disk.readSector (da); - int level = 1; - int ptr = -1; - while (ptr < 255) - { - ptr++; - int start = ptr; - while (ptr < 256 && buffer[ptr] != 0x0D) - 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; - } - } - - private void extractMessages (DefaultMutableTreeNode node, List sectors) - { - Message.resetMessageId (); - messages = new ArrayList<> (); - - // Copy first 504 bytes from each sector to a single contiguous buffer - int recordLength = 42; - int max = recordLength * 12; - byte[] buffer = new byte[sectors.size () * max]; - int offset = 0; - - for (DiskAddress da : sectors) - { - byte[] tempBuffer = disk.readSector (da); - System.arraycopy (tempBuffer, 0, buffer, offset, max); - offset += max; - } - - // int id = 0; - int totalLines = 0; - - for (int ptr = 0; ptr < buffer.length; ptr += recordLength) - { - int sequence = buffer[ptr + recordLength - 2]; - ++totalLines; - if (sequence == 1) // end of message - { - int totalBytes = totalLines * recordLength; - byte[] newBuffer = new byte[totalBytes]; - int messageEnd = ptr + recordLength; - int messageStart = messageEnd - totalBytes; - System.arraycopy (buffer, messageStart, newBuffer, 0, totalBytes); - - Message m; - if (scenarioHeader.scenarioID == 1) - m = new PlainMessage (newBuffer); - else - m = new CodedMessage (newBuffer); - messages.add (m); - - List messageBlocks = new ArrayList<> (); - int lastBlock = -1; - for (int p2 = messageStart; p2 < messageEnd; p2 += recordLength) - { - int blockNo = p2 / max; - offset = p2 % max; - if (blockNo != lastBlock) - { - messageBlocks.add (sectors.get (blockNo)); - lastBlock = blockNo; - } - } - addToNode (m, node, messageBlocks, messageSector); - // id += totalLines; - totalLines = 0; - } - } - } - - private void extractLevels (DefaultMutableTreeNode node, List sectors) - { - List nodeSectors = new ArrayList<> (); - ScenarioData sd = scenarioHeader.data.get (Header.MAZE_AREA); - levels = new ArrayList<> (sd.total); - int max = sd.totalBlocks / 2; - - for (int i = 0; i < max; i++) - { - List blocks = getTwoBlocks (sd, i, sectors); - nodeSectors.addAll (blocks); - byte[] buffer = disk.readSectors (blocks); - byte[] data2 = new byte[896]; - System.arraycopy (buffer, 0, data2, 0, data2.length); - // System.out.println (HexFormatter.format (data2)); - - MazeLevel mazeLevel = new MazeLevel (data2, i + 1); - mazeLevel.setMessages (messages); - mazeLevel.setMonsters (monsters); - mazeLevel.setItems (items); - levels.add (mazeLevel); - addToNode (mazeLevel, node, blocks, mazeSector); - } - - StringBuilder text = new StringBuilder (); - for (MazeLevel level : levels) - text.append (level.getName () + "\n"); - - DefaultAppleFileSource afs = (DefaultAppleFileSource) node.getUserObject (); - afs.setSectors (nodeSectors); - DefaultDataSource dds = (DefaultDataSource) afs.getDataSource (); - dds.text = text.toString (); - } - - private void extractImages (DefaultMutableTreeNode node, List sectors) - { - List nodeSectors = new ArrayList<> (); - ScenarioData sd = scenarioHeader.data.get (Header.IMAGE_AREA); - int max = sd.totalBlocks; - images = new ArrayList<> (); - - for (int i = 0; i < max; i++) - { - DiskAddress da = sectors.get (sd.dataOffset + i); - nodeSectors.add (da); - byte[] buffer = disk.readSector (da); - byte[] exactBuffer = new byte[480]; - System.arraycopy (buffer, 0, exactBuffer, 0, exactBuffer.length); - - String name = "Unknown"; - for (Monster m : monsters) - if (m.imageID == i) - { - name = m.genericName; - break; - } - - AbstractImage mi = scenarioHeader.scenarioID < 3 ? new Image (name, buffer) - : new ImageV2 (name, exactBuffer); - images.add (mi); - addToNode (mi, node, da, imageSector); - } - - StringBuilder text = new StringBuilder (); - for (AbstractImage image : images) - text.append (image.getName () + "\n"); - - DefaultAppleFileSource afs = (DefaultAppleFileSource) node.getUserObject (); - afs.setSectors (nodeSectors); - DefaultDataSource dds = (DefaultDataSource) afs.getDataSource (); - dds.text = text.toString (); - } - - private void extractExperienceLevels (DefaultMutableTreeNode node, - List sectors) - { - List nodeSectors = new ArrayList<> (); - ScenarioData sd = scenarioHeader.data.get (Header.EXPERIENCE_AREA); - experiences = new ArrayList<> (sd.total); - int max = sd.totalBlocks / 2; - - for (int i = 0; i < max; i++) - { - List blocks = getTwoBlocks (sd, i, sectors); - nodeSectors.addAll (blocks); - byte[] buffer = disk.readSectors (blocks); - - for (int ptr = 0; ptr <= buffer.length; ptr += 78) - { - if (buffer[ptr] == 0) - break; - - byte[] newBuffer = new byte[78]; - System.arraycopy (buffer, ptr, newBuffer, 0, newBuffer.length); - ExperienceLevel el = new ExperienceLevel ("exp", newBuffer); - experiences.add (el); - addToNode (el, node, blocks, experienceSector); - } - } - - DefaultAppleFileSource afs = (DefaultAppleFileSource) node.getUserObject (); - afs.setSectors (nodeSectors); - } - - private void addToNode (AbstractFile af, DefaultMutableTreeNode node, DiskAddress block, - SectorType type) - { - List blocks = new ArrayList<> (1); - blocks.add (block); - addToNode (af, node, blocks, type); - } - - private void addToNode (AbstractFile af, DefaultMutableTreeNode node, - List blocks, SectorType type) - { - DefaultAppleFileSource dafs = - new DefaultAppleFileSource (af.getName (), af, this, blocks); - DefaultMutableTreeNode childNode = new DefaultMutableTreeNode (dafs); - node.add (childNode); - childNode.setAllowsChildren (false); - } - - private List getTwoBlocks (ScenarioData sd, int i, - List sectors) - { - List blocks = new ArrayList<> (2); - blocks.add (sectors.get (sd.dataOffset + i * 2)); - blocks.add (sectors.get (sd.dataOffset + i * 2 + 1)); - return blocks; - } +package com.bytezone.diskbrowser.wizardry; + +import java.awt.Color; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; + +import com.bytezone.diskbrowser.applefile.AbstractFile; +import com.bytezone.diskbrowser.applefile.AppleFileSource; +import com.bytezone.diskbrowser.disk.DefaultAppleFileSource; +import com.bytezone.diskbrowser.disk.DefaultDataSource; +import com.bytezone.diskbrowser.disk.Disk; +import com.bytezone.diskbrowser.disk.DiskAddress; +import com.bytezone.diskbrowser.disk.SectorType; +import com.bytezone.diskbrowser.gui.DataSource; +import com.bytezone.diskbrowser.pascal.PascalDisk; +import com.bytezone.diskbrowser.utilities.HexFormatter; +import com.bytezone.diskbrowser.wizardry.Character.Attributes; +import com.bytezone.diskbrowser.wizardry.Character.Statistics; +import com.bytezone.diskbrowser.wizardry.Header.ScenarioData; +import com.bytezone.diskbrowser.wizardry.Spell.SpellType; + +// ---------------------------------------------------------------------------------// +public class WizardryScenarioDisk extends PascalDisk +// ---------------------------------------------------------------------------------// +{ + public Header scenarioHeader; + + public List images; + public List items; + public List characters; + public List spells; + public List messages; + public List monsters; + public List levels; + List experiences; + List rewards; + + // 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); + SectorType itemSector = new SectorType ("Items", Color.blue); + SectorType characterSector = new SectorType ("Characters", Color.magenta); + SectorType spellSector = new SectorType ("Spells", Color.orange); + SectorType messageSector = new SectorType ("Messages", Color.cyan); + SectorType imageSector = new SectorType ("Images", Color.red); + SectorType experienceSector = new SectorType ("Experience", Color.darkGray); + SectorType treasureSector = new SectorType ("Treasure", Color.pink); + + // ---------------------------------------------------------------------------------// + public WizardryScenarioDisk (Disk disk) + // ---------------------------------------------------------------------------------// + { + super (disk); + + if (false) + { + sectorTypesList.add (mazeSector); + sectorTypesList.add (monsterSector); + sectorTypesList.add (itemSector); + sectorTypesList.add (characterSector); + sectorTypesList.add (spellSector); + sectorTypesList.add (messageSector); + sectorTypesList.add (imageSector); + sectorTypesList.add (experienceSector); + sectorTypesList.add (treasureSector); + } + + 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); + + scenarioHeader = new Header (dataNode, this); + + // 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 (); + List sectors = afs.getSectors (); + + extractItems (linkNode ("Items", "Items string", dataNode), sectors); + extractRewards (linkNode ("Rewards", "Treasure string", dataNode), sectors); + extractMonsters (linkNode ("Monsters", "Monsters string", dataNode), sectors); + 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); + 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 (Character c : characters) + { + c.linkItems (items); + c.linkSpells (spells); + int type = c.getStatistics ().typeInt; + c.linkExperience (experiences.get (type)); + } + } + + // ---------------------------------------------------------------------------------// + 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 isWizardryFormat (Disk disk, boolean debug) + // ---------------------------------------------------------------------------------// + { + byte[] buffer = disk.readSector (2); + int totalFiles = HexFormatter.intValue (buffer[16], buffer[17]); + if (totalFiles != 3) + return false; + + for (int i = 1, ptr = 32; i <= totalFiles; i++, ptr += 26) + { + String text = HexFormatter.getPascalString (buffer, ptr); + if (!text.equals ("SCENARIO.DATA") && !text.equals ("SCENARIO.MESGS") + && !text.equals ("WIZARDRY.CODE")) + return false; + } + return true; + } + + // ---------------------------------------------------------------------------------// + @Override + public AppleFileSource getFile (String fileName) + // ---------------------------------------------------------------------------------// + { + // System.out.println ("Wizardry disk looking for : " + fileName); + return null; + } + + // ---------------------------------------------------------------------------------// + public String getCatalogText () + // ---------------------------------------------------------------------------------// + { + return null; + } + + // ---------------------------------------------------------------------------------// + @Override + public List getFileSectors (int fileNo) + // ---------------------------------------------------------------------------------// + { + return null; + } + + // ---------------------------------------------------------------------------------// + @Override + public DataSource getFile (int fileNo) + // ---------------------------------------------------------------------------------// + { + return null; + } + + // ---------------------------------------------------------------------------------// + private void extractRewards (DefaultMutableTreeNode node, List sectors) + // ---------------------------------------------------------------------------------// + { + List nodeSectors = new ArrayList<> (); + ScenarioData sd = scenarioHeader.data.get (Header.TREASURE_TABLE_AREA); + rewards = new ArrayList<> (sd.total); + int max = sd.totalBlocks / 2; + + int seq = 0; + for (int i = 0; i < max; i++) + { + List blocks = getTwoBlocks (sd, i, sectors); + nodeSectors.addAll (blocks); + byte[] buffer = disk.readSectors (blocks); + seq = addReward (buffer, blocks, node, seq); + } + + StringBuilder text = new StringBuilder (); + for (Reward t : rewards) + text.append (t.getDump () + "\n"); + + DefaultAppleFileSource afs = (DefaultAppleFileSource) node.getUserObject (); + afs.setSectors (nodeSectors); + DefaultDataSource dds = (DefaultDataSource) afs.getDataSource (); + dds.text = text.toString (); + } + + // ---------------------------------------------------------------------------------// + private int addReward (byte[] buffer, List blocks, + DefaultMutableTreeNode node, int seq) + // ---------------------------------------------------------------------------------// + { + int recLen = 168; + for (int ptr = 0; ptr < 1008; ptr += recLen) + { + byte[] data2 = new byte[recLen]; + System.arraycopy (buffer, ptr, data2, 0, recLen); + + Reward tt = new Reward ("Type " + seq, data2, seq++, items); + rewards.add (tt); + addToNode (tt, node, blocks, treasureSector); + } + return seq; + } + + // ---------------------------------------------------------------------------------// + private void extractCharacters (DefaultMutableTreeNode node, List sectors) + // ---------------------------------------------------------------------------------// + { + List nodeSectors = new ArrayList<> (); + ScenarioData sd = scenarioHeader.data.get (Header.CHARACTER_AREA); + characters = new ArrayList<> (sd.total); + int max = sd.totalBlocks / 2; + if (max < sd.total) + System.out.println ("Characters short in Wizardry disk"); + + for (int i = 0; i < max; i++) + { + List blocks = getTwoBlocks (sd, i, sectors); + nodeSectors.addAll (blocks); + byte[] buffer = disk.readSectors (blocks); + addCharacters (buffer, blocks, node); + } + + StringBuilder text = new StringBuilder (); + text.append ("Name Age Align Race Type " + + "HP St In Pi Vi Ag Lu Status\n"); + text.append ("------------- ---- -------- -------- ---------- " + + "-- -- -- -- -- -- -- ------\n"); + for (Character 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 *" : "")); + } + + DefaultAppleFileSource afs = (DefaultAppleFileSource) node.getUserObject (); + afs.setSectors (nodeSectors); + DefaultDataSource dds = (DefaultDataSource) afs.getDataSource (); + dds.text = text.toString (); + } + + // ---------------------------------------------------------------------------------// + private void addCharacters (byte[] buffer, List blocks, + DefaultMutableTreeNode node) + // ---------------------------------------------------------------------------------// + { + int recLen = 208; + for (int ptr = 0; ptr < 832; ptr += recLen) + { + int nameLength = buffer[ptr] & 0xFF; + if (nameLength == 0xC3 || buffer[ptr + 40] == 0x07) + continue; + String name = HexFormatter.getString (buffer, ptr + 1, nameLength); + + byte[] data2 = new byte[recLen]; + System.arraycopy (buffer, ptr, data2, 0, recLen); + + Character c = new Character (name, data2, scenarioHeader.scenarioID); + characters.add (c); + addToNode (c, node, blocks, characterSector); + } + } + + // ---------------------------------------------------------------------------------// + private void extractMonsters (DefaultMutableTreeNode node, List sectors) + // ---------------------------------------------------------------------------------// + { + List nodeSectors = new ArrayList<> (); + ScenarioData sd = scenarioHeader.data.get (Header.MONSTER_AREA); + monsters = new ArrayList<> (sd.total); + int max = sd.totalBlocks / 2; + + for (int i = 0; i < max; i++) + { + List blocks = getTwoBlocks (sd, i, sectors); + nodeSectors.addAll (blocks); + byte[] buffer = disk.readSectors (blocks); + addMonsters (buffer, blocks, node); + } + + StringBuilder text = new StringBuilder (); + for (int block = 0; block < 4; block++) + { + text.append (" ID Name\n"); + text.append ("--- ---------------"); + for (int i = 0; i < 24; i++) + text.append (" --"); + text.append ("\n"); + for (Monster m : monsters) + text.append (m.getDump (block) + "\n"); + text.append ("\n"); + } + DefaultAppleFileSource afs = (DefaultAppleFileSource) node.getUserObject (); + afs.setSectors (nodeSectors); + DefaultDataSource dds = (DefaultDataSource) afs.getDataSource (); + dds.text = text.toString (); + } + + // ---------------------------------------------------------------------------------// + private void addMonsters (byte[] buffer, List blocks, + DefaultMutableTreeNode node) + // ---------------------------------------------------------------------------------// + { + int recLen = 158; + for (int ptr = 0; ptr < 948; ptr += recLen) + { + int nameLength = buffer[ptr + 32] & 0xFF; + if (nameLength == 0 || nameLength == 255) + break; + String itemName = HexFormatter.getString (buffer, ptr + 33, nameLength); + + byte[] data2 = new byte[recLen]; + System.arraycopy (buffer, ptr, data2, 0, recLen); + + Monster m = new Monster (itemName, data2, rewards, monsters); + monsters.add (m); + addToNode (m, node, blocks, monsterSector); + } + } + + // ---------------------------------------------------------------------------------// + private void extractItems (DefaultMutableTreeNode node, List sectors) + // ---------------------------------------------------------------------------------// + { + List nodeSectors = new ArrayList<> (); + ScenarioData sd = scenarioHeader.data.get (Header.ITEM_AREA); + items = new ArrayList<> (sd.total); + int max = sd.totalBlocks / 2; + + for (int i = 0; i < max; i++) + { + List blocks = getTwoBlocks (sd, i, sectors); + nodeSectors.addAll (blocks); + byte[] buffer = disk.readSectors (blocks); + addItems (buffer, blocks, node); + } + + StringBuilder text = new StringBuilder (); + for (int block = 0; block < 3; block++) + { + text.append (" ID Name\n"); + text.append ("--- ---------------"); + for (int i = 0; i < 24; i++) + text.append (" --"); + text.append ("\n"); + for (Item item : items) + text.append (item.getDump (block) + "\n"); + text.append ("\n"); + } + DefaultAppleFileSource afs = (DefaultAppleFileSource) node.getUserObject (); + afs.setSectors (nodeSectors); + DefaultDataSource dds = (DefaultDataSource) afs.getDataSource (); + dds.text = text.toString (); + } + + // ---------------------------------------------------------------------------------// + private void addItems (byte[] buffer, List blocks, + DefaultMutableTreeNode node) + // ---------------------------------------------------------------------------------// + { + int recLen = 78; + for (int ptr = 0; ptr < 1014; ptr += recLen) + { + if (buffer[ptr] == 0) + break; + String itemName = HexFormatter.getPascalString (buffer, ptr); + + byte[] data2 = new byte[recLen]; + System.arraycopy (buffer, ptr, data2, 0, recLen); + + Item i = new Item (itemName, data2); + items.add (i); + addToNode (i, node, blocks, itemSector); + } + } + + // ---------------------------------------------------------------------------------// + private void extractSpells (DefaultMutableTreeNode node, List sectors) + // ---------------------------------------------------------------------------------// + { + spells = new ArrayList<> (); + List blocks = new ArrayList<> (2); + int offset = scenarioHeader.scenarioID <= 2 ? 4 : 1; + blocks.add (sectors.get (offset)); + blocks.add (sectors.get (offset + 1)); + + SpellType spellType = SpellType.MAGE; + for (DiskAddress da : blocks) + { + byte[] buffer = disk.readSector (da); + int level = 1; + int ptr = -1; + while (ptr < 255) + { + ptr++; + int start = ptr; + while (ptr < 256 && buffer[ptr] != 0x0D) + 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; + } + } + + // ---------------------------------------------------------------------------------// + private void extractMessages (DefaultMutableTreeNode node, List sectors) + // ---------------------------------------------------------------------------------// + { + Message.resetMessageId (); + messages = new ArrayList<> (); + + // Copy first 504 bytes from each sector to a single contiguous buffer + int recordLength = 42; + int max = recordLength * 12; + byte[] buffer = new byte[sectors.size () * max]; + int offset = 0; + + for (DiskAddress da : sectors) + { + byte[] tempBuffer = disk.readSector (da); + System.arraycopy (tempBuffer, 0, buffer, offset, max); + offset += max; + } + + // int id = 0; + int totalLines = 0; + + for (int ptr = 0; ptr < buffer.length; ptr += recordLength) + { + int sequence = buffer[ptr + recordLength - 2]; + ++totalLines; + if (sequence == 1) // end of message + { + int totalBytes = totalLines * recordLength; + byte[] newBuffer = new byte[totalBytes]; + int messageEnd = ptr + recordLength; + int messageStart = messageEnd - totalBytes; + System.arraycopy (buffer, messageStart, newBuffer, 0, totalBytes); + + Message m; + if (scenarioHeader.scenarioID == 1) + m = new PlainMessage (newBuffer); + else + m = new CodedMessage (newBuffer); + messages.add (m); + + List messageBlocks = new ArrayList<> (); + int lastBlock = -1; + for (int p2 = messageStart; p2 < messageEnd; p2 += recordLength) + { + int blockNo = p2 / max; + offset = p2 % max; + if (blockNo != lastBlock) + { + messageBlocks.add (sectors.get (blockNo)); + lastBlock = blockNo; + } + } + addToNode (m, node, messageBlocks, messageSector); + // id += totalLines; + totalLines = 0; + } + } + } + + // ---------------------------------------------------------------------------------// + private void extractLevels (DefaultMutableTreeNode node, List sectors) + // ---------------------------------------------------------------------------------// + { + List nodeSectors = new ArrayList<> (); + ScenarioData sd = scenarioHeader.data.get (Header.MAZE_AREA); + levels = new ArrayList<> (sd.total); + int max = sd.totalBlocks / 2; + + for (int i = 0; i < max; i++) + { + List blocks = getTwoBlocks (sd, i, sectors); + nodeSectors.addAll (blocks); + byte[] buffer = disk.readSectors (blocks); + byte[] data2 = new byte[896]; + System.arraycopy (buffer, 0, data2, 0, data2.length); + // System.out.println (HexFormatter.format (data2)); + + MazeLevel mazeLevel = new MazeLevel (data2, i + 1); + mazeLevel.setMessages (messages); + mazeLevel.setMonsters (monsters); + mazeLevel.setItems (items); + levels.add (mazeLevel); + addToNode (mazeLevel, node, blocks, mazeSector); + } + + StringBuilder text = new StringBuilder (); + for (MazeLevel level : levels) + text.append (level.getName () + "\n"); + + DefaultAppleFileSource afs = (DefaultAppleFileSource) node.getUserObject (); + afs.setSectors (nodeSectors); + DefaultDataSource dds = (DefaultDataSource) afs.getDataSource (); + dds.text = text.toString (); + } + + // ---------------------------------------------------------------------------------// + private void extractImages (DefaultMutableTreeNode node, List sectors) + // ---------------------------------------------------------------------------------// + { + List nodeSectors = new ArrayList<> (); + ScenarioData sd = scenarioHeader.data.get (Header.IMAGE_AREA); + int max = sd.totalBlocks; + images = new ArrayList<> (); + + for (int i = 0; i < max; i++) + { + DiskAddress da = sectors.get (sd.dataOffset + i); + nodeSectors.add (da); + byte[] buffer = disk.readSector (da); + byte[] exactBuffer = new byte[480]; + System.arraycopy (buffer, 0, exactBuffer, 0, exactBuffer.length); + + String name = "Unknown"; + for (Monster m : monsters) + if (m.imageID == i) + { + name = m.genericName; + break; + } + + AbstractImage mi = scenarioHeader.scenarioID < 3 ? new Image (name, buffer) + : new ImageV2 (name, exactBuffer); + images.add (mi); + addToNode (mi, node, da, imageSector); + } + + StringBuilder text = new StringBuilder (); + for (AbstractImage image : images) + text.append (image.getName () + "\n"); + + DefaultAppleFileSource afs = (DefaultAppleFileSource) node.getUserObject (); + afs.setSectors (nodeSectors); + DefaultDataSource dds = (DefaultDataSource) afs.getDataSource (); + dds.text = text.toString (); + } + + // ---------------------------------------------------------------------------------// + private void extractExperienceLevels (DefaultMutableTreeNode node, + List sectors) + // ---------------------------------------------------------------------------------// + { + List nodeSectors = new ArrayList<> (); + ScenarioData sd = scenarioHeader.data.get (Header.EXPERIENCE_AREA); + experiences = new ArrayList<> (sd.total); + int max = sd.totalBlocks / 2; + + for (int i = 0; i < max; i++) + { + List blocks = getTwoBlocks (sd, i, sectors); + nodeSectors.addAll (blocks); + byte[] buffer = disk.readSectors (blocks); + + for (int ptr = 0; ptr <= buffer.length; ptr += 78) + { + if (buffer[ptr] == 0) + break; + + byte[] newBuffer = new byte[78]; + System.arraycopy (buffer, ptr, newBuffer, 0, newBuffer.length); + ExperienceLevel el = new ExperienceLevel ("exp", newBuffer); + experiences.add (el); + addToNode (el, node, blocks, experienceSector); + } + } + + DefaultAppleFileSource afs = (DefaultAppleFileSource) node.getUserObject (); + afs.setSectors (nodeSectors); + } + + // ---------------------------------------------------------------------------------// + private void addToNode (AbstractFile af, DefaultMutableTreeNode node, DiskAddress block, + SectorType type) + // ---------------------------------------------------------------------------------// + { + List blocks = new ArrayList<> (1); + blocks.add (block); + addToNode (af, node, blocks, type); + } + + // ---------------------------------------------------------------------------------// + private void addToNode (AbstractFile af, DefaultMutableTreeNode node, + List blocks, SectorType type) + // ---------------------------------------------------------------------------------// + { + DefaultAppleFileSource dafs = + new DefaultAppleFileSource (af.getName (), af, this, blocks); + DefaultMutableTreeNode childNode = new DefaultMutableTreeNode (dafs); + node.add (childNode); + childNode.setAllowsChildren (false); + } + + // ---------------------------------------------------------------------------------// + private List getTwoBlocks (ScenarioData sd, int i, + List sectors) + // ---------------------------------------------------------------------------------// + { + List blocks = new ArrayList<> (2); + blocks.add (sectors.get (sd.dataOffset + i * 2)); + blocks.add (sectors.get (sd.dataOffset + i * 2 + 1)); + return blocks; + } } \ No newline at end of file