master ohmu/planport / sokoban / level.c
ohmu  ·  2026-09-07
  1#include <u.h>
  2#include <libc.h>
  3#include <bio.h>
  4#include <draw.h>
  5
  6#include "sokoban.h"
  7
  8void
  9consumeline(Biobuf *b)
 10{
 11	while(Bgetc(b) != '\n')
 12		;
 13}
 14
 15/* parse a level file */
 16int
 17loadlevels(char *path)
 18{
 19	Biobuf *b;
 20	int x = 0, y = 0, lnum = 0;
 21	char c;
 22		
 23	if(path == nil)
 24		return 0;
 25
 26	b = Bopen(path, OREAD);
 27	if(b == nil) {
 28		fprint(2, "could not open file %s: %r\n", path);
 29		return 0;
 30	}
 31
 32	memset(levels, 0, Maxlevels*sizeof(Level));
 33	
 34	while((c = Bgetc(b)) > 0) {
 35		switch(c)  {
 36		case ';':
 37			consumeline(b); 	/* no ';'-comments in the middle of a level */
 38			break;
 39		case '\n':
 40			levels[lnum].index = lnum;
 41			levels[lnum].done = 0;
 42			x = 0;
 43			levels[lnum].max.y = ++y;
 44
 45			c = Bgetc(b);
 46			if(c == '\n' || c == Beof) {
 47				/* end of level */
 48				if(++lnum == Maxlevels)
 49					goto Done;
 50
 51				x = 0;
 52				y = 0;
 53			} else
 54				Bungetc(b);
 55			break;
 56		case '#':
 57			levels[lnum].board[x][y] = Wall;
 58			x++;
 59			break;
 60		case ' ':
 61			levels[lnum].board[x][y] = Empty;
 62			x++;
 63			break;
 64		case '$':
 65			levels[lnum].board[x][y] = Cargo;
 66			x++;
 67			break;
 68		case '*':
 69			levels[lnum].board[x][y] = GoalCargo;
 70			x++;
 71			break;
 72		case '.':
 73			levels[lnum].board[x][y] = Goal;
 74			x++;
 75			break;
 76		case '@':
 77			levels[lnum].board[x][y] = Empty;
 78			levels[lnum].glenda = Pt(x, y);
 79			x++;
 80			break;
 81		case '+':
 82			levels[lnum].board[x][y] = Goal;
 83			levels[lnum].glenda = Pt(x, y);
 84			x++;
 85			break;
 86		default:
 87			fprint(2, "impossible character for level %d: %c\n", lnum+1, c);
 88			return 0;
 89		}
 90		if(x > levels[lnum].max.x)
 91			levels[lnum].max.x = x;
 92		levels[lnum].max.y = y;
 93	}
 94Done:
 95	Bterm(b);
 96
 97	level = levels[0];
 98	numlevels = lnum;
 99
100	return 1;
101}
102