diff --git a/example/data/fonts/blackcha.txt b/example/data/fonts/blackcha.txt new file mode 100644 index 0000000..99305e4 --- /dev/null +++ b/example/data/fonts/blackcha.txt @@ -0,0 +1,29 @@ +Black Chancery font +version of 11/19/91 by Earl Allen/Doug Miles +(Includes both PostScript and TrueType outlines) +----------------- + +Black Chancery is a calligraphic outline font based on the public domain bitmap font of the same name. It's a good looking and useful display font, lending itself well to many occasions. And a suitable companion to Black Chancery Italic. + +Black Chancery began, several years ago, as a modification of Bill Horton�s lovely FancyChancery 24 point bitmap, which had random dots missing from within the letters to give the effect of snow falling in front of them. (Rather like his Palazzo Grey font, part of Casady�s bitmap Fluent Fonts). Doug Miles filled in the dots, did some restyling, made five additional large point sizes, and gave it a new name. + +Earl Allen of Altsys Corp. used Fontographer 3.2 to autotrace the BlackChancery bitmaps to make PostScript Type 1 outlines, cleaned them up, adjusted character spacing and added kerning pairs. Doug Miles further cleaned-up the outlines, removing unneeded control points, adjusted the height and baseline positions of most characters, resized some of them, added accented letters and other option characters. He converted the numbers to "old style" figures, probably more appropriate for this font. + +(Note that Bill Horton has made his own public domain PostScript version of BlackChancery, considerably restyled and called MacHumaine. It's more angular looking, more faithful to actual hand-done broad-pen calligraphy. This extended the remarkable uncoordinated collaborative effort full circle, from his FancyChancery bitmaps, to Doug's BlackChancery version, to PostScript outlines by Marion Delahan, and back to Bill!) + +There is an optional lowercase j available by pressing Option-j, if you prefer a different style. There are now ligatures of ct and st at Option-comma and Option-period, and of course the ligatures of fi and fl are in their standard locations at Option-5 and Option-6. + +BlackChancery is great for headlines, letterheads, greeting cards. Wherever used, it adds an old-world elegance to your printed page. + + +11/19/91 Revisons: +Replaced all accented characters with composites +Changed ', ", �, a, d, g, q; f, �, �; �, �; reduced size of most accents by 15%. +Moved to right by 5 ems: p (1250 ems to the em-square) +Moved to right by 10 ems: i, �, l, t, u +Moved to right by 15 ems: b, h, k, m, n, r +Moved to left and narrowed by 30 ems: x +Moved to left and narrowed by 70 ems: v, w, y +Added 50 ems of leading, which had been 0. +Fixed a lot of little things here and there in conjunction with making the italic version. + diff --git a/example/data/fonts/blackcry.ttf b/example/data/fonts/blackcry.ttf new file mode 100644 index 0000000..cca5091 Binary files /dev/null and b/example/data/fonts/blackcry.ttf differ diff --git a/example/snake.c b/example/snake.c index 8b13789..97ae3e5 100644 --- a/example/snake.c +++ b/example/snake.c @@ -1 +1,376 @@ +#include + +#define SIZE 32 +#define WIDTH 16 +#define HEIGHT 16 +#define MAXLEN (WIDTH*HEIGHT+1) +#define MAXFOOD 5 +#define FRAMERATE 24 + + +enum TileType { + NONE, + WALL, + FOOD, + SNAKE +}; + +enum GameMode { + MENU, + START, + PLAY, + GAMEOVER +}; + + +int grid[WIDTH][HEIGHT]; +Sprite sprites[WIDTH][HEIGHT]; +Group gridGroup, storage; + +Sound nom, cut; + +int snake[MAXLEN][2]; +int len; +int foodCount; +int dx, dy; +int framesRemain; + +int optStop; +int optCut; +double optWalls; +int optStepFrames; + +int difficulty; + +int mode; + +Animation tileWall; +Animation tileFood; +Animation tileHead; +Animation tileBody; +Animation tileBend; +Animation tileTail; + +Font font; + + +void putFood() { + for(int i = 0; i < 100 && foodCount < MAXFOOD; ++i) { + int x = randomNumber(0, WIDTH-1); + int y = randomNumber(0, HEIGHT-1); + if (grid[x][y] == NONE) { + grid[x][y] = FOOD; + spriteSetAnimation(sprites[x][y], tileFood); + ++foodCount; + } + } +} + + +void setSnakeTile(int i) { + int x = snake[i][0]; + int y = snake[i][1]; + Sprite s = sprites[x][y]; + Animation tile = tileBody; + double rotation = 0; + + int left = FALSE; + int right = FALSE; + int top = FALSE; + int bottom = FALSE; + if (i > 0) { + left = left || snake[i-1][0] < x; + right = right || snake[i-1][0] > x; + top = top || snake[i-1][1] < y; + bottom = bottom || snake[i-1][1] > y; + } + if (i < len-1) { + left = left || snake[i+1][0] < x; + right = right || snake[i+1][0] > x; + top = top || snake[i+1][1] < y; + bottom = bottom || snake[i+1][1] > y; + } + + if (i == 0) { + tile = tileHead; + if (top) rotation = 90; + if (bottom) rotation = -90; + if (right) rotation = 180; + } else + if (i == len-1) { + tile = tileTail; + if (top) rotation = -90; + if (bottom) rotation = 90; + if (left) rotation = 180; + } else + if (left && top) { + tile = tileBend; + rotation = 180; + } else + if (left && bottom) { + tile = tileBend; + rotation = 90; + } else + if (right && top) { + tile = tileBend; + rotation = -90; + } else + if (right && bottom) { + tile = tileBend; + rotation = 0; + } else + if (top) { + rotation = 90; + } + + spriteSetAnimation(s, tile); + spriteSetRotation(s, rotation); +} + + +void resetTile(int x, int y) { + grid[x][y] = NONE; + Sprite s = sprites[x][y]; + spriteSetNoAnimation(s); + spriteSetRotation(s, 0); +} + + +void moveSnake() { + int x = snake[0][0] + dx; + int y = snake[0][1] + dy; + int cell = grid[x][y]; + + if (cell == WALL) { + if (!optStop) mode = GAMEOVER; + dx = snake[0][0] - snake[1][0]; + dy = snake[0][1] - snake[1][1]; + return; + } + + if (cell == SNAKE) { + if (!optCut) { mode = GAMEOVER; return; } + int prevLen = len; + for(int i = 0; i < len; ++i) + if (snake[i][0] == x && snake[i][1] == y) + { len=i; setSnakeTile(len-1); break; } + for(int i = len; i < prevLen; ++i) + resetTile(snake[i][0], snake[i][1]); + soundPlay(cut, FALSE); + } + + if (cell != NONE && cell != FOOD && cell != SNAKE) + { mode = GAMEOVER; return; } + + for(int i = len; i > 0; --i) { + snake[i][0] = snake[i-1][0]; + snake[i][1] = snake[i-1][1]; + } + snake[0][0] = x; + snake[0][1] = y; + + if (cell == FOOD || cell == SNAKE) { + grid[x][y] = SNAKE; + ++len; + setSnakeTile(0); + setSnakeTile(1); + } else { + grid[x][y] = SNAKE; + setSnakeTile(0); + setSnakeTile(1); + setSnakeTile(len-1); + resetTile(snake[len][0], snake[len][1]); + } + + if (cell == FOOD) { + --foodCount; + soundPlay(nom, FALSE); + putFood(); + } +} + + +void restart() { + optStepFrames = 12; + optWalls = 0; + optCut = TRUE; + optStop = TRUE; + switch(difficulty) { + case 2: + optStepFrames = 12; + optWalls = 0.01; + break; + case 3: + optStepFrames = 10; + optWalls = 0.02; + optCut = FALSE; + break; + case 4: + optStepFrames = 8; + optWalls = 0.04; + optCut = FALSE; + optStop = FALSE; + break; + case 5: + optStepFrames = 6; + optWalls = 0.06; + optCut = FALSE; + optStop = FALSE; + break; + }; + + + for(int x = 0; x < WIDTH; ++x) { + for(int y = 0; y < HEIGHT; ++y) { + grid[x][y] = NONE; + Sprite s = sprites[x][y]; + spriteSetRotation(s, 0); + spriteSetNoAnimation(s); + if ( x == 0 || y == 0 + || x == WIDTH-1 || y == HEIGHT-1 + || randomFloat() < optWalls ) + { + grid[x][y] = WALL; + spriteSetAnimation(s, tileWall); + } + } + } + + len = 2; + snake[0][0] = WIDTH/2; + snake[0][1] = HEIGHT/2; + snake[1][0] = snake[0][0] - 1; + snake[1][1] = snake[0][1]; + for(int i = 0; i < len; ++i) + grid[ snake[i][0] ][ snake[i][1] ] = SNAKE; + for(int i = 0; i < len; ++i) + setSnakeTile(i); + + dx = 1; + dy = 0; + + foodCount = 0; + putFood(); + + framesRemain = optStepFrames; + mode = START; +} + + +void init() { + tileWall = createAnimation("data/sprite/bricks.png"); + tileFood = createAnimation("data/sprite/apple.png"); + tileHead = createAnimation("data/sprite/snake/head.png"); + tileBody = createAnimation("data/sprite/snake/body.png"); + tileBend = createAnimation("data/sprite/snake/bend.png"); + tileTail = createAnimation("data/sprite/snake/tail.png"); + + font = createFont("data/fonts/blackcry.ttf"); + textFont(font); + + storage = createGroup(); + Animation tiles[6] = { tileWall, tileFood, tileHead, tileBody, tileBend, tileTail }; + for(int i = 0; i < 6; ++i) { + Sprite s = createSprite(0, 0); + spriteSetAnimation(s, tiles[i]); + groupAdd(storage, s); + } + groupSetVisibleEach(storage, FALSE); + + gridGroup = createGroup(); + for(int x = 0; x < WIDTH; ++x) { + for(int y = 0; y < HEIGHT; ++y) { + Sprite s = createSpriteEx((x + 0.5)*SIZE, (y + 0.5)*SIZE, SIZE, SIZE); + spriteSetShapeColor(s, colorByName("transparent")); + groupAdd(gridGroup, s); + sprites[x][y] = s; + } + } + + nom = createSound("data/sound/beep.ogg"); + cut = createSound("data/sound/nom.ogg"); + + mode = MENU; +} + + +void draw() { + double cx = worldGetWidth()/2.0; + double cy = worldGetHeight()/2.0; + + if (mode == PLAY) { + int prevdx = snake[0][0] - snake[1][0]; + int prevdy = snake[0][1] - snake[1][1]; + + if (keyWentDown("left") && (prevdx != 1 || prevdy != 0)) { dx = -1; dy = 0; framesRemain = 0; } + else if (keyWentDown("right") && (prevdx != -1 || prevdy != 0)) { dx = 1; dy = 0; framesRemain = 0; } + else if (keyWentDown("up") && (prevdx != 0 || prevdy != 1)) { dx = 0; dy = -1; framesRemain = 0; } + else if (keyWentDown("down") && (prevdx != 0 || prevdy != -1)) { dx = 0; dy = 1; framesRemain = 0; } + if (--framesRemain <= 0) { + moveSnake(); + framesRemain = optStepFrames; + } + drawSprites(); + if (keyWentDown("escape")) mode = MENU; + } else + if (mode == GAMEOVER) { + drawSprites(); + + fill(colorByRGBA(1, 1, 1, 0.25)); + rect(0, 0, worldGetWidth(), worldGetHeight()); + + noFill(); + textAlign(HALIGN_CENTER, HALIGN_CENTER); + textSize(24); + text("Game Over", cx, cy); + textSize(12); + text("press enter", cx, cy + 24); + if (keyWentDown("return")) mode = MENU; + if (keyWentDown("escape")) mode = MENU; + } else + if (mode == START) { + drawSprites(); + + fill(colorByRGBA(1, 1, 1, 0.25)); + rect(0, 0, worldGetWidth(), worldGetHeight()); + + noFill(); + textAlign(HALIGN_CENTER, VALIGN_CENTER); + textSize(24); + text("Press enter to start", cx, cy); + if (keyWentDown("return")) mode = PLAY; + if (keyWentDown("escape")) mode = MENU; + } else + if (mode == MENU) { + noFill(); + textAlign(HALIGN_LEFT, VALIGN_CENTER); + textSize(24); + int x = cx - 100; + int y = cy - 24*3; + text("Select difficulty level:", x, y); y += 24; + text("1 - very easy", x, y); y += 24; + text("2 - easy", x, y); y += 24; + text("3 - medium", x, y); y += 24; + text("4 - hard", x, y); y += 24; + text("5 - very hard", x, y); y += 24; + difficulty = 0; + if (keyWentDown("1")) difficulty = 1; + if (keyWentDown("2")) difficulty = 2; + if (keyWentDown("3")) difficulty = 3; + if (keyWentDown("4")) difficulty = 4; + if (keyWentDown("5")) difficulty = 5; + if (difficulty) restart(); + if (keyWentDown("escape")) worldStop(); + } +} + +int main() { + worldSetWidth(SIZE * WIDTH); + worldSetHeight(SIZE * HEIGHT); + worldSetFrameRate(FRAMERATE); + worldSetInit(&init); + worldSetDraw(&draw); + worldRun(); + return 0; +} diff --git a/src/common.c b/src/common.c index 53ba18c..78f59ac 100644 --- a/src/common.c +++ b/src/common.c @@ -179,7 +179,7 @@ unsigned int colorByName(const char *colorName) { } while (*a && *b); } } else { - double r, g, b, a; + double r = 0, g = 0, b = 0, a = 1; sscanf(x, "%lf %lf %lf %lf", &r, &g, &b, &a); code = colorByRGBA(r, g, b, a); }