#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() {
worldSetTitle("Sokoban");
worldSetInit(&init);
worldSetDraw(&draw);
worldSetFrameRateEx(10, 100);
worldRun();
return 0;
}