示例#1
0
void PreviewScene::refresh(uint16_t (&playfield)[2][MAX_FIELD_HEIGHT][MAX_FIELD_WIDTH]) {

    // load the 3d tile resource
    // (NOTE: this is a temporary measure until actual graphic/palette
    // loading is implemented)
    // each palette zone is 216px tall and each row of tiles is
    // 32 tiles long.
    if (waterLevel(level))
        tiles.load(":images/3dtiles-water.png");
    else
        tiles.load(":images/3dtiles.png");

    int mapHeight = levelHeight(level);
    int mapWidth = level->header.width;
    int mapLength = level->header.length;
    level->header.fieldHeight = 2 * (mapHeight + mapWidth + mapLength + 2);
    level->header.fieldWidth  = 4 * (mapWidth + mapLength);

    int width = level->header.fieldWidth;
    int height = level->header.fieldHeight;

    // reset the scene (remove all members)
    this->clear();

    // set the pixmap and scene size based on the playfield's size
    QPixmap pixmap(width * ISO_TILE_SIZE, height * ISO_TILE_SIZE);
    pixmap.fill(QColor(0, 0, 0, 0));

    this->setSceneRect(0, 0, width * ISO_TILE_SIZE, height * ISO_TILE_SIZE);

    // no level area = don't render anything
    if (mapLength + mapWidth == 0) {
        this->addPixmap(pixmap);
        this->update();
        return;
    }

    // used to render one tile w/ flip etc. for each layer
    QPixmap layer1tile(ISO_TILE_SIZE, ISO_TILE_SIZE);
    QPixmap layer2tile(ISO_TILE_SIZE, ISO_TILE_SIZE);

    QPainter layer1painter, layer2painter;
    QPainter painter;

    painter.begin(&pixmap);

    for (int h = 0; h < height; h++) {
        for (int w = 0; w < width; w++) {
            layer1tile.fill(QColor(0,0,0,0));
            layer2tile.fill(QColor(0,0,0,0));

            uint16_t tile1 = playfield[0][h][w];
            if (TILE(tile1)) {
                int      y1    = (TILE(tile1) / 32) * ISO_TILE_SIZE
                               + (PALN(tile1) * 216);
                int      x1    = (TILE(tile1) % 32) * ISO_TILE_SIZE;

                layer1painter.begin(&layer1tile);
                layer1painter.drawPixmap(0, 0,
                                         tiles, x1, y1, ISO_TILE_SIZE, ISO_TILE_SIZE);
                layer1painter.end();

                // flip the pixmap horizontally and/or vertically
                layer1tile = QPixmap::fromImage(layer1tile.toImage().mirrored(tile1 & FH, tile1 & FV));
            }

            uint16_t tile2 = playfield[1][h][w];
            if (TILE(tile2)) {
                int      y2    = (TILE(tile2) / 32) * ISO_TILE_SIZE
                               + (PALN(tile2) * 216);
                int      x2    = (TILE(tile2) % 32) * ISO_TILE_SIZE;

                layer2painter.begin(&layer2tile);
                layer2painter.drawPixmap(0, 0,
                                         tiles, x2, y2, ISO_TILE_SIZE, ISO_TILE_SIZE);
                layer2painter.end();

                // flip the pixmap horizontally and/or vertically
                layer2tile = QPixmap::fromImage(layer2tile.toImage().mirrored(tile2 & FH, tile2 & FV));
            }

            // draw the tile pixmaps onto the scene
            // if layer 1 has priority, draw layer 2 first
            if (tile1 & PRI) {
                painter.drawPixmap(w * ISO_TILE_SIZE, h * ISO_TILE_SIZE, layer2tile);
                painter.drawPixmap(w * ISO_TILE_SIZE, h * ISO_TILE_SIZE, layer1tile);
            } else {
                painter.drawPixmap(w * ISO_TILE_SIZE, h * ISO_TILE_SIZE, layer1tile);
                painter.drawPixmap(w * ISO_TILE_SIZE, h * ISO_TILE_SIZE, layer2tile);
            }
        }
    }
    // next, if sprites are enabled, draw them
    // most of this is copied from the 2D draw code
    if (sprites) {
        for (int y = 0; y < mapLength; y++) {
            for (int x = 0; x < mapWidth; x++) {
                QPixmap gfx;
                int frame;
                int obs = level->tiles[y][x].obstacle;
                int z = level->tiles[y][x].height;

                if (obs == 0) continue;

                // whispy woods (index 0x00 in enemies.png)
                if (obs == 0x02) {
                    gfx = enemies;
                    frame = 0;

                // kirby's start pos (kirby.png)
                // (this time also use the final boss version)
                } else if (obs == 0x0c || obs == 0xc3) {
                    gfx = player;
                    frame = 0;

                // dedede (frame 0 in dedede.png)
                } else if (obs == 0x0d) {
                    gfx = dedede;
                    frame = 0;

                // most enemies (ind. 01 to 13 in enemies.png)
                } else if (obs >= 0x40 && obs <= 0x52) {
                    gfx = enemies;
                    frame = obs - 0x40 + 1;

                // transformer (ind. 14 in enemies.png
                } else if (obs == 0x57) {
                    gfx = enemies;
                    frame = 0x14;

                // gordo (ind. 00 to 21 in gordo.png)
                } else if (obs >= 0x80 && obs <= 0x97) {
                    gfx = gordo;
                    frame = obs - 0x80;

                // kracko (index 15-17 in enemies.png)
                } else if (obs >= 0xac && obs <= 0xae) {
                    gfx = enemies;
                    frame = obs - 0xac + 0x15;

                // anything else - question mark (or don't draw)
                } else {
                    obs = 0;
                }

                // draw the selected obstacle
                if (obs) {
                    // horizontal: start at 0 pixels
                    // move TILE_SIZE / 2 right for each positive move on the x-axis (west to east)
                    // and  TILE_SIZE / 2 left  for each positive move on the y-axis (north to south)
                    int startX = (TILE_SIZE / 2) * (x + (mapLength - y - 1));
                    // start at h * TILE_SIZE / 4 tiles
                    // move TILE_SIZE / 4 down for each positive move on the x-axis (west to east)
                    // and  TILE_SIZE / 4 down for each positive move on the y-axis (north to south)
                    // and  TILE_SIZE / 4 up   for each positive move on the z-axis (tile z)
                    // and then adjust for height of sprites
                    int startY = (TILE_SIZE / 4) * (mapHeight + x + y - z + 4) - gfx.height();
                    // move down half a tile's worth if the sprite is on a slope
                    if (level->tiles[y][x].geometry >= stuff::slopes)
                        startY += TILE_SIZE / 8;

                    painter.drawPixmap(startX, startY,
                                       gfx, frame * TILE_SIZE, 0,
                                       TILE_SIZE, gfx.height());
                }
            }
        }
    }

    // finally, add the 3d map pixmap onto the scene
    painter.end();

    this->addPixmap(pixmap);
    this->update();
}
示例#2
0
bool Mine::doCommand(RobotCommand command) {
  if (state != State::InProgress)
    return false;

  if (command == RobotCommand::Abort) {
    state = State::Aborted;
    commandHistory.push_back(command);
    return true;
  }

  int newRobotX = var.robotX;
  int newRobotY = var.robotY;

  std::vector<MineUpdate> updateQueue;

  int dx=0, dy=0;
  switch (command) {
	  case RobotCommand::Left:  dx=-1; break;
	  case RobotCommand::Right: dx=+1; break;
	  case RobotCommand::Up:    dy=+1; break;
	  case RobotCommand::Down:  dy=-1; break;
    default: break;
  }

  if (dx != 0 || dy != 0) {
    int nx = var.robotX + dx;
    int ny = var.robotY + dy;
    auto c = get(nx, ny);
    if (c == Tile::Empty || 
        c == Tile::Earth || 
        c == Tile::Lambda || 
        c == Tile::OpenLift || 
        c == Tile::Razor) {
      newRobotX = nx;
      newRobotY = ny;
    } else if (rockType(c) && dy == 0 && get(nx + dx, var.robotY) == Tile::Empty) {
      updateQueue.push_back({nx+dx, var.robotY, c});
      newRobotX = nx;
    } else if (c >= Tile::TrampolineA && c <= Tile::TrampolineI) {
      Tile target = problem->getTargetForTramp(c);
      Position jumpTo = problem->targetLoc[problem->indexOfTrampTarget(target)];
      newRobotX = jumpTo.x;
      newRobotY = jumpTo.y;
      for (auto i : problem->getTrampLocsForTarget(target)) {
        updateQueue.push_back({i.x, i.y, Tile::Empty});
      }
    } 

    // If we have been commanded to move, but haven't moved, command must not
    // have been valid, do nothing.
    if (newRobotX == var.robotX && newRobotY == var.robotY)
      return false;
  }

  if (command == RobotCommand::Slice) {
    if (var.curRazors > 0) {
      var.curRazors--;
      for (auto i : BeardDirs) {
        if (get(var.robotX + i.dx, var.robotY + i.dy) == Tile::Beard) {
          updateQueue.push_back({var.robotX + i.dx, var.robotY + i.dy, Tile::Empty});
        }
      }
    } else {
      return false;
    }
  }

  commandHistory.push_back(command);

  auto nr = get(newRobotX, newRobotY);
  if (nr == Tile::Lambda)
    ++var.collectedLambdas;
  else if (nr == Tile::Razor)
    ++var.curRazors;
  else if (nr == Tile::OpenLift)
    state = State::Win;

  updateQueue.push_back({var.robotX, var.robotY, Tile::Empty});
  updateQueue.push_back({newRobotX, newRobotY, Tile::Robot});

  // Apply all of the robot moves before computing the world update.
  for (auto update : updateQueue)
    set(update.x, update.y, update.c);
  updateQueue.clear();

  var.robotX = newRobotX;
  var.robotY = newRobotY;

  bool beardGrowTime = (moveCount()+1) % problem->beard.growthrate == 0;
  for (auto const& rockbeard : rockBeardPositions) {
    int x = rockbeard.x;
    int y = rockbeard.y;

    if (rockType(get(rockbeard))) {
      Tile thisRock = get(rockbeard);
      if (get(x, y - 1) == Tile::Empty) {
        updateQueue.push_back({x, y, Tile::Empty});
        if (thisRock == Tile::HigherOrderRock && get(x, y - 2) != Tile::Empty) {
          updateQueue.push_back({x, y - 1, Tile::Lambda});
        } else {
          updateQueue.push_back({x, y - 1, thisRock});
        }
      } else if (rockType(get(x, y - 1)) && get(x + 1, y) == Tile::Empty && get(x + 1, y - 1) == Tile::Empty) {
        updateQueue.push_back({x, y, Tile::Empty});
        if (thisRock == Tile::HigherOrderRock && get(x + 1, y - 2) != Tile::Empty) {
          updateQueue.push_back({x + 1, y - 1, Tile::Lambda});
        } else {
          updateQueue.push_back({x + 1, y - 1, thisRock});
        }
      } else if (rockType(get(x, y - 1)) && get(x - 1, y) == Tile::Empty && get(x - 1, y - 1) == Tile::Empty) {
        updateQueue.push_back({x, y, Tile::Empty});
        if (thisRock == Tile::HigherOrderRock && get(x - 1, y - 2) != Tile::Empty) {
          updateQueue.push_back({x - 1, y - 1, Tile::Lambda});
        } else {
          updateQueue.push_back({x - 1, y - 1, thisRock});
        }
      } else if (get(x, y - 1) == Tile::Lambda && get(x + 1, y) == Tile::Empty && get(x + 1, y - 1) == Tile::Empty) {
        updateQueue.push_back({x, y, Tile::Empty});
        if (thisRock == Tile::HigherOrderRock && get(x + 1, y - 2) != Tile::Empty) {
          updateQueue.push_back({x + 1, y - 1, Tile::Lambda});
        } else {
          updateQueue.push_back({x + 1, y - 1, thisRock});
        }
      }
    } else {
      assert(get(rockbeard) == Tile::Beard);
      if (beardGrowTime) {
        for ( auto dir : BeardDirs ) {
          int nx = x + dir.dx;
          int ny = y + dir.dy;
          if ( get(nx, ny) == Tile::Empty ) {
            updateQueue.push_back({nx, ny, Tile::Beard});
          }
        }
      }
    }
  }

  if (var.curWaterLevel <= var.robotY)
    var.submergedSteps = 0;

  var.curWaterLevel = waterLevel(totalMoves + 1);

  if (var.curWaterLevel > var.robotY)
    var.submergedSteps += 1;

  if (var.submergedSteps > problem->water.waterproof) {
    state = State::Lose;
  }

  if (var.collectedLambdas == problem->numInitialLambdas) {
    for (auto lift : problem->liftLoc)
      updateQueue.push_back({lift.x, lift.y, Tile::OpenLift});
  }

  for (auto update : updateQueue) {
    if ((rockType(update.c) || update.c == Tile::Lambda) && update.x == var.robotX && update.y == var.robotY + 1) {
      // Robot was hit on the head by rock
      state = State::Lose;
    }

    set(update.x, update.y, update.c);
  }

  ++totalMoves;
  return true;
}