✒ 🍎 の 呪

 

note.com

Apple版 の Wizardryソースコード の 抜粋。
オリジナル の WizardryPascal という言語で書かれている。

ただ、これはたぶんオリジナルのソースコードではなくて、
バイナリを逆アセンブルして Pascal に変換したか、
直で Pascal に変換するソフトを使ったものを人間が手を使って見やすくしたもの。
それを、さらに σ(^_^) が見易く(?)したもの。

で、これはキャンプ時に、ビショップがアイテムを鑑定する部分のルーチン。



BEGIN (* IDITEM *)
  CHARX := LLBASE04;
  XGOTO := XBK2CMP2;

  REPEAT
    GOTOXY ( 0, 18);
    WRITE ( CHR(11));
    WRITE ( 'IDENTIFY WHAT ITEM (0=EXIT) ? >' );
      { どのスロットにあるアイテムを鑑定する?と表示 }

    GETKEY;
      { キーボードの入力を取得 }

    ITEMX := ORD( INCHAR) - ORD( '0');

    IF ITEPIX = 0 THEN
      EXITIDIT
      { 入力が0ならキャラクター画面に戻り }
      { 他の数字であれば次にうつる }
    UNTIL ( 0 < ITEMX ) OR ( ITEMX <= CHARACTR[ CHARX].POSS.POSSCNT );

      IF CHARACTR[ CHARX].POSS.POSSESS[ ITEMX].IDENTIF THEN
        EXITIDIT;
      { 得られたスロット番号のアイテムがすでに鑑定されているなら戻る }

    CHARACTR[ CHARX].POSS.POSSESS[ ITEMX].IDENTIF :=
       (RANDOM MOD 100) < (10 + 5 * CHARACTR[ CHARX].CHARLEV);
      { 1D100 の サイコロを振り、自分のレベルx5+10より下になれば鑑定成功となり、
      鑑定済とする ( =その スロット番号 の アイテム に 鑑定済みフラグ を立てる ) }


    IF CHARACTR[ CHARX].POSS.POSSESS[ ITEMX].IDENTIF THEN
      CENTSTR( 'SUCCESS!') ELSE CENTSTR( 'FAILURE.);

    IF (RANDOM MD) 100) < (35 - (3 * CHARACTR[ CHARX].CHARLEV))
        THEN
          BEGIN
            MOVELEFT( IOCACHE[ GETREC(  
              ZOBlECT,
               CHARACTR[ CHARX].POSS.POSSESS[ ITEMX].EQINDEX,  
               SIZEOF( TOBIREC))], OBJECT, SIZEOF( TOBJREC));


            CHARACTR[ CHARX].POSS.POSSESS[ ITEMX].CURSED OBlECT.CURSED;

            XGOTO := XEQPDSP

          END;

   EXITIDIT END; (* IDITEM *)



さて、有名な Supper BIshop だが、
キー入力の部分で、所持アイテム数の最大の 8 以下を押すことを暗に求めらる。
が、数字キーには、0~9があるわけで …… 。

もし、9が入力されても、( 0 < ITEMX ) OR ……となっているので、
前項が成立して、
9も受け付けてしまうのだ!。

9が指定されると、通常通り、鑑定判定が行われ、
鑑定に成功すると、鑑定成功として、アイテムの8ビット目 最上位ビット が 立てられる。
その位置には、自分自身の経験値のメモリがあり、

すなわち、(たぶん自身の経験値の)変数の最上位ビット目に1が立てられる。
すさまじい経験値が設定されてしまうバグ(スーパービショップ)がある。

これは、

UNTIL (ITEMX > 0) OR (ITEMX <= CHARACTR[ CHARX].POSS.POSSCNT);

たぶん、「9」以外のキー、例えば「a」などを押した場合も、
どこかのビットが操作されているはずである。