summaryrefslogtreecommitdiff
path: root/spout.c
diff options
context:
space:
mode:
Diffstat (limited to 'spout.c')
-rw-r--r--spout.c819
1 files changed, 819 insertions, 0 deletions
diff --git a/spout.c b/spout.c
new file mode 100644
index 0000000..cd04f38
--- /dev/null
+++ b/spout.c
@@ -0,0 +1,819 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "piece.h"
+
+#include "sintable.h"
+
+#define FRAMERATE 50
+#define MAX_GRAIN 500
+
+const unsigned char MATSUMI[] = {
+// 80, 77, 66, 80, 180, 0, 0, 0, 1, 0, 128, 0, 10, 0, 223, 119,
+// 160, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 34, 56, 68, 10, 4,
+ 80, 129, 202, 0, 0, 0, 0, 0, 8, 0, 8, 34, 73, 255, 127, 223,
+ 241, 241, 95, 0, 0, 0, 0, 0, 8, 0, 0, 71, 72, 254, 10, 5,
+ 67, 17, 68, 0, 1, 2, 59, 187, 137, 75, 136, 66, 164, 16, 81, 31,
+ 84, 225, 155, 0, 2, 25, 10, 168, 138, 74, 72, 135, 33, 255, 49, 5,
+ 97, 177, 78, 0, 2, 33, 58, 171, 142, 74, 72, 134, 32, 16, 23, 215,
+ 86, 77, 117, 0, 2, 33, 34, 170, 9, 74, 73, 2, 73, 255, 49, 21,
+ 176, 33, 78, 0, 1, 26, 59, 187, 137, 50, 73, 2, 76, 40, 81, 28,
+ 0, 193, 181, 0, 0, 0, 0, 0, 0, 0, 0, 2, 245, 199, 23, 211,
+ 240, 33, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0
+};
+
+typedef struct {
+ short x, y;
+} SVECTOR;
+
+typedef struct {
+ long x, y;
+} VECTOR;
+
+typedef struct tagGRAIN {
+ struct tagGRAIN *next;
+ struct tagGRAIN *prev;
+
+ SVECTOR s, v;
+ short pos;
+ unsigned char color;
+} GRAIN;
+
+GRAIN *grainUseLink, *grainFreeLink;
+
+unsigned char vbuff[128 * 88];
+unsigned char vbuff2[128 * 128];
+
+GRAIN grain[MAX_GRAIN];
+GRAIN *v2g[128 * 128];
+
+SVECTOR box;
+
+VECTOR mPos, mSpeed;
+int mR;
+
+int nGrain;
+
+int time = FRAMERATE * 60, score = 0, height = 0, dispscore = 0;
+int hiScore[2] = {0, 0};
+int dispPos, upperLine, rollCount;
+
+void spout(int t, int x, int y);
+void sweep(unsigned char c1, unsigned char c2);
+void initGrain(void);
+GRAIN *allocGrain(void);
+GRAIN *freeGrain(GRAIN *current);
+
+void pceAppInit(void)
+{
+ pceLCDDispStop();
+ pceLCDSetBuffer(vbuff);
+ pceAppSetProcPeriod(1000 / FRAMERATE);
+
+ memset(vbuff, 0, 128 * 88);
+
+ pceLCDDispStart();
+
+ pceCPUSetSpeed(CPU_SPEED_NORMAL);
+
+ {
+ FILEACC fa;
+ if(!pceFileOpen(&fa, "spout.sco", FOMD_RD)) {
+ pceFileReadSct(&fa, (void *)hiScore, 0, 8);
+ pceFileClose(&fa);
+ }
+ }
+
+ pcePadSetTrigMode(PP_MODE_SINGLE);
+
+ srand(pceTimerGetCount());
+}
+
+void pceAppProc(int cnt)
+{
+ static int gamePhase = 0, gameover;
+
+ int pad = pcePadGet();
+
+ if( (pad & (PAD_C | TRG_D)) == (PAD_C | TRG_D) ||
+ (pad & (TRG_C | PAD_D)) == (TRG_C | PAD_D)) {
+ if(gamePhase >= 2) {
+ gamePhase = 0;
+ } else {
+ pceAppReqExit(0);
+ }
+ pad = 0;
+ }
+
+ if(gamePhase == 4) {
+ if(pad & (TRG_C)) {
+ gamePhase = 3;
+ }
+ return;
+ }
+
+ if(!(gamePhase & 1)) {
+ if(gamePhase == 0) {
+ if(score > hiScore[0] || (score == hiScore[0] && height > hiScore[1])) {
+ FILEACC fa;
+ hiScore[0] = score;
+ hiScore[1] = height;
+ if(!pceFileOpen(&fa, "spout.sco", FOMD_WR)) {
+ pceFileWriteSct(&fa, (void *)hiScore, 0, 8);
+ } else if(!pceFileCreate("spout.sco", 8)) {
+ if(!pceFileOpen(&fa, "spout.sco", FOMD_WR)) {
+ pceFileWriteSct(&fa, (void *)hiScore, 0, 8);
+ }
+ }
+ pceFileClose(&fa);
+ }
+ } else {
+ score = 0;
+ dispscore = 0;
+ height = - 58;
+ time = 60 * FRAMERATE;
+ }
+
+ {
+ int i;
+ for(i = 0; i < 128 * 128; i ++) {
+ v2g[i] = NULL;
+ }
+ initGrain();
+ nGrain = 0;
+ }
+
+ if(gamePhase & 2) {
+ memset(vbuff2, 0xd2, 128 * 128);
+ memset(vbuff2 + 128 * 0, 0, 128 * 78);
+ memset(vbuff2 + 128 * (128 - 32), 0, 128 * 32);
+ } else {
+ memset(vbuff2, 0, 128 * 128);
+ }
+
+ memset(vbuff, 0, 128 * 88);
+
+ {
+ int i;
+ unsigned char *pC;
+
+ pC = vbuff2;
+ for(i = 0; i < 128; i ++) {
+ *pC++ = 0x0b;
+ *pC++ = 0x0b;
+ *pC++ = 0x0b;
+ *pC++ = 0x0b;
+ pC += 128 - 8;
+ *pC++ = 0x0b;
+ *pC++ = 0x0b;
+ *pC++ = 0x0b;
+ *pC++ = 0x0b;
+ }
+ }
+
+ mPos.x = 40 * 256;
+ mPos.y = 0 * 256;
+ mSpeed.x = 0;
+ mSpeed.y = 0;
+ mR = 256 + (gamePhase & 2) * 224;
+
+ dispPos = 0;
+ upperLine = 0;
+ gameover = 0;
+ rollCount = 0;
+ gamePhase ++;
+
+ memset(vbuff + 128, 0x03, 128);
+ pceFontSetType(2 + 128);
+ pceFontSetPos(0, 82);
+ if(height > 0) {
+ pceFontPrintf("time:%2d height:%4d score:%6d", (time + FRAMERATE - 1) / FRAMERATE, height % 10000, score % 1000000);
+ } else {
+ pceFontPrintf("time:%2d height: 0 score:%6d", (time + FRAMERATE - 1) / FRAMERATE, score % 1000000);
+ }
+ pceFontSetType(0);
+ }
+
+ if((pad & TRG_C) && gamePhase == 3 && gameover == 0) {
+ pceFontSetType(2 + 128);
+ pceFontSetPos(64 - 7 * 4 / 2, 33);
+ pceFontPrintf(" pause ");
+ pceFontSetType(0);
+
+ gamePhase = 4;
+
+ pceLCDTrans();
+ return;
+ }
+
+ if(gamePhase & 2) {
+ if(gameover == 0) {
+ if((pad & PAD_RI)) {
+ mR = (mR - 16) & 1023;
+ } else if((pad & PAD_LF)) {
+ mR = (mR + 16) & 1023;
+ }
+ if((pad & (PAD_A | PAD_B))) {
+ mSpeed.x -= sintable[(256 + mR) & 1023] / 128;
+ mSpeed.y += sintable[mR] / 128;
+ }
+ mSpeed.y += 8;
+
+ if(mSpeed.x < -256 * 4) {
+ mSpeed.x = -256 * 4;
+ } else if(mSpeed.x > 256 * 4) {
+ mSpeed.x = 256 * 4;
+ }
+ if(mSpeed.y < -256 * 4) {
+ mSpeed.y = -256 * 4;
+ } else if(mSpeed.y > 256 * 4) {
+ mSpeed.y = 256 * 4;
+ }
+
+ mPos.x += mSpeed.x / 16;
+ mPos.y += mSpeed.y / 16;
+
+ if(mPos.x >= 125 * 256) {
+ mPos.x = 124 * 256;
+ gameover = 1;
+ } else if(mPos.x <= 2 * 256) {
+ mPos.x = 3 * 256;
+ gameover = 1;
+ }
+ if(mPos.y >= 78 * 256) {
+ mPos.y = 77 * 256;
+ gameover = 1;
+ }
+
+ if(mPos.y < 40 * 256) {
+ unsigned char *pC;
+ int i, j, w, x1 , x2;
+ mPos.y += 256;
+ upperLine = (upperLine - 1) & 127;
+ height ++;
+
+ if(height > 0) {
+ score ++;
+ if((height & 127) == 0) {
+ score += (time + FRAMERATE - 1) / FRAMERATE * 10;
+ time += 60 * FRAMERATE;
+ if(time > 99 * FRAMERATE) {
+ time = 99 * FRAMERATE;
+ }
+ pceFontSetType(2 + 128);
+ pceFontSetPos(4 * 5, 82);
+ pceFontPrintf("%2d", (time + FRAMERATE - 1) / FRAMERATE);
+ pceFontSetType(0);
+ }
+ pceFontSetType(2 + 128);
+ pceFontSetPos(4 * 15, 82);
+ pceFontPrintf("%4d", height % 10000);
+ pceFontSetType(0);
+ }
+
+ if(upperLine == 111 && height > 0) {
+ unsigned long *pL;
+ pL = (unsigned long *)(vbuff2 + 128 * 108 + 4);
+ while(pL < (unsigned long *)(vbuff2 + 128 * 109 - 4)) {
+ *pL++ = 0;
+ }
+ pL += 2;
+ while(pL < (unsigned long *)(vbuff2 + 128 * 110 - 4)) {
+ *pL++ = 0xd3d3d3d3;
+ }
+ pL += 2;
+ while(pL < (unsigned long *)(vbuff2 + 128 * 111 - 4)) {
+ *pL++ = 0;
+ }
+ }
+
+ box.x = 20 - (height + 40) / 64;
+ if(box.x < 4) {
+ box.x = 4;
+ }
+ box.y = 20 - (height + 40) / 64;
+ if(box.y < 4) {
+ box.y = 4;
+ }
+
+ for(j = 0; j < 1; j ++) {
+ int x, y;
+ x = 4 + (rand() % box.x);
+ y = 4 + (rand() % box.y);
+ pC = vbuff2 + ((upperLine - 20 - (rand() & 7)) & 127) * 128;
+ x1 = 4 + (rand() % (120 - x));
+ x2 = x;
+ i = y;
+ while(i > 0) {
+ if(pC < vbuff2) {
+ pC += 128 * 128;
+ }
+ pC += x1;
+ w = x2;
+ while(w > 0) {
+ *pC++ = 0;
+ w --;
+ }
+ pC -= x1 + x2 + 128;
+ i --;
+ }
+ }
+
+ sweep(0x13, 0xd2);
+ }
+ }
+ } else {
+ mPos.x = 7 * 256;
+ mPos.y = 60 * 256;
+ mR = 0;
+
+ if((rollCount & 7) == 0) {
+ int i, j;
+
+ if((upperLine & 31) == 0) {
+ unsigned long *pL;
+ pceLCDSetBuffer(vbuff2 + ((upperLine - 24) & 127) * 128);
+ pceFontSetBkColor(0);
+
+ switch(upperLine / 32) {
+ case 0:
+ pL = (unsigned long *)(vbuff2 + 12 + ((upperLine - 24) & 127) * 128);
+ for(i = 0; i < 16; i ++) {
+ for(j = 0; j < 26 / 2; j ++) {
+ *pL = 0x91919191;
+ pL += 2;
+ }
+ if((i & 7) == 3) {
+ pL += 7;
+ } else if((i & 7) == 7) {
+ pL += 5;
+ } else {
+ pL += 6;
+ }
+ }
+
+ pceFontSetTxColor(0x03);
+ pceFontSetType(1 + 128);
+ pceFontSetPos(64 - 4 * 5, 0);
+ pceFontPrintf("spout");
+ break;
+
+ case 2:
+ pceFontSetTxColor(0xc3);
+ pceFontSetType(2 + 128);
+ pceFontSetPos(118 - 20 * 4, 0);
+ pceFontPrintf(" height: %8d", hiScore[1] % 1000000);
+ pceFontSetPos(118 - 20 * 4, 6);
+ pceFontPrintf("high-score: %8d", hiScore[0] % 1000000);
+ break;
+
+ case 1:
+ {
+ const unsigned char *pS = MATSUMI;
+ unsigned char *pD = vbuff2 + ((upperLine - 16) & 127) * 128;
+ for(i = 0; i < 128 / 8 * 10; i ++) {
+ unsigned char t = *pS++;
+ for(j = 0; j < 8; j ++) {
+ if(t & 0x80) {
+ *pD = 0xc3;
+ }
+ pD ++;
+ t <<= 1;
+ }
+ }
+ }
+ break;
+ }
+
+ pceFontSetType(0);
+ pceFontSetTxColor(0x03);
+ pceFontSetBkColor(0);
+
+ pceLCDSetBuffer(vbuff);
+ }
+ upperLine = (upperLine - 1) & 127;
+
+ sweep(0x13, 0x00);
+ }
+ }
+
+ rollCount ++;
+
+ {
+ static int gx[] = {-2, 2, -1, 1, 0};
+ int r, t;
+
+ r = rand() & 3;
+ t = gx[r]; gx[r] = gx[r + 1]; gx[r + 1] = t;
+ if(gamePhase & 2) {
+ if(gameover == 0 && (pad & (PAD_A | PAD_B))) {
+ int i, t, x, y;
+ for(i = 0; i < 5; i ++) {
+ t = mPos.x / 256 + gx[i] + ((mPos.y / 256 - 1 + abs(gx[i]) + dispPos) & 127) * 128;
+ x = mSpeed.x / 16 + sintable[(256 + mR) & 1023] / 8;
+ y = mSpeed.y / 16 - sintable[mR] / 8;
+ spout(t, x, y);
+ }
+ }
+ } else {
+ int i, t;
+ for(i = -1; i <= 2; i ++) {
+ t = 7 + i + ((60 - 1 + dispPos) & 127) * 128;
+ spout(t, 512, -384);
+ }
+ }
+ }
+
+ {
+ GRAIN *pG, *pG2;
+ SVECTOR svt;
+
+ pG = grainUseLink;
+ while(pG) {
+ int f = 0;
+ unsigned char *c;
+
+ pG->v.y += 8;
+
+ pG->s.x += pG->v.x;
+ pG->s.y += pG->v.y;
+
+ *(vbuff2 + pG->pos) = 0;
+ *(v2g + pG->pos) = NULL;
+
+ if(pG->s.y >= 256) {
+ do {
+ pG->s.y -= 256;
+ pG->pos = (pG->pos + 128) & 16383;
+ c = (vbuff2 + pG->pos);
+
+ if(*c) {
+ if(*c & 0x04) {
+ int r;
+ pG2 = *(v2g + pG->pos);
+ r = 31 - (rand() & 63);
+ svt = pG->v;
+ pG->v = pG2->v;
+ pG2->v = svt;
+ pG->v.x += r;
+ pG2->v.x -= r;
+ } else {
+ pG->v.y = -pG->v.y / 2;
+ pG->v.x += 15 - (rand() & 31);
+ if(*c & 0xc0) {
+ *c -= 0x40;
+ if(!(*c & 0xc0)) {
+ *c = 0;
+ }
+ }
+ if(pG->color & 0xc0) {
+ pG->color -= 0x40;
+ } else {
+ pG->color = 0;
+ f = 1;
+ }
+ }
+ pG->pos = (pG->pos - 128) & 16383;
+ break;
+ }
+ } while(pG->s.y >= 256);
+ } else {
+ while(pG->s.y <= -256) {
+ pG->s.y += 256;
+ pG->pos = (pG->pos - 128) & 16383;
+ c = (vbuff2 + pG->pos);
+
+ if(*c) {
+ if(*c & 4) {
+ pG2 = *(v2g + pG->pos);
+ svt = pG->v;
+ pG->v = pG2->v;
+ pG2->v = svt;
+ } else {
+ pG->v.y = -pG->v.y / 2;
+ if(*c & 0xc0) {
+ *c -= 0x40;
+ if(!(*c & 0xc0)) {
+ *c = 0;
+ }
+ }
+ if(pG->color & 0xc0) {
+ pG->color -= 0x40;
+ } else {
+ pG->color = 0;
+ f = 1;
+ }
+ }
+ pG->pos = (pG->pos + 128) & 16383;
+ break;
+ }
+ }
+ }
+
+ if(pG->s.x >= 256) {
+ do {
+ pG->s.x -= 256;
+ pG->pos = (pG->pos + 1) & 16383;
+ c = (vbuff2 + pG->pos);
+
+ if(*c) {
+ if(*c & 4) {
+ pG2 = *(v2g + pG->pos);
+ svt = pG->v;
+ pG->v = pG2->v;
+ pG2->v = svt;
+ } else {
+ pG->v.x = -pG->v.x / 2;
+ if(*c & 0xc0) {
+ *c -= 0x40;
+ if(!(*c & 0xc0)) {
+ *c = 0;
+ }
+ }
+ if(pG->color & 0xc0) {
+ pG->color -= 0x40;
+ } else {
+ pG->color = 0;
+ f = 1;
+ }
+ }
+ pG->pos = (pG->pos - 1) & 16383;
+ break;
+ }
+ } while(pG->s.x >= 256);
+ } else {
+ while(pG->s.x <= -256) {
+ pG->s.x += 256;
+ pG->pos = (pG->pos - 1) & 16383;
+ c = (vbuff2 + pG->pos);
+
+ if(*c) {
+ if(*c & 4) {
+ pG2 = *(v2g + pG->pos);
+ svt = pG->v;
+ pG->v = pG2->v;
+ pG2->v = svt;
+ } else {
+ pG->v.x = -pG->v.x / 2;
+ if(*c & 0xc0) {
+ *c -= 0x40;
+ if(!(*c & 0xc0)) {
+ *c = 0;
+ }
+ }
+ if(pG->color & 0xc0) {
+ pG->color -= 0x40;
+ } else {
+ pG->color = 0;
+ f = 1;
+ }
+ }
+ pG->pos = (pG->pos + 1) & 16383;
+ break;
+ }
+ }
+ }
+
+ if(f) {
+ *(vbuff2 + pG->pos) = pG->color;
+ nGrain --;
+ *(v2g + pG->pos) = NULL;
+ pG = freeGrain(pG);
+ } else {
+ *(vbuff2 + pG->pos) = pG->color;
+ *(v2g + pG->pos) = pG;
+ pG = pG->next;
+ }
+ }
+ }
+
+ dispPos = upperLine;
+
+ {
+ unsigned long *pL, *pL2, *pLe;
+ pL = (unsigned long *)(vbuff + 2 * 128);
+ pL2 = (unsigned long *)(vbuff2 + dispPos * 128);
+
+ pLe = pL2 + 128 * 78 / 4;
+ if(pLe > (unsigned long *)(vbuff2 + 128 * 128)) {
+ pLe = (unsigned long *)(vbuff2 + 128 * 128);
+ }
+
+ while(pL2 < pLe) {
+ *pL = *pL2 & 0x03030303;
+ pL ++;
+ pL2 ++;
+ }
+
+ pL2 = (unsigned long *)(vbuff2);
+ while(pL < (unsigned long *)(vbuff + 128 * (78 + 2))) {
+ *pL = *pL2 & 0x03030303;
+ pL ++;
+ pL2 ++;
+ }
+ }
+
+ {
+ unsigned char *pC;
+ pC = vbuff2 + mPos.x / 256 + ((mPos.y / 256 + dispPos) & 127) * 128;
+ if(*pC != 0 && (*pC & 4) == 0) {
+ gameover = *pC;
+ }
+ }
+
+ {
+ static int gPhase = 0;
+ unsigned char *pC;
+ int i, x, y;
+ if(gameover == 0 && (gamePhase & 2)) {
+ x = mPos.x + sintable[(256 + mR) & 1023] * gPhase / 64;
+ y = mPos.y - sintable[mR] * gPhase / 64;
+ for(i = 0; i < 3; i ++) {
+ if(y >= 78 * 256) {
+ break;
+ }
+ *(vbuff + x / 256 + (y / 256 + 2) * 128) = 3;
+ x += sintable[(256 + mR) & 1023] / 16;
+ y -= sintable[mR] / 16;
+
+ if(y >= 78 * 256) {
+ break;
+ }
+ *(vbuff + x / 256 + (y / 256 + 2) * 128) = 3;
+ x += sintable[(256 + mR) & 1023] / 16;
+ y -= sintable[mR] / 16;
+
+ if(y >= 78 * 256) {
+ break;
+ }
+ *(vbuff + x / 256 + (y / 256 + 2) * 128) = 3;
+ x += sintable[(256 + mR) & 1023] * 2 / 16;
+ y -= sintable[mR] * 2 / 16;
+ }
+ gPhase = (gPhase + 1) & 15;
+ }
+
+ pC = vbuff + mPos.x / 256 + (mPos.y / 256 + 2) * 128;
+ *(pC - 129) = 0x03;
+ *(pC - 128) = 0x03;
+ *(pC - 127) = 0x03;
+ *(pC - 1) = 0x03;
+ *pC = 0x00;
+ *(pC + 1) = 0x03;
+ *(pC + 127) = 0x03;
+ *(pC + 128) = 0x03;
+ *(pC + 129) = 0x03;
+ }
+
+ if(gamePhase == 1) {
+ if(pad & (TRG_A | TRG_B)) {
+ gamePhase = 2;
+ }
+ } else if(gameover) {
+ if(pad & (TRG_A | TRG_B)) {
+ gamePhase = 0;
+ }
+ }
+
+ if((gamePhase & 2) && time && gameover == 0) {
+ time --;
+ if((time % FRAMERATE) == 0) {
+ pceFontSetType(2 + 128);
+ pceFontSetPos(4 * 5, 82);
+ pceFontPrintf("%2d", (time + FRAMERATE - 1) / FRAMERATE);
+ pceFontSetType(0);
+ }
+ if(time == 0) {
+ gameover = 1;
+ }
+ }
+
+ if(dispscore < score) {
+ dispscore ++;
+ if(dispscore < score) {
+ dispscore ++;
+ }
+ pceFontSetType(2 + 128);
+ pceFontSetPos(4 * 26, 82);
+ pceFontPrintf("%6d", dispscore % 1000000);
+ pceFontSetType(0);
+ }
+
+ if(gamePhase == 3 && gameover != 0) {
+ pceFontSetType(2 + 128);
+ pceFontSetPos(64 - 11 * 4 / 2, 33);
+ pceFontPrintf(" game over ");
+ pceFontSetType(0);
+ }
+
+ pceLCDTrans();
+}
+
+
+void pceAppExit( void )
+{
+ pceCPUSetSpeed(CPU_SPEED_NORMAL);
+}
+
+void spout(int t, int x, int y)
+{
+ if(*(vbuff2 + t) == 0) {
+ if(nGrain < MAX_GRAIN) {
+ GRAIN *pG = allocGrain();
+
+ pG->v.x = x;
+ pG->v.y = y;
+ pG->s.x = 0;
+ pG->s.y = 0;
+
+ pG->color = (2 + (rand() & 1)) + 4 + 64 * 3;
+
+ pG->pos = t;
+ *(vbuff2 + t) = pG->color;
+ v2g[t] = pG;
+ nGrain ++;
+ }
+ }
+}
+
+void sweep(unsigned char c1, unsigned char c2)
+{
+ int i;
+
+ unsigned char *pC = vbuff2 + 4 + 128 * ((upperLine + 77) & 127);
+ for(i = 0; i < 120; i ++) {
+ if(*pC & 4) {
+ GRAIN **ppG;
+ ppG = v2g + (int)(pC - vbuff2);
+ freeGrain(*ppG);
+ *ppG = NULL;
+ nGrain --;
+ }
+ *pC++ = c1;
+ }
+
+ pC += 8;
+ if(pC >= vbuff2 + 128 * 128) {
+ pC -= 128 * 128;
+ }
+
+ for(i = 0; i < 120; i ++) {
+ *pC++ = c2;
+ }
+}
+
+void initGrain(void)
+{
+ int i;
+
+ for(i = 0; i < MAX_GRAIN - 1; i ++) {
+ grain[i].next = &grain[i + 1];
+ }
+ grain[i].next = NULL;
+
+ grainFreeLink = grain;
+ grainUseLink = NULL;
+
+ return;
+}
+
+GRAIN *allocGrain(void)
+{
+ GRAIN *current = grainFreeLink;
+
+ if(current) {
+ grainFreeLink = current->next;
+
+ current->next = grainUseLink;
+ current->prev = NULL;
+ if(current->next) {
+ current->next->prev = current;
+ }
+ grainUseLink = current;
+ }
+
+ return current;
+}
+
+GRAIN *freeGrain(GRAIN *current)
+{
+ GRAIN *next = current->next;
+
+ if(next) {
+ next->prev = current->prev;
+ }
+ if(current->prev) {
+ current->prev->next = next;
+ } else {
+ grainUseLink = next;
+ }
+
+ current->next = grainFreeLink;
+ grainFreeLink = current;
+
+ return next;
+}
+