Wizardry #1-2-3

Character Awards - ">*KDG"

Wizardry 1-2-3 Character Awards

By: Snafaru

Email: snafaru@zimlab.com

Web site: http://www.zimlab.com/wizardry

Created: 2022/03/04.
Updated: 2022/03/18.

Upon completing quests in Wizardry 1, 2, and 3, your characters can accumulate awards, honors, and titles.

When you look up your characters' details in Gilgamesh’s Tavern, Training Grounds, or at a Camp, you can see these awards on the right of your characters' names.

The awards your characters earn transfer from scenario to scenario, they do not lose them in the progression of their heroic exploits.

If one of your characters accumulates all of the awards, they will have ">*KDG" next to their name.

Here is a breakdown of the awards:

">" - Trebor's Honour Guard. The chevron is granted by this overlord for returning his Amulet which you have taken back from defeating the evil Wizard Werdna in Wizardry's first scenario, Proving Grounds of the Mad Overlord.

"K" - Keeper of the Holy Staff of Gnilda. This rank and title are given by Queen Margda, and are bestowed upon the character whom has returned the Staff of Gnilda in Wizardry's second scenario, The Knight of Diamonds.

"G" - Knight of the City of llylgamyn. The Keeper of the Holy Staff of Gnilda chooses the characters that have helped returning the Staff of Gnilda by making them Knights in recognition of their aid doing so in Wizardry's second scenario, The Knight of Diamonds.

"D" - Descendant of the Heroes and Heroines of the Knight of Diamonds. Wizardry's third scenario, Legacy of Llylgamyn, requires that the characters embarking in its quests must be descendants of the characters from Knight of Diamonds by first performing a Rite of Passage which grants them this title and also permits them to wear the awards of their forebearers as a honor and reminder of their deeds.

"*" - The Star of Llylgamyn. By surrendering the Orb of Earithin to the Sages of Llylgamyn, Queen Beyki, great granddaughter of Queen Margda, gives your characters this august award in appreciation for your valor in Wizardry's third scenario, Legacy of Llylgamyn.

Look after the print screen below to see how this translates in the character's record bytes and game code.

Here is a print screen showing all the awards


Although convoluted, here is how my brain process worked it out from the character's record bytes and game code

When you look into the reversed engineered code, you can see how it was done.

What I found is that the string that is parsed, as shown in Wiz1WizardryPascal.txt, to write the awards after a character’s names is (I added spaces for clarity):
>!$# &*<? BCPK ODG@

Here is the corresponding binary when all awards are used:
1000 0100 0001 0110

Reverse it:
0001 0010 1000 0110

Convert to hex:
1 2 8 6

Then reverse the bytes, this give you:
21 68

So, 21 68 is in the character’s record data when they get all the awards. In this case: >*KDG

All the possible combinations are then:

First byte: 00 01 20 21
Second byte: 00 02 04 06 08 28 48 68

Then, thanks to Denis Molony's DiskBrowser, I saw that this corresponded to the following bytes in the characters' records:

206 (HEX CE)
207 (HEX CF)

Denis Molony's "DiskBrowser" program is available from his GitHub at https://github.com/dmolony

Here is Denis' Java code to show the awards in DiskBrowser, it is done in the true spirit of the original programming
  private static char[] awardsText = ">!$#&*<?BCPKODG@".toCharArray ();

  // ---------------------------------------------------------------------------------//
  public String getAwardString ()
  // ---------------------------------------------------------------------------------//
    StringBuilder text = new StringBuilder ();

    int awards = Utility.getShort (buffer, 206);    // convert two bytes to 16 bit integer

    for (int i = 0; i < 16; i++)
      if ((awards & 0x01) != 0)
        text.append (awardsText[i]);
      awards >>>= 1;

    return text.toString ();

  // ---------------------------------------------------------------------------------//
  public static int getShort (byte[] buffer, int ptr)
  // ---------------------------------------------------------------------------------//
      return (buffer[ptr] & 0xFF) | ((buffer[ptr + 1] & 0xFF) << 8);
    catch (ArrayIndexOutOfBoundsException e)
      System.out.printf ("Index out of range (getShort): %04X  %<d%n", ptr);
      return 0;

Here is a sample alternate coding that I came up with using my limited programming skills
(If you replace "v1" and "v2" by numbers you will see it works)

String awards = "";

int v1 = buffer[206];
int v2 = buffer[207];

if (v1 == 0x01) awards=awards+">";
     else if (v1 == 0x20) awards=awards+"*";
     else if (v1 == 0x21) awards=awards+">*";
     else awards=awards+"";

if (v2 == 0x02) awards=awards+"D";
     else if (v2 == 0x04) awards=awards+"G";
     else if (v2 == 0x06) awards=awards+"DG";
     else if (v2 == 0x08) awards=awards+"K";
     else if (v2 == 0x28) awards=awards+"KD";
     else if (v2 == 0x48) awards=awards+"KG";
     else if (v2 == 0x68) awards=awards+"KDG";
     else awards=awards+"";

return awards;

If you take a look at the reversed engineered Pascal code, it looks like this
  9378  18   31:D     1       PROCEDURE CHEVRONS;  (* P010C1F *)
  9379  18   31:D     1       
  9380  18   31:D     1         VAR
  9381  18   31:D     1              INDX     : INTEGER;
  9382  18   31:D     2              LOSTXYL4 : PACKED ARRAY[ 0..15] OF BOOLEAN;
  9383  18   31:D     3       
  9384  18   31:0     0         BEGIN
  9385  18   31:1     0           MOVELEFT( CHARACTR[ CAMPCHAR].LOSTXYL.AWARDS[ 4], LOSTXYL4, 2);
  9386  18   31:1    21           PRINTSTR( CAMPWIN, ' "');
  9387  18   31:1    32           FOR INDX := 0 TO 15 DO
  9388  18   31:2    43             IF LOSTXYL4[ INDX] THEN
  9389  18   31:3    52               PRINTSTR( CAMPWIN, COPY( '>!$#&*<?BCPKODG@', INDX + 1, 1));
  9390  18   31:1    95           PRINTSTR( CAMPWIN, '" ')
  9391  18   31:0   103         END;  (* CHEVRONS *)