|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
#include <math.h>
|
|
Ivan Mahonin |
7362e0 |
#include <stdio.h>
|
|
Ivan Mahonin |
7362e0 |
#include <assert.h>
|
|
Ivan Mahonin |
7362e0 |
#include <stdlib.h>
|
|
Ivan Mahonin |
7362e0 |
#include <string.h>
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
#include "helianthus.h"
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
cf0aba |
#define COLS 16
|
|
Ivan Mahonin |
cf0aba |
#define ROWS 9
|
|
Ivan Mahonin |
cf0aba |
#define ACTIVELETTERS 20
|
|
Ivan Mahonin |
cf0aba |
#define MAXLETTERS 256
|
|
Ivan Mahonin |
beb95c |
#define MAXSOUNDS 16
|
|
Ivan Mahonin |
7362e0 |
#define RMTIME 1.0
|
|
Ivan Mahonin |
cf0aba |
#define EXTIME 2.0
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
#define COUNT (ROWS*COLS)
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
typedef struct {
|
|
Ivan Mahonin |
7362e0 |
Animation glyphs[4];
|
|
Ivan Mahonin |
7362e0 |
int glyphsCount;
|
|
Ivan Mahonin |
beb95c |
Sound sounds[MAXSOUNDS];
|
|
Ivan Mahonin |
beb95c |
int soundsCount;
|
|
Ivan Mahonin |
7362e0 |
Animation g[4];
|
|
Ivan Mahonin |
7362e0 |
} Letter;
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
typedef struct {
|
|
Ivan Mahonin |
7362e0 |
int r, c;
|
|
Ivan Mahonin |
7362e0 |
} Pos;
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
typedef struct {
|
|
Ivan Mahonin |
7362e0 |
int len;
|
|
Ivan Mahonin |
7362e0 |
Pos p[4];
|
|
Ivan Mahonin |
7362e0 |
double tm;
|
|
Ivan Mahonin |
7362e0 |
} Track;
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
typedef struct {
|
|
Ivan Mahonin |
7362e0 |
Letter *l;
|
|
Ivan Mahonin |
7362e0 |
Animation g;
|
|
Ivan Mahonin |
7362e0 |
double tm;
|
|
Ivan Mahonin |
7362e0 |
} Cell;
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
cf0aba |
Letter menuLetter;
|
|
Ivan Mahonin |
7362e0 |
Letter letters[MAXLETTERS];
|
|
Ivan Mahonin |
7362e0 |
int lettersCount;
|
|
Ivan Mahonin |
7362e0 |
int cellWidth = 1;
|
|
Ivan Mahonin |
7362e0 |
int cellHeight = 1;
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
Cell board[ROWS][COLS];
|
|
Ivan Mahonin |
7362e0 |
Pos selected = { -1, -1 };
|
|
Ivan Mahonin |
7362e0 |
Track tracks[COUNT];
|
|
Ivan Mahonin |
7362e0 |
int tracksCount;
|
|
Ivan Mahonin |
7362e0 |
Animation bgtex;
|
|
Ivan Mahonin |
cf0aba |
int glyphsMask = 0;
|
|
Ivan Mahonin |
396d7d |
int mode;
|
|
Ivan Mahonin |
4958c9 |
int mute;
|
|
Ivan Mahonin |
cf0aba |
double exitTm;
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
beb95c |
|
|
Ivan Mahonin |
7362e0 |
void clearBoard() {
|
|
Ivan Mahonin |
cf0aba |
exitTm = 0;
|
|
Ivan Mahonin |
396d7d |
mode = 0;
|
|
Ivan Mahonin |
7362e0 |
memset(tracks, 0, sizeof(tracks));
|
|
Ivan Mahonin |
7362e0 |
memset(board, 0, sizeof(board));
|
|
Ivan Mahonin |
7362e0 |
tracksCount = 0;
|
|
Ivan Mahonin |
7362e0 |
selected = (Pos){ -1, -1 };
|
|
Ivan Mahonin |
7362e0 |
}
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
beb95c |
|
|
Ivan Mahonin |
beb95c |
void clearSounds() {
|
|
Ivan Mahonin |
beb95c |
for(int i = 0; i < lettersCount; ++i)
|
|
Ivan Mahonin |
beb95c |
for(int j = 0; j < letters[i].soundsCount; ++i)
|
|
Ivan Mahonin |
beb95c |
soundDestroy(letters[i].sounds[j]);
|
|
Ivan Mahonin |
beb95c |
}
|
|
Ivan Mahonin |
beb95c |
|
|
Ivan Mahonin |
beb95c |
|
|
Ivan Mahonin |
7362e0 |
void clearLetters() {
|
|
Ivan Mahonin |
7362e0 |
clearBoard();
|
|
Ivan Mahonin |
beb95c |
clearSounds();
|
|
Ivan Mahonin |
7362e0 |
for(int i = 0; i < lettersCount; ++i)
|
|
Ivan Mahonin |
7362e0 |
for(int j = 0; j < letters[i].glyphsCount; ++j)
|
|
Ivan Mahonin |
7362e0 |
animationDestroy(letters[i].glyphs[j]);
|
|
Ivan Mahonin |
7362e0 |
memset(letters, 0, sizeof(letters));
|
|
Ivan Mahonin |
cf0aba |
memset(&menuLetter, 0, sizeof(menuLetter));
|
|
Ivan Mahonin |
7362e0 |
lettersCount = 0;
|
|
Ivan Mahonin |
7362e0 |
cellWidth = cellHeight = 1;
|
|
Ivan Mahonin |
7362e0 |
}
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
beb95c |
|
|
Ivan Mahonin |
7362e0 |
int loadLetters(const char *filename, int rows, int cols) {
|
|
Ivan Mahonin |
7362e0 |
clearLetters();
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
int w, h;
|
|
Ivan Mahonin |
7362e0 |
unsigned char *pixels;
|
|
Ivan Mahonin |
7362e0 |
if (!imageLoad(filename, &w, &h, &pixels))
|
|
Ivan Mahonin |
7362e0 |
return FALSE;
|
|
Ivan Mahonin |
7362e0 |
int stride = w*4;
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
int ww = w/cols/2;
|
|
Ivan Mahonin |
7362e0 |
int hh = h/rows/2;
|
|
Ivan Mahonin |
7362e0 |
if (!ww || !hh)
|
|
Ivan Mahonin |
7362e0 |
{ free(pixels); return FALSE; }
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
int bufstride = ww*4;
|
|
Ivan Mahonin |
7362e0 |
int bufsize = hh*bufstride;
|
|
Ivan Mahonin |
7362e0 |
unsigned char *buf = calloc(bufsize, 1);
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
Letter *letter = letters;
|
|
Ivan Mahonin |
7362e0 |
for(int r = 0; r < rows; ++r)
|
|
Ivan Mahonin |
7362e0 |
for(int c = 0; c < cols; ++c)
|
|
Ivan Mahonin |
7362e0 |
{
|
|
Ivan Mahonin |
7362e0 |
for(int rr = 0; rr < 2; ++rr)
|
|
Ivan Mahonin |
7362e0 |
for(int cc = 0; cc < 2; ++cc) {
|
|
Ivan Mahonin |
7362e0 |
unsigned char *p = pixels + (r*2 + rr)*hh*stride + (c*2 + cc)*bufstride;
|
|
Ivan Mahonin |
7362e0 |
for(int rrr = 0; rrr < hh; ++rrr) memcpy(buf + rrr*bufstride, p + rrr*stride, bufstride);
|
|
Ivan Mahonin |
7362e0 |
unsigned int visible = 0;
|
|
Ivan Mahonin |
7362e0 |
for(unsigned char *b = buf + 3, *e = b + bufsize; b < e; b += 4) visible += *b;
|
|
Ivan Mahonin |
7362e0 |
if (!visible) continue;
|
|
Ivan Mahonin |
7362e0 |
letter->glyphs[ letter->glyphsCount++ ] = createAnimationFromImage(ww, hh, buf, TRUE);
|
|
Ivan Mahonin |
7362e0 |
}
|
|
Ivan Mahonin |
cf0aba |
if (letter->glyphsCount > menuLetter.glyphsCount) menuLetter = *letter;
|
|
Ivan Mahonin |
7362e0 |
if (letter->glyphsCount > 0) ++letter;
|
|
Ivan Mahonin |
7362e0 |
}
|
|
Ivan Mahonin |
7362e0 |
lettersCount = letter - letters;
|
|
Ivan Mahonin |
7362e0 |
cellWidth = ww;
|
|
Ivan Mahonin |
7362e0 |
cellHeight = hh;
|
|
Ivan Mahonin |
cf0aba |
assert(menuLetter.glyphsCount == 4);
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
free(buf);
|
|
Ivan Mahonin |
7362e0 |
free(pixels);
|
|
Ivan Mahonin |
7362e0 |
return TRUE;
|
|
Ivan Mahonin |
7362e0 |
}
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
beb95c |
void loadSounds(const char *path) {
|
|
Ivan Mahonin |
beb95c |
Directory dir = openDirectoryEx(path, "", ".ogg", FALSE, TRUE, FALSE);
|
|
Ivan Mahonin |
beb95c |
if (!dir) return;
|
|
Ivan Mahonin |
beb95c |
for(int i = 0; i < directoryGetCount(dir); ++i) {
|
|
Ivan Mahonin |
beb95c |
int index = atoi(directoryGet(dir, i));
|
|
Ivan Mahonin |
beb95c |
if (index <= 0 || index > lettersCount) continue;
|
|
Ivan Mahonin |
beb95c |
Letter *l = &letters[index-1];
|
|
Ivan Mahonin |
beb95c |
if (l->soundsCount >= MAXSOUNDS) continue;
|
|
Ivan Mahonin |
beb95c |
l->sounds[l->soundsCount] = createSound(directoryGetFull(dir, i));
|
|
Ivan Mahonin |
beb95c |
if (l->sounds[l->soundsCount]) ++l->soundsCount;
|
|
Ivan Mahonin |
beb95c |
}
|
|
Ivan Mahonin |
beb95c |
closeDirectory(dir);
|
|
Ivan Mahonin |
beb95c |
}
|
|
Ivan Mahonin |
beb95c |
|
|
Ivan Mahonin |
beb95c |
|
|
Ivan Mahonin |
396d7d |
void shuffleLetters(int glyps) {
|
|
Ivan Mahonin |
7362e0 |
for(int i = 0; i < lettersCount; ++i) {
|
|
Ivan Mahonin |
7362e0 |
int j = randomNumber(i, lettersCount - 1);
|
|
Ivan Mahonin |
7362e0 |
if (j != i) { Letter l = letters[i]; letters[i] = letters[j]; letters[j] = l; }
|
|
Ivan Mahonin |
7362e0 |
Letter *l = &letters[i];
|
|
Ivan Mahonin |
7362e0 |
assert(l->glyphsCount > 0);
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
396d7d |
int gc = 0;
|
|
Ivan Mahonin |
396d7d |
Animation g[4] = {};
|
|
Ivan Mahonin |
396d7d |
for(int j = 0; j < l->glyphsCount; ++j)
|
|
Ivan Mahonin |
396d7d |
if (glyps & (1 << j)) g[gc++] = l->glyphs[j];
|
|
Ivan Mahonin |
396d7d |
if (!gc) g[gc++] = l->glyphs[0];
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
396d7d |
for(int j = 0; j < gc; ++j) {
|
|
Ivan Mahonin |
396d7d |
int k = randomNumber(j, gc - 1);
|
|
Ivan Mahonin |
396d7d |
if (k != j) { Animation a = g[j]; g[j] = g[k]; g[k] = a; }
|
|
Ivan Mahonin |
7362e0 |
}
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
396d7d |
for(int j = 0; j < 4; ++j)
|
|
Ivan Mahonin |
396d7d |
l->g[j] = g[j%gc];
|
|
Ivan Mahonin |
396d7d |
|
|
Ivan Mahonin |
7362e0 |
for(int j = 0; j < 4; ++j) {
|
|
Ivan Mahonin |
7362e0 |
int k = randomNumber(j, 3);
|
|
Ivan Mahonin |
7362e0 |
if (k != j) { Animation g = l->g[j]; l->g[j] = l->g[k]; l->g[k] = g; }
|
|
Ivan Mahonin |
7362e0 |
assert(l->g[j]);
|
|
Ivan Mahonin |
7362e0 |
}
|
|
Ivan Mahonin |
7362e0 |
}
|
|
Ivan Mahonin |
7362e0 |
}
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
beb95c |
void simpleBoard() {
|
|
Ivan Mahonin |
beb95c |
clearBoard();
|
|
Ivan Mahonin |
beb95c |
for(int i = 0; i < COUNT; ++i) {
|
|
Ivan Mahonin |
beb95c |
Letter *l = &letters[i%lettersCount];
|
|
Ivan Mahonin |
beb95c |
board[i/COLS][i%COLS].l = l;
|
|
Ivan Mahonin |
beb95c |
board[i/COLS][i%COLS].g = l->glyphs[1];
|
|
Ivan Mahonin |
beb95c |
}
|
|
Ivan Mahonin |
beb95c |
mode = 1;
|
|
Ivan Mahonin |
beb95c |
}
|
|
Ivan Mahonin |
beb95c |
|
|
Ivan Mahonin |
beb95c |
|
|
Ivan Mahonin |
396d7d |
void generateBoard(int glyphsMask, int maxLetters) {
|
|
Ivan Mahonin |
396d7d |
if (maxLetters < 1) maxLetters = 1;
|
|
Ivan Mahonin |
396d7d |
|
|
Ivan Mahonin |
7362e0 |
clearBoard();
|
|
Ivan Mahonin |
396d7d |
shuffleLetters(glyphsMask);
|
|
Ivan Mahonin |
396d7d |
|
|
Ivan Mahonin |
7362e0 |
int indices[COUNT];
|
|
Ivan Mahonin |
7362e0 |
for(int i = 0; i < COUNT; ++i) indices[i] = i;
|
|
Ivan Mahonin |
396d7d |
|
|
Ivan Mahonin |
eecafb |
int lc = lettersCount < maxLetters ? lettersCount : maxLetters;
|
|
Ivan Mahonin |
7362e0 |
for(int i = 0; i < COUNT; ++i) {
|
|
Ivan Mahonin |
7362e0 |
int j = randomNumber(i, COUNT-1);
|
|
Ivan Mahonin |
7362e0 |
int id = indices[j]; indices[j] = indices[i]; indices[i] = id;
|
|
Ivan Mahonin |
396d7d |
Letter *l = &letters[ (id/4)%lc ];
|
|
Ivan Mahonin |
7362e0 |
board[i/COLS][i%COLS].l = l;
|
|
Ivan Mahonin |
7362e0 |
board[i/COLS][i%COLS].g = l->g[id%4];
|
|
Ivan Mahonin |
7362e0 |
}
|
|
Ivan Mahonin |
396d7d |
|
|
Ivan Mahonin |
396d7d |
mode = 1;
|
|
Ivan Mahonin |
7362e0 |
}
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
Letter* get(Pos p)
|
|
Ivan Mahonin |
7362e0 |
{ return p.r >= 0 && p.r < ROWS && p.c >= 0 && p.c < COLS ? board[p.r][p.c].l : NULL; }
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
int findSubTrack1(Track *t, Pos b) {
|
|
Ivan Mahonin |
7362e0 |
Pos p = t->p[t->len - 1];
|
|
Ivan Mahonin |
7362e0 |
//printf(" -- -- ft1: %d %d -> %d %d\n", p.r, p.c, b.r, b.c);
|
|
Ivan Mahonin |
7362e0 |
if (p.c == b.c && p.r < b.r) { for(++p.r; p.r != b.r; ++p.r) if (get(p)) return FALSE; } else
|
|
Ivan Mahonin |
7362e0 |
if (p.c == b.c && p.r > b.r) { for(--p.r; p.r != b.r; --p.r) if (get(p)) return FALSE; } else
|
|
Ivan Mahonin |
7362e0 |
if (p.r == b.r && p.c < b.c) { for(++p.c; p.c != b.c; ++p.c) if (get(p)) return FALSE; } else
|
|
Ivan Mahonin |
7362e0 |
if (p.r == b.r && p.c > b.c) { for(--p.c; p.c != b.c; --p.c) if (get(p)) return FALSE; } else return FALSE;
|
|
Ivan Mahonin |
7362e0 |
t->p[t->len++] = p;
|
|
Ivan Mahonin |
7362e0 |
return TRUE;
|
|
Ivan Mahonin |
7362e0 |
}
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
int findSubTrack2(Track *t, Pos b, int horz) {
|
|
Ivan Mahonin |
7362e0 |
Pos *p = &t->p[t->len];
|
|
Ivan Mahonin |
7362e0 |
*p = t->p[t->len - 1];
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
//printf(" -- ft2: %d %d -> %d %d %s\n", p->r, p->c, b.r, b.c, horz ? "horz" : "vert");
|
|
Ivan Mahonin |
7362e0 |
if (p->c == b.c || p->r == b.r) return findSubTrack1(t, b);
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
++t->len;
|
|
Ivan Mahonin |
7362e0 |
if (horz) {
|
|
Ivan Mahonin |
7362e0 |
if (p->c < b.c) { for(++p->c; p->c != b.c; ++p->c) if (get(*p)) break; }
|
|
Ivan Mahonin |
7362e0 |
else { for(--p->c; p->c != b.c; --p->c) if (get(*p)) break; }
|
|
Ivan Mahonin |
7362e0 |
} else {
|
|
Ivan Mahonin |
7362e0 |
if (p->r < b.r) { for(++p->r; p->r != b.r; ++p->r) if (get(*p)) break; }
|
|
Ivan Mahonin |
7362e0 |
else { for(--p->r; p->r != b.r; --p->r) if (get(*p)) break; }
|
|
Ivan Mahonin |
7362e0 |
}
|
|
Ivan Mahonin |
7362e0 |
if (!get(*p) && findSubTrack1(t, b)) return TRUE;
|
|
Ivan Mahonin |
7362e0 |
--t->len;
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
return FALSE;
|
|
Ivan Mahonin |
7362e0 |
}
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
int findSubTrack3(Track *t, Pos b) {
|
|
Ivan Mahonin |
7362e0 |
Pos p0 = t->p[t->len - 1];
|
|
Ivan Mahonin |
7362e0 |
Pos *p = &t->p[t->len];
|
|
Ivan Mahonin |
7362e0 |
if (p->c == b.c && p->r == b.r) return FALSE;
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
//printf("ft3: %d %d -> %d %d\n", p0.r, p0.c, b.r, b.c);
|
|
Ivan Mahonin |
7362e0 |
if (findSubTrack2(t, b, FALSE)) return TRUE;
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
++t->len;
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
*p = p0;
|
|
Ivan Mahonin |
7362e0 |
for(++p->c; p->c <= COLS; ++p->c)
|
|
Ivan Mahonin |
7362e0 |
if (get(*p)) break; else
|
|
Ivan Mahonin |
7362e0 |
if (findSubTrack2(t, b, FALSE)) return TRUE;
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
*p = p0;
|
|
Ivan Mahonin |
7362e0 |
for(--p->c; p->c >= -1; --p->c)
|
|
Ivan Mahonin |
7362e0 |
if (get(*p)) break; else
|
|
Ivan Mahonin |
7362e0 |
if (findSubTrack2(t, b, FALSE)) return TRUE;
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
*p = p0;
|
|
Ivan Mahonin |
7362e0 |
for(++p->r; p->r <= ROWS; ++p->r)
|
|
Ivan Mahonin |
7362e0 |
if (get(*p)) break; else
|
|
Ivan Mahonin |
7362e0 |
if (findSubTrack2(t, b, TRUE)) return TRUE;
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
*p = p0;
|
|
Ivan Mahonin |
7362e0 |
for(--p->r; p->r >= -1; --p->r)
|
|
Ivan Mahonin |
7362e0 |
if (get(*p)) break; else
|
|
Ivan Mahonin |
7362e0 |
if (findSubTrack2(t, b, TRUE)) return TRUE;
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
--t->len;
|
|
Ivan Mahonin |
7362e0 |
return FALSE;
|
|
Ivan Mahonin |
7362e0 |
}
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
Track findTrack(Pos a, Pos b) {
|
|
Ivan Mahonin |
7362e0 |
Track t = {};
|
|
Ivan Mahonin |
7362e0 |
t.p[t.len++] = a;
|
|
Ivan Mahonin |
7362e0 |
Letter *la = get(a);
|
|
Ivan Mahonin |
7362e0 |
Letter *lb = get(b);
|
|
Ivan Mahonin |
7362e0 |
return la && la == lb && (a.c != b.c || a.r != b.r) && findSubTrack3(&t, b) ? t : (Track){};
|
|
Ivan Mahonin |
7362e0 |
}
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
void hint() {
|
|
Ivan Mahonin |
7362e0 |
if (tracksCount) return;
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
for(int i = 0; i < COUNT; ++i) {
|
|
Ivan Mahonin |
7362e0 |
Pos a = { i/COLS, i%COLS };
|
|
Ivan Mahonin |
7362e0 |
for(int j = 0; j < COUNT; ++j) {
|
|
Ivan Mahonin |
7362e0 |
Pos b = { j/COLS, j%COLS };
|
|
Ivan Mahonin |
7362e0 |
Track t = findTrack(a, b);
|
|
Ivan Mahonin |
7362e0 |
if (t.len) {
|
|
Ivan Mahonin |
7362e0 |
t.tm = 1;
|
|
Ivan Mahonin |
7362e0 |
tracks[tracksCount++] = t;
|
|
Ivan Mahonin |
7362e0 |
}
|
|
Ivan Mahonin |
7362e0 |
}
|
|
Ivan Mahonin |
7362e0 |
}
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
if (!tracksCount) return; // beep
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
int i = randomNumber(0, tracksCount - 1);
|
|
Ivan Mahonin |
7362e0 |
if (i) tracks[0] = tracks[i];
|
|
Ivan Mahonin |
7362e0 |
tracksCount = 1;
|
|
Ivan Mahonin |
7362e0 |
}
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
void init() {
|
|
Ivan Mahonin |
7362e0 |
bgtex = createAnimationEx("data/shisen/minas.png", TRUE, TRUE, TRUE);
|
|
Ivan Mahonin |
7362e0 |
if (!loadLetters("data/shisen/letters-gen.png", 5, 8)) {
|
|
Ivan Mahonin |
7362e0 |
printf("cannot load letters\n");
|
|
Ivan Mahonin |
7362e0 |
windowStop();
|
|
Ivan Mahonin |
7362e0 |
return;
|
|
Ivan Mahonin |
7362e0 |
}
|
|
Ivan Mahonin |
beb95c |
loadSounds("data/shisen/sounds");
|
|
Ivan Mahonin |
beb95c |
//simpleBoard();
|
|
Ivan Mahonin |
7362e0 |
}
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
void draw() {
|
|
Ivan Mahonin |
7362e0 |
double w = windowGetWidth();
|
|
Ivan Mahonin |
7362e0 |
double h = windowGetHeight();
|
|
Ivan Mahonin |
7362e0 |
double dt = windowGetFrameTime();
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
saveState();
|
|
Ivan Mahonin |
7362e0 |
translate(w*0.5, h*0.5);
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
{
|
|
Ivan Mahonin |
7362e0 |
saveState();
|
|
Ivan Mahonin |
7362e0 |
double aw = animationGetFrameOrigWidth(bgtex, 0);
|
|
Ivan Mahonin |
7362e0 |
double ah = animationGetFrameOrigHeight(bgtex, 0);
|
|
Ivan Mahonin |
7362e0 |
double kw = w/aw;
|
|
Ivan Mahonin |
7362e0 |
double kh = h/ah;
|
|
Ivan Mahonin |
7362e0 |
double k = kw > kh ? kw: kh;
|
|
Ivan Mahonin |
7362e0 |
aw *= k;
|
|
Ivan Mahonin |
7362e0 |
ah *= k;
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
noStroke();
|
|
Ivan Mahonin |
7362e0 |
rectTextured(bgtex, -0.5*aw, -0.5*ah, aw, ah);
|
|
Ivan Mahonin |
7362e0 |
fill(colorByRGBA(1.0, 1.0, 1.0, 0.5));
|
|
Ivan Mahonin |
7362e0 |
rect(-0.5*aw, -0.5*ah, aw, ah);
|
|
Ivan Mahonin |
7362e0 |
restoreState();
|
|
Ivan Mahonin |
7362e0 |
}
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
396d7d |
if (mode == 0) {
|
|
Ivan Mahonin |
396d7d |
double kw = w/(cellWidth*6);
|
|
Ivan Mahonin |
396d7d |
double kh = h/(cellHeight*3);
|
|
Ivan Mahonin |
396d7d |
double k = kw < kh ? kw: kh;
|
|
Ivan Mahonin |
396d7d |
if (k > 1) k = 1;
|
|
Ivan Mahonin |
396d7d |
zoom(k);
|
|
Ivan Mahonin |
396d7d |
noStroke();
|
|
Ivan Mahonin |
396d7d |
translate(-cellWidth*2, -0.5*cellHeight);
|
|
Ivan Mahonin |
396d7d |
assert(letters[0].glyphsCount >= 4);
|
|
Ivan Mahonin |
396d7d |
|
|
Ivan Mahonin |
396d7d |
int mc = (int)floor(mouseTransformedX()/cellWidth);
|
|
Ivan Mahonin |
396d7d |
int mr = (int)floor(mouseTransformedY()/cellHeight);
|
|
Ivan Mahonin |
396d7d |
if (!mr && mc >= 0 && mc < 4 && mouseWentDown("left")) glyphsMask ^= 1 << mc;
|
|
Ivan Mahonin |
396d7d |
|
|
Ivan Mahonin |
396d7d |
for(int i = 0; i < 4; ++i) {
|
|
Ivan Mahonin |
396d7d |
double s = !mr && mc == i ? 1 : 0.9;
|
|
Ivan Mahonin |
396d7d |
double d = (1 - s)/2;
|
|
Ivan Mahonin |
396d7d |
double a = glyphsMask & (1 << i) ? 1.0 : 0.5;
|
|
Ivan Mahonin |
396d7d |
fill(colorByRGBA(1, 1, 1, a));
|
|
Ivan Mahonin |
cf0aba |
rectTextured(menuLetter.glyphs[i], (i + d)*cellWidth, d*cellHeight, cellWidth*s, cellHeight*s);
|
|
Ivan Mahonin |
7362e0 |
}
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
396d7d |
if (glyphsMask) {
|
|
Ivan Mahonin |
396d7d |
noFill();
|
|
Ivan Mahonin |
396d7d |
stroke(colorByRGBA(0.0, 0.0, 0.0, 0.75));
|
|
Ivan Mahonin |
cf0aba |
textAlign(HALIGN_CENTER, VALIGN_CENTER);
|
|
Ivan Mahonin |
396d7d |
textSize(cellHeight*0.5);
|
|
Ivan Mahonin |
396d7d |
text(2*cellWidth, 1.5*cellHeight, "press enter");
|
|
Ivan Mahonin |
396d7d |
if ( keyWentDown("any enter")
|
|
Ivan Mahonin |
396d7d |
|| (mr == 1 && mc >= 0 && mc < 4 && mouseWentDown("left")) )
|
|
Ivan Mahonin |
cf0aba |
generateBoard(glyphsMask, ACTIVELETTERS);
|
|
Ivan Mahonin |
396d7d |
}
|
|
Ivan Mahonin |
cf0aba |
|
|
Ivan Mahonin |
cf0aba |
if (keyWentDown("escape")) windowStop();
|
|
Ivan Mahonin |
396d7d |
} else {
|
|
Ivan Mahonin |
cf0aba |
double kw = w/(cellWidth*(COLS + 4));
|
|
Ivan Mahonin |
396d7d |
double kh = h/(cellHeight*(ROWS + 2));
|
|
Ivan Mahonin |
396d7d |
double k = kw < kh ? kw: kh;
|
|
Ivan Mahonin |
396d7d |
zoom(k);
|
|
Ivan Mahonin |
396d7d |
|
|
Ivan Mahonin |
396d7d |
translate(-0.5*COLS*cellWidth, -0.5*ROWS*cellHeight);
|
|
Ivan Mahonin |
396d7d |
strokeWidth(0.1*cellWidth);
|
|
Ivan Mahonin |
396d7d |
|
|
Ivan Mahonin |
cf0aba |
saveState();
|
|
Ivan Mahonin |
cf0aba |
noFill();
|
|
Ivan Mahonin |
cf0aba |
stroke(colorByRGBA(0.0, 0.0, 0.0, 0.75));
|
|
Ivan Mahonin |
cf0aba |
textSize(cellWidth*0.5);
|
|
Ivan Mahonin |
cf0aba |
textAlign(HALIGN_RIGHT, VALIGN_BOTTOM);
|
|
Ivan Mahonin |
cf0aba |
text(-0.2*cellWidth, -0.2*cellHeight, "back");
|
|
Ivan Mahonin |
cf0aba |
textAlign(HALIGN_LEFT, VALIGN_TOP);
|
|
Ivan Mahonin |
cf0aba |
text((COLS + 0.2)*cellWidth, (ROWS + 0.2)*cellHeight, "hint");
|
|
Ivan Mahonin |
4958c9 |
textAlign(HALIGN_LEFT, VALIGN_BOTTOM);
|
|
Ivan Mahonin |
4958c9 |
text((COLS + 0.2)*cellWidth, -0.2*cellHeight, mute ? "silence" : "sound");
|
|
Ivan Mahonin |
cf0aba |
restoreState();
|
|
Ivan Mahonin |
396d7d |
|
|
Ivan Mahonin |
396d7d |
double mx = mouseTransformedX();
|
|
Ivan Mahonin |
396d7d |
double my = mouseTransformedY();
|
|
Ivan Mahonin |
396d7d |
Pos hover = {};
|
|
Ivan Mahonin |
396d7d |
hover.r = (int)floor(my/cellHeight);
|
|
Ivan Mahonin |
cf0aba |
hover.c = (int)floor(mx/cellWidth);
|
|
Ivan Mahonin |
cf0aba |
|
|
Ivan Mahonin |
cf0aba |
if (hover.r < 0 && hover.c < 0 && mouseDown("left"))
|
|
Ivan Mahonin |
cf0aba |
exitTm += dt/EXTIME; else exitTm = 0;
|
|
Ivan Mahonin |
cf0aba |
if (keyWentDown("escape") || exitTm >= 1)
|
|
Ivan Mahonin |
cf0aba |
clearBoard();
|
|
Ivan Mahonin |
cf0aba |
|
|
Ivan Mahonin |
396d7d |
if (mouseWentDown("left")) {
|
|
Ivan Mahonin |
beb95c |
Letter *l = get(hover);
|
|
Ivan Mahonin |
4958c9 |
if (l && l->soundsCount && !mute)
|
|
Ivan Mahonin |
beb95c |
soundPlay( l->sounds[ randomNumber(0, l->soundsCount-1) ], FALSE );
|
|
Ivan Mahonin |
beb95c |
|
|
Ivan Mahonin |
396d7d |
Track t = findTrack(selected, hover);
|
|
Ivan Mahonin |
396d7d |
if (t.len) {
|
|
Ivan Mahonin |
396d7d |
t.tm = 1;
|
|
Ivan Mahonin |
396d7d |
Cell *ca = &board[selected.r][selected.c];
|
|
Ivan Mahonin |
396d7d |
Cell *cb = &board[hover.r][hover.c];
|
|
Ivan Mahonin |
396d7d |
ca->l = cb->l = NULL;
|
|
Ivan Mahonin |
396d7d |
ca->tm = cb->tm = t.tm;
|
|
Ivan Mahonin |
396d7d |
tracks[tracksCount++] = t;
|
|
Ivan Mahonin |
7362e0 |
}
|
|
Ivan Mahonin |
cf0aba |
|
|
Ivan Mahonin |
cf0aba |
if (hover.r == selected.r && hover.c == selected.c)
|
|
Ivan Mahonin |
cf0aba |
selected.r = selected.c = -1;
|
|
Ivan Mahonin |
cf0aba |
else
|
|
Ivan Mahonin |
4958c9 |
if ( !(hover.r < 0 && hover.c < 0) // ignore hint, sound or exit pressing
|
|
Ivan Mahonin |
4958c9 |
&& !(hover.r >= ROWS && hover.c >= COLS)
|
|
Ivan Mahonin |
4958c9 |
&& !(hover.r < 0 && hover.c >= COLS) )
|
|
Ivan Mahonin |
beb95c |
selected = hover;
|
|
Ivan Mahonin |
4958c9 |
|
|
Ivan Mahonin |
4958c9 |
if (hover.r < 0 && hover.c >= COLS) mute = !mute;
|
|
Ivan Mahonin |
7362e0 |
}
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
396d7d |
Letter *hl = mouseDown("right") ? get(hover) : NULL;
|
|
Ivan Mahonin |
cf0aba |
if (keyWentDown("h") || (!hl && mouseWentDown("right")))
|
|
Ivan Mahonin |
cf0aba |
hint();
|
|
Ivan Mahonin |
cf0aba |
if (hover.r >= ROWS && hover.c >= COLS) {
|
|
Ivan Mahonin |
cf0aba |
hl = mouseDown("left") ? get(selected) : NULL;
|
|
Ivan Mahonin |
cf0aba |
if (!hl && mouseWentDown("left")) hint();
|
|
Ivan Mahonin |
cf0aba |
}
|
|
Ivan Mahonin |
396d7d |
|
|
Ivan Mahonin |
396d7d |
// draw letters
|
|
Ivan Mahonin |
396d7d |
for(int r = 0; r < ROWS; ++r)
|
|
Ivan Mahonin |
396d7d |
for(int c = 0; c < COLS; ++c) {
|
|
Ivan Mahonin |
396d7d |
Cell *cell = &board[r][c];
|
|
Ivan Mahonin |
396d7d |
if (!cell->g) continue;
|
|
Ivan Mahonin |
396d7d |
|
|
Ivan Mahonin |
396d7d |
double a = 1;
|
|
Ivan Mahonin |
396d7d |
if (cell->tm) {
|
|
Ivan Mahonin |
396d7d |
cell->tm -= dt/RMTIME;
|
|
Ivan Mahonin |
396d7d |
if (cell->tm <= 0) {
|
|
Ivan Mahonin |
396d7d |
cell->g = NULL;
|
|
Ivan Mahonin |
396d7d |
cell->tm = 0;
|
|
Ivan Mahonin |
396d7d |
continue;
|
|
Ivan Mahonin |
396d7d |
}
|
|
Ivan Mahonin |
396d7d |
a = cell->tm;
|
|
Ivan Mahonin |
396d7d |
}
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
396d7d |
saveState();
|
|
Ivan Mahonin |
396d7d |
noStroke();
|
|
Ivan Mahonin |
396d7d |
fill(colorByRGBA(1.0, 1.0, 1.0, a));
|
|
Ivan Mahonin |
396d7d |
if (a == 1 && hl && hl == cell->l ) fill(colorByRGBA(0.9, 0.9, 0.9, a));
|
|
Ivan Mahonin |
396d7d |
if (a == 1 && c == hover.c && r == hover.r) fill(colorByRGBA(0.9, 0.9, 0.9, a));
|
|
Ivan Mahonin |
396d7d |
if (a == 1 && c == selected.c && r == selected.r) fill(colorByRGBA(0.8, 0.8, 0.8, a));
|
|
Ivan Mahonin |
396d7d |
rectTextured(cell->g, c*cellWidth, r*cellHeight, cellWidth, cellHeight);
|
|
Ivan Mahonin |
396d7d |
restoreState();
|
|
Ivan Mahonin |
396d7d |
}
|
|
Ivan Mahonin |
396d7d |
|
|
Ivan Mahonin |
396d7d |
// draw tracks
|
|
Ivan Mahonin |
396d7d |
int j = 0;
|
|
Ivan Mahonin |
396d7d |
for(int i = 0; i < tracksCount; ++i) {
|
|
Ivan Mahonin |
396d7d |
Track *t = &tracks[i];
|
|
Ivan Mahonin |
396d7d |
t->tm -= dt/RMTIME;
|
|
Ivan Mahonin |
396d7d |
if (t->tm <= 0) { j = i + 1; continue; }
|
|
Ivan Mahonin |
396d7d |
saveState();
|
|
Ivan Mahonin |
396d7d |
stroke(colorByRGBA(1, 0, 0, t->tm));
|
|
Ivan Mahonin |
396d7d |
for(int k = 0; k < t->len; ++k)
|
|
Ivan Mahonin |
396d7d |
lineTo((t->p[k].c + 0.5)*cellWidth, (t->p[k].r + 0.5)*cellHeight);
|
|
Ivan Mahonin |
396d7d |
strokePath();
|
|
Ivan Mahonin |
396d7d |
restoreState();
|
|
Ivan Mahonin |
396d7d |
}
|
|
Ivan Mahonin |
396d7d |
tracksCount -= j;
|
|
Ivan Mahonin |
396d7d |
memmove(tracks, tracks + j, sizeof(*tracks)*tracksCount);
|
|
Ivan Mahonin |
cf0aba |
|
|
Ivan Mahonin |
cf0aba |
// draw exiting
|
|
Ivan Mahonin |
cf0aba |
noFill();
|
|
Ivan Mahonin |
cf0aba |
stroke(colorByRGBA(1, 0, 0, exitTm));
|
|
Ivan Mahonin |
cf0aba |
double r = cellHeight/2;
|
|
Ivan Mahonin |
cf0aba |
arc(mx - r, my - r, 2*r, 2*r, 0, 360*exitTm);
|
|
Ivan Mahonin |
7362e0 |
}
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
restoreState();
|
|
Ivan Mahonin |
7362e0 |
}
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
int main() {
|
|
Ivan Mahonin |
7362e0 |
windowSetResizable(TRUE);
|
|
Ivan Mahonin |
7362e0 |
windowSetVariableFrameRate();
|
|
Ivan Mahonin |
7362e0 |
windowSetInit(&init);
|
|
Ivan Mahonin |
7362e0 |
windowSetDraw(&draw);
|
|
Ivan Mahonin |
7362e0 |
windowRun();
|
|
Ivan Mahonin |
7362e0 |
}
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
|
|
Ivan Mahonin |
7362e0 |
|