Blob Blame Raw

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <helianthus.h>


Sprite player;
Group walls;
Group boxes;
Group places;

Animation animPlayer;
Animation animWall;
Animation animBox;
Animation animPlace;

Font font;


double speed = 256;

char levels[256][1024];
int levelsCount = 0;
int level = 0;


void loadLevel() {
  if (level < 0) level = levelsCount - 1;
  if (level >= levelsCount) level = 0;

  FILE *f = fopen(levels[level], "r");
  if (!f) {
    messageBox("Cannot open level file");
    return;
  }

  groupDestroyEach(walls);
  groupDestroyEach(boxes);
  groupDestroyEach(places);

  int c;
  int x = 32;
  int y = 32;
  int maxX = 0, maxY = 0;
  Sprite s;
  do {
    c = fgetc(f);

    if (c == '\n') { y += 64; x = 32; continue; }

    if (c == '.') {
      s = createSpriteEx(x, y, 10, 10);
      spriteSetAnimation(s, animPlace);
      spriteSetColliderCircle(s, 0, 0, -1);
      spriteSetDepth(s, 1);
      groupAdd(places, s);
    } else
    if (c == '#') {
      s = createSpriteEx(x, y, 64, 64);
      spriteSetAnimation(s, animWall);
      spriteSetMassLevel(s, 100);
      groupAdd(walls, s);
      if (maxX < x) maxX = x;
      if (maxY < y) maxY = y;
    } else
    if (c == 'B') {
      s = createSpriteEx(x, y, 62, 62);
      spriteSetAnimation(s, animBox);
      spriteSetColliderRectangle(s, 0, 0, 0, -1, -1, 16);
      groupAdd(boxes, s);
    } else
    if (c == '@') {
      spriteSetXY(player, x, y);
    }

    x += 64;
  } while (c != EOF);
  fclose(f);

  worldSetWidth(maxX + 32);
  worldSetHeight(maxY + 32);
}


void init() {
  background(colorByName("black"));

  animPlayer = createAnimation("data/sprite/breadball.png");
  animWall = createAnimation("data/sprite/bricks-tile.png");
  animBox = createAnimation("data/sprite/box.png");
  animPlace = createAnimation("data/sprite/dot.png");

  font = createFont("data/fonts/blackcry.ttf");
  textFont(font);

  player = createSpriteEx(0, 0, 62, 62);
  spriteSetAnimation(player, animPlayer);
  spriteSetColliderCircle(player, 0, 0, -1);

  walls = createGroup();
  boxes = createGroup();
  places = createGroup();

  Directory dir = openDirectory("data/levels/sokoban");
  if (!dir || !directoryGetCount(dir)) {
    messageBox("Cannot open levels directory");
    exit(1);
  }
  for(int i = 0; i < directoryGetCount(dir); ++i) {
    const char *filename = directoryGet(dir, i);
    int l = strlen(filename);
    if (l >= 6 && strcmp(filename + l - 6, ".level") == 0) {
      snprintf(levels[levelsCount], 1023, "data/levels/sokoban/%s", filename);
      ++levelsCount;
    }
  }
  closeDirectory(dir);

  loadLevel();
}


void draw() {
  double dt = worldGetFrameTime();

  double x = spriteGetX(player);
  double y = spriteGetY(player);
  double step = speed*dt;
  if (keyDown("left")) {
    spriteSetMirrorX(player, -1);
    spriteSetX(player, x - step);
  }
  if (keyDown("right")) {
    spriteSetMirrorX(player, 1);
    spriteSetX(player, x + step);
  }
  if (keyDown("up")) {
    spriteSetY(player, y - step);
  }
  if (keyDown("down")) {
    spriteSetY(player, y + step);
  }

  if (keyWentDown("r")) {
      loadLevel();
  }
  if (keyWentDown("pageup")) {
      --level;
      loadLevel();
  }
  if (keyWentDown("pagedown")) {
      ++level;
      loadLevel();
  }

  groupCollide(walls, player);
  groupCollide(boxes, player);
  groupCollideBetween(boxes);
  groupCollideGroup(walls, boxes);

  drawSprites();

  noFill();
  stroke(colorByName("white"));
  textAlign(HALIGN_CENTER, VALIGN_BOTTOM);
  text("R - restart level, PgUp - previous level, PgDown - next level", worldGetWidth()/2, worldGetHeight() - 10);
}


int main() {
	worldSetInit(&init);
	worldSetDraw(&draw);
	worldSetFrameRateEx(10, 100);
	worldRun();
	return 0;
}