summary refs log tree commit diff stats
path: root/data/maps/the_keen/rooms/Main Area.txtpb
Commit message (Collapse)AuthorAgeFilesLines
* Added the_keenStar Rauchenberger6 days1-0/+75
53' href='#n53'>53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
#ifndef COMMON_H_04DD2B2A
#define COMMON_H_04DD2B2A

#include <vector>
#include <string_view>
#include <fstream>
#include <stdexcept>

class BufferView {
public:

  BufferView(const std::vector<char>& buffer) : data_(&buffer) {}

  int ReadNextByte() {
    int o2r = offset_;
    offset_++;
    return ReadByte(o2r);
  }

  int ReadByte(int addr) const {
    return static_cast<unsigned char>((*data_)[addr]);
  }

  int ReadNextTwoBytes() {
    int o2r = offset_;
    offset_+=2;
    return ReadTwoBytes(o2r);
  }

  int ReadTwoBytes(int addr) const {
    return static_cast<unsigned char>((*data_)[addr]) | (static_cast<unsigned char>((*data_)[addr + 1]) << 8);
  }

  int ReadNextFourBytes() {
    int o2r = offset_;
    offset_+=4;
    return ReadFourBytes(o2r);
  }

  unsigned long ReadFourBytes(int addr) const {
    return static_cast<unsigned char>((*data_)[addr]) | (static_cast<unsigned char>((*data_)[addr + 1]) << 8) | (static_cast<unsigned char>((*data_)[addr + 2]) << 16) | (static_cast<unsigned char>((*data_)[addr + 3]) << 24);
  }

  void Seek(int offset) {
    offset_ = offset;
  }

  void SeekAdd(int delta) {
    offset_ += delta;
  }

  std::vector<char> Decompress(int addr) {
    int start = addr;
    Seek(addr);
    if (ReadNextByte() != 0x10) {
      throw std::domain_error("No LZ77 signature");
    }

    int length = ReadNextByte();
    length += (ReadNextByte() << 8);
    length += (ReadNextByte() << 16);

    std::vector<char> result(length, 0);

    int bPos = 0;
    while (bPos < length) {
      unsigned char ch = ReadNextByte();
      for (int i=0;i<8;i++) {
        switch ((ch >> (7-i)) & 1) {
          case 0: {
            if (bPos >= length) break;
            result[bPos++] = ReadNextByte();
            break;
          }
          case 1: {
            int t = (ReadNextByte() << 8);
            t += ReadNextByte();
            int n = ((t >> 12) & 0xF) + 3; // num of bytes to copy
            int o = (t & 0xFFF);

            for (int j=0; j<n; j++) {
              if (bPos >= length) break;
              result[bPos] = result[bPos - o - 1];
              bPos++;
            }
            break;
          }
          default: break;
        }
      }
    }

    return result;
  }

private:

  const std::vector<char>* data_;
  int offset_ = 0;
};

class Rom {
public:

  explicit Rom(std::string_view filename) {
    std::ifstream romfile(filename.data(), std::ios::binary);
    if (!romfile.is_open()) {
      throw std::invalid_argument("Could not find ROM file: " + std::string(filename));
    }

    romfile.seekg(0, romfile.end);
    int length = romfile.tellg();
    romfile.seekg(0, romfile.beg);

    if (length != 0x2000000) {
      throw std::invalid_argument("Incorrect ROM length");
    }

    data_ = std::vector<char>(length, 0);
    romfile.read(data_.data(), length);

    const char header[] = {'M','O','T','H','E','R','3',0,0,0,0,0,'A','3','U','J'};
    std::string headerTest;
    for (int i = 0xA0; i < 0xB0; i++) {
      if (data_.at(i) != header[i-0xA0]) {
        std::cout << i << std::endl;

        throw std::invalid_argument("Invalid ROM header");
      }
    }
  }

  const std::vector<char>& data() const { return data_; }

  BufferView buffer() const { return {data_}; }

private:

  std::vector<char> data_;
};

class Palette {
public:

  Palette() = default;

  Palette(BufferView m3, const int addr) {
    for (int i=0; i<16; i++) {
      unsigned short ch = m3.ReadTwoBytes(addr + (i << 1));
      int r = (ch & 0x1F);
      int g = ((ch >> 5) & 0x1F);
      int b = ((ch >> 10) & 0x1F);
      colors_.push_back(Magick::ColorRGB((r << 3)/256.0, (g << 3)/256.0, (b << 3)/256.0));
    }
  }

  const std::vector<Magick::Color>& Colors() const { return colors_; }

private:
  std::vector<Magick::Color> colors_;
};

#endif /* end of include guard: COMMON_H_04DD2B2A */