2020-02-11 07:29:55 +00:00
|
|
|
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;
|
2022-03-31 02:04:23 +00:00
|
|
|
import com.bytezone.diskbrowser.utilities.Utility;
|
2020-02-11 07:29:55 +00:00
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------------//
|
2021-07-22 09:40:52 +00:00
|
|
|
class Monster extends AbstractFile
|
2020-02-11 07:29:55 +00:00
|
|
|
// -----------------------------------------------------------------------------------//
|
|
|
|
{
|
2022-03-31 02:04:23 +00:00
|
|
|
int scenarioId;
|
|
|
|
|
2020-02-11 07:29:55 +00:00
|
|
|
public final String genericName;
|
|
|
|
public final String realName;
|
|
|
|
public final int monsterID;
|
2022-03-28 03:55:49 +00:00
|
|
|
|
2020-02-11 07:29:55 +00:00
|
|
|
List<Monster> monsters;
|
|
|
|
Reward goldReward;
|
|
|
|
Reward chestReward;
|
|
|
|
|
2022-03-31 02:04:23 +00:00
|
|
|
final int type;
|
|
|
|
final int imageID;
|
2022-03-29 08:00:32 +00:00
|
|
|
|
2020-02-11 07:29:55 +00:00
|
|
|
public final int partnerID;
|
|
|
|
public final int partnerOdds;
|
|
|
|
public final int armourClass;
|
2022-03-28 03:55:49 +00:00
|
|
|
public final int recsn;
|
2020-02-11 07:29:55 +00:00
|
|
|
public final int mageSpellLevel;
|
|
|
|
public final int priestSpellLevel;
|
2022-03-29 08:00:32 +00:00
|
|
|
|
2022-03-31 02:04:23 +00:00
|
|
|
int experiencePoints;
|
2020-02-11 07:29:55 +00:00
|
|
|
int levelDrain;
|
2022-03-28 03:55:49 +00:00
|
|
|
int healPts;
|
|
|
|
int breathe;
|
|
|
|
int unaffect;
|
|
|
|
int unique;
|
2020-02-11 07:29:55 +00:00
|
|
|
int resistance;
|
|
|
|
int abilities;
|
2022-03-31 02:04:23 +00:00
|
|
|
|
2020-02-11 07:29:55 +00:00
|
|
|
public final Dice groupSize, hitPoints;
|
|
|
|
List<Dice> damage = new ArrayList<> ();
|
|
|
|
|
|
|
|
static int counter = 0;
|
|
|
|
|
2022-03-26 08:07:17 +00:00
|
|
|
public static String[] monsterClass = { "Fighter", "Mage", "Priest", "Thief", "Midget", "Giant",
|
|
|
|
"Mythical", "Dragon", "Animal", "Were", "Undead", "Demon", "Insect", "Enchanted" };
|
2021-07-22 09:40:52 +00:00
|
|
|
|
2022-03-31 02:04:23 +00:00
|
|
|
// Scenario #1 values
|
2022-03-29 08:00:32 +00:00
|
|
|
private static int[] experience = { //
|
|
|
|
55, 235, 415, 230, 380, 620, 840, 520, 550, 350, // 00-09
|
|
|
|
475, 515, 920, 600, 735, 520, 795, 780, 990, 795, // 10-19
|
|
|
|
1360, 1320, 1275, 680, 960, 600, 755, 1120, 2075, 870, // 20-29
|
|
|
|
960, 600, 1120, 2435, 1080, 2280, 975, 875, 1135, 1200, // 30-39
|
|
|
|
620, 740, 1460, 1245, 960, 1405, 1040, 1220, 1520, 1000, // 40-49
|
|
|
|
960, 2340, 2160, 2395, 790, 1140, 1235, 1790, 1720, 2240, // 50-59
|
|
|
|
1475, 1540, 1720, 1900, 1240, 1220, 1020, 20435, 5100, 3515, // 60-69
|
|
|
|
2115, 2920, 2060, 2140, 1400, 1640, 1280, 4450, 42840, 3300, // 70-79
|
|
|
|
40875, 5000, 3300, 2395, 1935, 1600, 3330, 44090, 40840, 5200, // 80-89
|
|
|
|
4155, 3000, 9200, 3160, 7460, 7320, 15880, 1600, 2200, 1000, // 90-99
|
|
|
|
1900 // 100
|
|
|
|
};
|
|
|
|
|
2020-02-11 07:29:55 +00:00
|
|
|
// ---------------------------------------------------------------------------------//
|
2022-03-31 02:04:23 +00:00
|
|
|
Monster (String name, byte[] buffer, List<Reward> rewards, List<Monster> monsters, int scenarioId)
|
2020-02-11 07:29:55 +00:00
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
{
|
|
|
|
super (name, buffer);
|
|
|
|
|
2022-03-31 02:04:23 +00:00
|
|
|
this.scenarioId = scenarioId;
|
|
|
|
|
2020-02-11 07:29:55 +00:00
|
|
|
realName = name;
|
|
|
|
genericName = HexFormatter.getPascalString (buffer, 0);
|
|
|
|
this.monsterID = counter++;
|
|
|
|
this.monsters = monsters;
|
2022-03-28 03:55:49 +00:00
|
|
|
|
2020-02-11 07:29:55 +00:00
|
|
|
imageID = buffer[64];
|
2022-03-28 03:55:49 +00:00
|
|
|
groupSize = new Dice (buffer, 66);
|
|
|
|
hitPoints = new Dice (buffer, 72);
|
2020-02-11 07:29:55 +00:00
|
|
|
type = buffer[78];
|
|
|
|
armourClass = buffer[80];
|
2022-03-28 03:55:49 +00:00
|
|
|
|
|
|
|
recsn = buffer[82]; // number of dice
|
2022-03-31 02:04:23 +00:00
|
|
|
for (int i = 0, ptr = 84; i < 7; i++, ptr += 6)
|
2022-03-28 03:55:49 +00:00
|
|
|
{
|
|
|
|
if (buffer[ptr] == 0)
|
|
|
|
break;
|
|
|
|
damage.add (new Dice (buffer, ptr));
|
|
|
|
}
|
|
|
|
|
2022-04-06 08:05:37 +00:00
|
|
|
experiencePoints = getWizLong (buffer, 126);
|
2020-02-11 07:29:55 +00:00
|
|
|
levelDrain = buffer[132];
|
2022-03-28 03:55:49 +00:00
|
|
|
healPts = buffer[134];
|
2022-03-31 02:04:23 +00:00
|
|
|
goldReward = rewards.get (buffer[136]);
|
|
|
|
chestReward = rewards.get (buffer[138]);
|
2020-02-11 07:29:55 +00:00
|
|
|
partnerID = buffer[140];
|
|
|
|
partnerOdds = buffer[142];
|
|
|
|
mageSpellLevel = buffer[144];
|
|
|
|
priestSpellLevel = buffer[146];
|
|
|
|
|
2022-03-28 03:55:49 +00:00
|
|
|
unique = buffer[148];
|
|
|
|
breathe = buffer[150];
|
|
|
|
unaffect = buffer[152];
|
|
|
|
|
|
|
|
resistance = buffer[154]; // bit flags
|
|
|
|
abilities = buffer[156]; // bit flags
|
2022-03-31 02:04:23 +00:00
|
|
|
|
|
|
|
goldReward.addMonster (this, 0);
|
|
|
|
chestReward.addMonster (this, 1);
|
2020-02-11 07:29:55 +00:00
|
|
|
}
|
|
|
|
|
2022-04-06 08:05:37 +00:00
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
private int getWizLong (byte[] buffer, int offset)
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
{
|
|
|
|
int low = Utility.getShort (buffer, offset);
|
|
|
|
int mid = Utility.getShort (buffer, offset + 2);
|
|
|
|
int high = Utility.getShort (buffer, offset + 4);
|
|
|
|
|
|
|
|
return high * 100000000 + mid * 10000 + low;
|
|
|
|
}
|
|
|
|
|
2020-02-11 07:29:55 +00:00
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
@Override
|
|
|
|
public String getText ()
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
{
|
|
|
|
StringBuilder text = new StringBuilder ();
|
|
|
|
|
2022-03-31 02:04:23 +00:00
|
|
|
int totalExperience = scenarioId == 1 ? getExperience () : experiencePoints;
|
2020-02-11 07:29:55 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2022-03-28 03:55:49 +00:00
|
|
|
text.append ("\n\nMonster class ... " + type + " " + monsterClass[type]);
|
2020-02-11 07:29:55 +00:00
|
|
|
text.append ("\nArmour class .... " + armourClass);
|
2022-03-28 03:55:49 +00:00
|
|
|
|
|
|
|
text.append ("\n\n# damage ........ " + recsn);
|
2020-02-11 07:29:55 +00:00
|
|
|
|
2022-03-28 03:55:49 +00:00
|
|
|
text.append ("\nDamage .......... " + getDamage ());
|
2020-02-11 07:29:55 +00:00
|
|
|
|
|
|
|
text.append ("\n\nLevel drain ..... " + levelDrain);
|
2022-03-28 03:55:49 +00:00
|
|
|
text.append ("\nHeal pts? ....... " + healPts);
|
2020-02-11 07:29:55 +00:00
|
|
|
|
|
|
|
text.append ("\n\nPartner ID ...... " + partnerID);
|
|
|
|
if (partnerOdds > 0)
|
2021-07-24 08:08:40 +00:00
|
|
|
text.append (" " + monsters.get (partnerID).getName ());
|
2020-02-11 07:29:55 +00:00
|
|
|
text.append ("\nPartner odds .... " + partnerOdds + "%");
|
|
|
|
|
|
|
|
text.append ("\n\nMage level ...... " + mageSpellLevel);
|
|
|
|
text.append ("\nPriest level .... " + priestSpellLevel);
|
|
|
|
|
2022-03-28 03:55:49 +00:00
|
|
|
text.append ("\n\nUnique .......... " + unique);
|
|
|
|
text.append ("\nBreathe ......... " + breathe);
|
|
|
|
text.append ("\nUnaffect ........ " + unaffect);
|
2020-02-11 07:29:55 +00:00
|
|
|
|
2022-03-29 08:00:32 +00:00
|
|
|
text.append ("\n\nResistance ...... " + String.format ("%3d %<02X", resistance));
|
|
|
|
text.append ("\nAbilities ....... " + String.format ("%3d %<02X", abilities));
|
2020-02-11 07:29:55 +00:00
|
|
|
|
2022-03-28 08:36:17 +00:00
|
|
|
text.append (String.format ("%n%nExperience ...... %-,7d", totalExperience));
|
2020-02-11 07:29:55 +00:00
|
|
|
|
2022-03-31 02:04:23 +00:00
|
|
|
text.append (String.format ("%n%n===== Gold reward %2d ======", goldReward.id));
|
2020-02-11 07:29:55 +00:00
|
|
|
// text.append ("\nTable ........... " + rewardTable1);
|
|
|
|
text.append ("\n" + goldReward.getText (false));
|
2022-03-31 02:04:23 +00:00
|
|
|
text.append (String.format ("===== Chest reward %2d =====", chestReward.id));
|
2020-02-11 07:29:55 +00:00
|
|
|
// 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 ();
|
|
|
|
}
|
|
|
|
|
2022-03-28 03:55:49 +00:00
|
|
|
// ---------------------------------------------------------------------------------//
|
2022-03-28 08:36:17 +00:00
|
|
|
private int getExperience ()
|
2022-03-28 03:55:49 +00:00
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
{
|
2022-03-28 08:36:17 +00:00
|
|
|
int expHitPoints = hitPoints.qty * hitPoints.sides * (breathe == 0 ? 20 : 40);
|
2022-03-29 08:00:32 +00:00
|
|
|
int expAc = 40 * (11 - armourClass);
|
2022-03-28 03:55:49 +00:00
|
|
|
|
2022-03-28 08:36:17 +00:00
|
|
|
int expMage = getBonus (35, mageSpellLevel);
|
|
|
|
int expPriest = getBonus (35, priestSpellLevel);
|
|
|
|
int expDrain = getBonus (200, levelDrain);
|
|
|
|
int expHeal = getBonus (90, healPts);
|
2022-03-28 03:55:49 +00:00
|
|
|
|
2022-03-28 08:36:17 +00:00
|
|
|
int expDamage = recsn <= 1 ? 0 : getBonus (30, recsn);
|
|
|
|
int expUnaffect = unaffect == 0 ? 0 : getBonus (40, (unaffect / 10 + 1));
|
2022-03-28 07:02:01 +00:00
|
|
|
|
2022-03-31 02:04:23 +00:00
|
|
|
int expFlags1 = getBonus (35, Integer.bitCount (resistance & 0x7E)); // 6 bits
|
|
|
|
int expFlags2 = getBonus (40, Integer.bitCount (abilities & 0x7F)); // 7 bits
|
2022-03-28 03:55:49 +00:00
|
|
|
|
2022-03-29 08:00:32 +00:00
|
|
|
return expHitPoints + expAc + expMage + expPriest + expDrain + expHeal + expDamage + expUnaffect
|
2022-03-28 03:55:49 +00:00
|
|
|
+ expFlags1 + expFlags2;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------------//
|
2022-03-28 07:02:01 +00:00
|
|
|
private int getBonus (int base, int multiplier)
|
2020-02-11 07:29:55 +00:00
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
{
|
2022-03-28 07:02:01 +00:00
|
|
|
if (multiplier == 0)
|
|
|
|
return 0;
|
2022-03-28 03:55:49 +00:00
|
|
|
|
2022-03-28 07:02:01 +00:00
|
|
|
int total = base;
|
2022-03-29 08:00:32 +00:00
|
|
|
while (multiplier > 1)
|
|
|
|
{
|
2022-03-31 02:04:23 +00:00
|
|
|
int part = total % 10000; // get the last 4 digits
|
|
|
|
|
2022-03-29 08:00:32 +00:00
|
|
|
multiplier--;
|
2022-03-31 02:04:23 +00:00
|
|
|
total += total; // double the value
|
|
|
|
|
|
|
|
if (part >= 5000) // mimics the wizardry bug
|
|
|
|
total += 10000; // yay, free points
|
2022-03-29 08:00:32 +00:00
|
|
|
}
|
2022-03-28 03:55:49 +00:00
|
|
|
|
2022-03-31 02:04:23 +00:00
|
|
|
return total;
|
2020-02-11 07:29:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
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 ();
|
2022-03-28 03:55:49 +00:00
|
|
|
|
2020-02-11 07:29:55 +00:00
|
|
|
for (Dice d : damage)
|
|
|
|
text.append (d + ", ");
|
2022-03-28 03:55:49 +00:00
|
|
|
|
2022-03-31 02:04:23 +00:00
|
|
|
if (text.length () > 0)
|
|
|
|
{
|
|
|
|
text.deleteCharAt (text.length () - 1);
|
|
|
|
text.deleteCharAt (text.length () - 1);
|
|
|
|
}
|
2022-03-28 03:55:49 +00:00
|
|
|
|
2020-02-11 07:29:55 +00:00
|
|
|
return text.toString ();
|
|
|
|
}
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
public String getDump (int block)
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
{
|
2022-03-26 08:07:17 +00:00
|
|
|
StringBuilder line = new StringBuilder (String.format ("%3d %-16s", monsterID, realName));
|
2022-03-29 08:00:32 +00:00
|
|
|
|
2020-02-11 07:29:55 +00:00
|
|
|
int lo = block == 0 ? 64 : block == 1 ? 88 : block == 2 ? 112 : 136;
|
|
|
|
int hi = lo + 24;
|
|
|
|
if (hi > buffer.length)
|
|
|
|
hi = buffer.length;
|
2022-03-29 08:00:32 +00:00
|
|
|
|
2020-02-11 07:29:55 +00:00
|
|
|
for (int i = lo; i < hi; i++)
|
|
|
|
line.append (String.format ("%02X ", buffer[i]));
|
2022-03-29 08:00:32 +00:00
|
|
|
|
2022-04-06 08:05:37 +00:00
|
|
|
if (block == 3)
|
|
|
|
if (scenarioId == 1)
|
|
|
|
{
|
|
|
|
int exp = getExperience ();
|
|
|
|
line.append (String.format (" %,6d %,6d", exp, exp - experience[monsterID]));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
line.append (String.format (" %,6d", experiencePoints));
|
2022-03-29 08:00:32 +00:00
|
|
|
|
2020-02-11 07:29:55 +00:00
|
|
|
return line.toString ();
|
|
|
|
}
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
public boolean match (int monsterID)
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
{
|
|
|
|
return this.monsterID == monsterID;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
@Override
|
|
|
|
public String toString ()
|
|
|
|
// ---------------------------------------------------------------------------------//
|
|
|
|
{
|
|
|
|
return realName;
|
|
|
|
}
|
2015-06-01 09:35:51 +00:00
|
|
|
}
|