Logo Search packages:      
Sourcecode: scummvm version File versions  Download package

debug.cpp

/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/tags/release-0-11-1/engines/agos/debug.cpp $
 * $Id: debug.cpp 30944 2008-02-23 22:50:18Z sev $
 *
 */

// AGOS debug functions


#include "agos/debug.h"
#include "agos/agos.h"
#include "agos/intern.h"
#include "agos/vga.h"

namespace AGOS {

const byte *AGOSEngine::dumpOpcode(const byte *p) {
      uint opcode;
      const char *s, *st;

      if (getGameType() == GType_ELVIRA1) {
            opcode = READ_BE_UINT16(p);
            p += 2;
            if (opcode == 10000)
                  return NULL;
      } else {
            opcode = *p++;
            if (opcode == 255)
                  return NULL;
      }

      if (getGameType() == GType_PP) {
            st = s = puzzlepack_opcodeNameTable[opcode];
      } else if (getGameType() == GType_FF) {
            st = s = feeblefiles_opcodeNameTable[opcode];
      } else if (getGameType() == GType_SIMON2 && getFeatures() & GF_TALKIE) {
            st = s = simon2talkie_opcodeNameTable[opcode];
      } else if (getFeatures() & GF_TALKIE) {
            st = s = simon1talkie_opcodeNameTable[opcode];
      } else if (getGameType() == GType_SIMON2) {
            st = s = simon2dos_opcodeNameTable[opcode];
      } else if (getGameType() == GType_SIMON1) {
            st = s = simon1dos_opcodeNameTable[opcode];
      } else if (getGameType() == GType_WW) {
            st = s = waxworks_opcodeNameTable[opcode];
      } else if (getGameType() == GType_ELVIRA2) {
            st = s = elvira2_opcodeNameTable[opcode];
      } else {
            st = s = elvira1_opcodeNameTable[opcode];
      }

      if (s == NULL) {
            error("dumpOpcode: INVALID OPCODE %d", opcode);
      }

      while (*st != '|')
            st++;
      printf("%s ", st + 1);

      for (;;) {
            switch (*s++) {
            case 'x':
                  printf("\n");
                  return NULL;
            case '|':
                  printf("\n");
                  return p;
            case 'B':{
                        byte b = *p++;
                        if (b == 255)
                              printf("[%d] ", *p++);
                        else
                              printf("%d ", b);
                        break;
                  }
            case 'V':{
                        byte b = *p++;
                        if (b == 255)
                              printf("[[%d]] ", *p++);
                        else
                              printf("[%d] ", b);
                        break;
                  }

            case 'W':{
                        int n = (int16)READ_BE_UINT16(p);
                        p += 2;
                        if (getGameType() == GType_PP) {
                              if (n >= 60000 && n < 62048)
                                    printf("[%d] ", n - 60000);
                              else
                                    printf("%d ", n);

                        } else {
                              if (n >= 30000 && n < 30512)
                                    printf("[%d] ", n - 30000);
                              else
                                    printf("%d ", n);
                        }
                        break;
                  }

            case 'w':{
                        int n = (int16)READ_BE_UINT16(p);
                        p += 2;
                        printf("%d ", n);
                        break;
                  }

            case 'I':{
                        int n = (int16)READ_BE_UINT16(p);
                        p += 2;
                        if (n == -1)
                              printf("SUBJECT_ITEM ");
                        else if (n == -3)
                              printf("OBJECT_ITEM ");
                        else if (n == -5)
                              printf("ME_ITEM ");
                        else if (n == -7)
                              printf("ACTOR_ITEM ");
                        else if (n == -9)
                              printf("ITEM_A_PARENT ");
                        else
                              printf("<%d> ", n);
                        break;
                  }

            case 'J':{
                        printf("-> ");
                  }
                  break;

            case 'T':{
                        uint n = READ_BE_UINT16(p);
                        p += 2;
                        if (n != 0xFFFF)
                              printf("\"%s\"(%d) ", getStringPtrByID(n), n);
                        else
                              printf("NULL_STRING ");
                  }
                  break;
            }
      }
}

void AGOSEngine::dumpSubroutineLine(SubroutineLine *sl, Subroutine *sub) {
      const byte *p;

      printf("; ****\n");

      p = (byte *)sl + SUBROUTINE_LINE_SMALL_SIZE;
      if (sub->id == 0) {
            printf("; verb=%d, noun1=%d, noun2=%d\n", sl->verb, sl->noun1, sl->noun2);
            p = (byte *)sl + SUBROUTINE_LINE_BIG_SIZE;
      }

      for (;;) {
            p = dumpOpcode(p);
            if (p == NULL)
                  break;
      }
}

void AGOSEngine::dumpSubroutine(Subroutine *sub) {
      SubroutineLine *sl;

      printf("\n******************************************\n;Subroutine, ID=%d:\nSUB_%d:\n", sub->id, sub->id);
      sl = (SubroutineLine *)((byte *)sub + sub->first);
      for (; (byte *)sl != (byte *)sub; sl = (SubroutineLine *)((byte *)sub + sl->next)) {
            dumpSubroutineLine(sl, sub);
      }
      printf("\nEND ******************************************\n");
}

void AGOSEngine::dumpSubroutines() {
      Subroutine *sub = _subroutineList;
      for (; sub; sub = sub->next) {
            dumpSubroutine(sub);
      }
}

void AGOSEngine::dumpAllSubroutines() {
      for (int i = 0; i < 65536; i++) {
            Subroutine *sub = getSubroutineByID(i);
            if (sub != NULL) {
                  dumpSubroutine(sub);
            }
      }
}

void AGOSEngine::dumpVideoScript(const byte *src, bool one_opcode_only) {
      uint opcode;
      const char *str, *strn;

      do {
            if (getGameType() == GType_SIMON2 || getGameType() == GType_FF || getGameType() == GType_PP) {
                  opcode = *src++;
            } else {
                  opcode = READ_BE_UINT16(src);
                  src += 2;
            }

            if (opcode >= _numVideoOpcodes) {
                  error("Invalid opcode %x", opcode);
            }

            if (getGameType() == GType_FF || getGameType() == GType_PP) {
                  strn = str = feeblefiles_videoOpcodeNameTable[opcode];
            } else if (getGameType() == GType_SIMON2) {
                  strn = str = simon2_videoOpcodeNameTable[opcode];
            } else if (getGameType() == GType_SIMON1) {
                  strn = str = simon1_videoOpcodeNameTable[opcode];
            } else if (getGameType() == GType_ELVIRA2 || getGameType() == GType_WW) {
                  strn = str = ww_videoOpcodeNameTable[opcode];
            } else {
                  strn = str = elvira1_videoOpcodeNameTable[opcode];
            }

            if (strn == NULL) {
                  error("dumpVideoScript: INVALID OPCODE %d", opcode);
            }

            while (*strn != '|')
                  strn++;
            printf("%.2d: %s ", opcode, strn + 1);

            int end = (getGameType() == GType_FF || getGameType() == GType_PP) ? 9999 : 999;
            for (; *str != '|'; str++) {
                  switch (*str) {
                  case 'x':
                        printf("\n");
                        return;
                  case 'b':
                        printf("%d ", *src++);
                        break;
                  case 'd':
                        printf("%d ", (int16)readUint16Wrapper(src));
                        src += 2;
                        break;
                  case 'v':
                        printf("[%d] ", readUint16Wrapper(src));
                        src += 2;
                        break;
                  case 'i':
                        printf("%d ", (int16)readUint16Wrapper(src));
                        src += 2;
                        break;
                  case 'j':
                        printf("-> ");
                        break;
                  case 'q':
                        while (readUint16Wrapper(src) != end) {
                              printf("(%d,%d) ", readUint16Wrapper(src),
                                                      readUint16Wrapper(src + 2));
                              src += 4;
                        }
                        src += 2;
                        break;
                  default:
                        error("Invalid fmt string '%c' in decompile VGA", *str);
                  }
            }

            printf("\n");
      } while (!one_opcode_only);
}

void AGOSEngine::dumpVgaScript(const byte *ptr, uint res, uint sprite_id) {
      dumpVgaScriptAlways(ptr, res, sprite_id);
}

void AGOSEngine::dumpVgaScriptAlways(const byte *ptr, uint res, uint sprite_id) {
      printf("; address=%x, vgafile=%d  vgasprite=%d\n",
                              (unsigned int)(ptr - _vgaBufferPointers[res].vgaFile1), res, sprite_id);
      dumpVideoScript(ptr, false);
      printf("; end\n");
}

void AGOSEngine::dumpVgaFile(const byte *vga) {
      const byte *pp;
      const byte *p;
      int count;

      pp = vga;
      if (getGameType() == GType_FF || getGameType() == GType_PP) {
            p = pp + READ_LE_UINT16(pp + 2);
            count = READ_LE_UINT16(&((const VgaFileHeader2_Feeble *) p)->animationCount);
            p = pp + READ_LE_UINT16(&((const VgaFileHeader2_Feeble *) p)->animationTable);

            while (--count >= 0) {
                  int id = READ_LE_UINT16(&((const AnimationHeader_Feeble *) p)->id);

                  dumpVgaScriptAlways(vga + READ_LE_UINT16(&((const AnimationHeader_Feeble *) p)->scriptOffs), id / 100, id);
                  p += sizeof(AnimationHeader_Feeble);
            }
      } else if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) {
            p = pp + READ_BE_UINT16(pp + 4);
            count = READ_BE_UINT16(&((const VgaFileHeader2_Common *) p)->animationCount);
            p = pp + READ_BE_UINT16(&((const VgaFileHeader2_Common *) p)->animationTable);

            while (--count >= 0) {
                  int id = READ_BE_UINT16(&((const AnimationHeader_Simon *) p)->id);

                  dumpVgaScriptAlways(vga + READ_BE_UINT16(&((const AnimationHeader_Simon *) p)->scriptOffs), id / 100, id);
                  p += sizeof(AnimationHeader_Simon);
            }
      } else {
            p = pp + READ_BE_UINT16(pp + 10) + 20;
            count = READ_BE_UINT16(&((const VgaFileHeader2_Common *) p)->animationCount);
            p = pp + READ_BE_UINT16(&((const VgaFileHeader2_Common *) p)->animationTable);

            while (--count >= 0) {
                  int id = READ_BE_UINT16(&((const AnimationHeader_WW *) p)->id);

                  dumpVgaScriptAlways(vga + READ_BE_UINT16(&((const AnimationHeader_WW *) p)->scriptOffs), id / 100, id);
                  p += sizeof(AnimationHeader_WW);
            }
      }

      pp = vga;
      if (getGameType() == GType_FF || getGameType() == GType_PP) {
            p = pp + READ_LE_UINT16(pp + 2);
            count = READ_LE_UINT16(&((const VgaFileHeader2_Feeble *) p)->imageCount);
            p = pp + READ_LE_UINT16(&((const VgaFileHeader2_Feeble *) p)->imageTable);

            while (--count >= 0) {
                  int id = READ_LE_UINT16(&((const ImageHeader_Feeble *) p)->id);

                  dumpVgaScriptAlways(vga + READ_LE_UINT16(&((const ImageHeader_Feeble *) p)->scriptOffs), id / 100, id);
                  p += sizeof(ImageHeader_Feeble);
            }
      } else if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) {
            p = pp + READ_BE_UINT16(pp + 4);
            count = READ_BE_UINT16(&((const VgaFileHeader2_Common *) p)->imageCount);
            p = pp + READ_BE_UINT16(&((const VgaFileHeader2_Common *) p)->imageTable);

            while (--count >= 0) {
                  int id = READ_BE_UINT16(&((const ImageHeader_Simon *) p)->id);

                  dumpVgaScriptAlways(vga + READ_BE_UINT16(&((const ImageHeader_Simon *) p)->scriptOffs), id / 100, id);
                  p += sizeof(ImageHeader_Simon);
            }
      } else {
            p = pp + READ_BE_UINT16(pp + 10) + 20;
            count = READ_BE_UINT16(&((const VgaFileHeader2_Common *) p)->imageCount);
            p = pp + READ_BE_UINT16(&((const VgaFileHeader2_Common *) p)->imageTable);

            while (--count >= 0) {
                  int id = READ_BE_UINT16(&((const ImageHeader_WW *) p)->id);

                  dumpVgaScriptAlways(vga + READ_BE_UINT16(&((const ImageHeader_WW *) p)->scriptOffs), id / 100, id);
                  p += sizeof(ImageHeader_WW);
            }
      }
}

static const byte bmp_hdr[] = {
      0x42, 0x4D,
      0x9E, 0x14, 0x00, 0x00,                   /* offset 2, file size */
      0x00, 0x00, 0x00, 0x00,
      0x36, 0x04, 0x00, 0x00,
      0x28, 0x00, 0x00, 0x00,

      0x3C, 0x00, 0x00, 0x00,                   /* image width */
      0x46, 0x00, 0x00, 0x00,                   /* image height */
      0x01, 0x00, 0x08, 0x00,
      0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00,

      0x00, 0x01, 0x00, 0x00,
      0x00, 0x01, 0x00, 0x00,
};

void dumpBMP(const char *filename, int w, int h, const byte *bytes, const uint32 *palette) {
      Common::File out;
      byte my_hdr[sizeof(bmp_hdr)];
      int i;

      out.open(filename, Common::File::kFileWriteMode);
      if (!out.isOpen())
            return;

      memcpy(my_hdr, bmp_hdr, sizeof(bmp_hdr));

      *(uint32 *)(my_hdr + 2) = w * h + 1024 + sizeof(bmp_hdr);
      *(uint32 *)(my_hdr + 18) = w;
      *(uint32 *)(my_hdr + 22) = h;


      out.write(my_hdr, sizeof(my_hdr));

      for (i = 0; i != 256; i++, palette++) {
            byte color[4];
            color[0] = (byte)(*palette >> 16);
            color[1] = (byte)(*palette >> 8);
            color[2] = (byte)(*palette);
            color[3] = 0;
            out.write(color, 4);
      }

      while (--h >= 0) {
            out.write(bytes + h * ((w + 3) & ~3), ((w + 3) & ~3));
      }
}

void AGOSEngine::dumpBitmap(const char *filename, const byte *offs, int w, int h, int flags, const byte *palette,
                                                 byte base) {

      if (getGameType() != GType_FF && getGameType() != GType_PP)
            w *= 16;

      /* allocate */
      byte *b = (byte *)malloc(w * h);
      int i, j;

      VC10_state state;

      state.depack_cont = -0x80;
      state.srcPtr = offs;
      state.dh = h;
      state.y_skip = 0;

      if (getGameType() == GType_FF || getGameType() == GType_PP) {
            for (i = 0; i != w; i++) {
                  byte *c = vc10_depackColumn(&state);
                  for (j = 0; j != h; j++) {
                        b[j * w + i] = c[j];
                  }
            }
      } else {
            for (i = 0; i != w; i += 2) {
                  byte *c = vc10_depackColumn(&state);
                  for (j = 0; j != h; j++) {
                        byte pix = c[j];
                        b[j * w + i] = (pix >> 4) | base;
                        b[j * w + i + 1] = (pix & 0xF) | base;
                  }
            }
      }

      dumpBMP(filename, w, h, b, (const uint32 *)palette);
      free(b);
}

void AGOSEngine::dumpSingleBitmap(int file, int image, const byte *offs, int w, int h, byte base) {
      char buf[40];

      sprintf(buf, "dumps/File%d_Image%d.bmp", file, image);

      if (Common::File::exists(buf))
            return;

      dumpBitmap(buf, offs, w, h, 0, _displayPalette, base);
}

void palLoad(byte *pal, const byte *vga1, int a, int b) {
      uint num = (a == 0) ? 0x20 : 0x10;
      byte *palptr;
      const byte *src;

      palptr = (byte *)&pal[a << 4];
      src = vga1 + 6 + b * 96;

      do {
            palptr[0] = src[0] << 2;
            palptr[1] = src[1] << 2;
            palptr[2] = src[2] << 2;
            palptr[3] = 0;

            palptr += 4;
            src += 3;
      } while (--num);
}

void AGOSEngine::dumpVgaBitmaps(const byte *vga, byte *vga1, int res) {
      int i;
      uint32 offs;
      const byte *p2;
      byte pal[768];

      memset(pal, 0, sizeof(pal));
      palLoad(pal, vga1, 2, 0);
      palLoad(pal, vga1, 3, 1);
      palLoad(pal, vga1, 4, 2);
      palLoad(pal, vga1, 5, 3);

      int width, height, flags;

      for (i = 1; ; i++) {
            p2 = vga + i * 8;
            offs = readUint32Wrapper(p2);

            /* try to detect end of images.
             * assume the end when offset >= 200kb */
            if (offs >= 204800)
                  return;

            if (getGameType() == GType_FF || getGameType() == GType_PP) {
                  width = READ_LE_UINT16(p2 + 6);
                  height = READ_LE_UINT16(p2 + 4) & 0x7FFF;
                  flags = p2[5];
            } else {
                  width = READ_BE_UINT16(p2 + 6) / 16;
                  height = p2[5];
                  flags = p2[4];
            }

            printf("Image %d. Width=%d, Height=%d, Flags=0x%X\n", i, width, height, flags);

            /* dump bitmap */
            char buf[40];
            sprintf(buf, "dumps/Res%d_Image%d.bmp", res, i);

            dumpBitmap(buf, vga + offs, width, height, flags, pal, 0);
      }
}

} // End of namespace AGOS

Generated by  Doxygen 1.6.0   Back to index