and here is the code if anybody wants to try it. it should work on all operating systems. Meanwhile I'll be looking for a place to host the compiled program.
#include <ctime>
#include <math.h>
#include <cstdlib>
#include <ctype.h>
#include <curses.h>
#include <iostream>
using namespace std;
/***************************/
#define legal(yyy,xxx) ((yyy>=0 && yyy<Y && xxx>=0 && xxx<X))
#define superlegal(yyy,xxx) ((yyy>0 && yyy<(Y-1) && xxx>0 && xxx<(X-1)))
#define alljelly(f) for( jelly *temp=jellyhead; temp!=NULL; temp=temp->next){f}
#define allkobolds(f) for(kobold* ktemp=koboldhead; ktemp!=NULL; ktemp=ktemp->next){f}
#define blocking 1
#define fence 2
#define trap 4
const int Y=23; //height of world
const int X=39; //width of world
class jelly
{
public:
int y;
int x;
int hp;
int hpmin;
int hpmax;
bool moved;
void split();
void move();
jelly* remove();
void eat();
jelly(int a, int b);
jelly *next;
jelly *samesquare;
};
jelly* JELLYMAP[Y][X];
jelly::jelly(int a, int b) //default constructor
{
y=a;
x=b;
hp=32;
hpmin=12;
hpmax=32;
moved=false;
next=NULL;
samesquare=NULL;
samesquare = JELLYMAP[y][x];
JELLYMAP[y][x]=this;
}
jelly* jellyhead;
class kobold
{
public:
int y;
int x;
void move();
int hp;
kobold* next;
kobold* remove();
kobold();
};
kobold* koboldhead=NULL;
kobold::kobold()
{
y=1;
x=X/2;
hp=10;
}
char VIEW[Y][X];
int COLOR[Y][X];
bool EXP[Y][X]; //explosion
int FOOD[Y][X];
int PATH[Y][X];
int MAP[Y][X];
int BOTTLES=0;
int cursorY=Y/2;
int cursorX=X/2;
char inchar;
int quit=0;
bool instructions=0;
/***************************/
void print();
void printinstructions();
void init();
void move();
void input();
bool overlap(int yy, int xx);
int sign(int i);
void maze(int z,int walltype);
bool shove(int y,int x, int yy, int xx);
bool subtract(jelly* temp);
bool moveto(int y, int x, jelly* temp);
void bottle();
char* convert(int number, char* strng);
int tilejellycount(int y, int x);
void explosion(int y, int x);
int countjelly();
void endgame();
bool hitkobold(int y, int x, int damage);
void insertkobold();
int foodcount();
/***************************/
int main()
{
int yy,xx;
init();
printinstructions();
while(!quit) //press q to quit
{
input();
if(instructions==0)
{
insertkobold();
move();
bottle();
yy=rand()%Y;
xx=rand()%X;
if(VIEW[yy][xx]==' ' && foodcount()<100)
FOOD[yy][xx]++;
}
print();
}
refresh();
echo(); // turn echoing back on before exiting
endwin(); // end curses control of the window
}
/***************************/
void init()
{
initscr();
srand(time(NULL)); // initializes the random number generator
clear(); // clear the window
noecho(); // don't show typed characters on the screen
start_color();
init_pair(0, COLOR_WHITE, COLOR_BLACK);
init_pair(1, COLOR_BLUE, COLOR_BLACK); //using default colors to make "color pairs"
init_pair(2, COLOR_RED, COLOR_BLACK);
init_pair(3, COLOR_GREEN, COLOR_BLACK);
init_pair(4, COLOR_YELLOW, COLOR_BLACK);
init_pair(5, COLOR_WHITE, COLOR_RED);
for(int y=0; y<Y; y++)
{
for(int x=0; x<X; x++)
{
VIEW[y][x]=' ';
MAP[y][x]=0;
EXP[y][x]=0;
JELLYMAP[y][x]=NULL;
if(y==0 || x==0 || y==Y-1 || x==X-1)
MAP[y][x]=1;
FOOD[y][x]=0;
COLOR[y][x]=0;
}
}
MAP[Y-1][X/2]=0;
MAP[0][X/2]=0;
maze(200,1);
maze(800,2);
jellyhead= new jelly(Y-2,X-2);
}
/***************************/
void print()
{
for(int y=0; y<Y; y++)
for(int x=0; x<X; x++)
{
VIEW[y][x]=' '; //clears view
if(MAP[y][x] & blocking)
VIEW[y][x]='#';
else if(MAP[y][x] & trap)
VIEW[y][x]='^';
if(MAP[y][x]==2)
{
VIEW[y][x]='+';
COLOR[y][x]=4;
}
if(FOOD[y][x]>0 && VIEW[y][x]==' ')
{
VIEW[y][x]='\"';
COLOR[y][x]=3;
}
if(tilejellycount(y,x) >= 2)
{
VIEW[y][x]='8';
COLOR[y][x]=1;
}
else if(tilejellycount(y,x)==1)
{
if(JELLYMAP[y][x]->hp > 16)
VIEW[y][x]='O';
else if(JELLYMAP[y][x]->hp > 4)
VIEW[y][x]='o';
else if(JELLYMAP[y][x]->hp > 0)
VIEW[y][x]='.';
COLOR[y][x]=1;
}
if(EXP[y][x])
{
COLOR[y][x]=5;
VIEW[y][x]='*';
EXP[y][x]=0;
}
}
for(kobold* ktemp=koboldhead; ktemp!=NULL; ktemp=ktemp->next)
{
VIEW[ktemp->y][ktemp->x]='k';
COLOR[ktemp->y][ktemp->x]=2;
}
VIEW[cursorY][cursorX]='@';
COLOR[cursorY][cursorX]=2;
VIEW[Y-1][X/2]='%'; //jelly bottleing plant
clear();
if(!instructions)
{
for(int y=0; y<Y; y++)
for(int x=0; x<X; x++)
{
attrset(COLOR_PAIR(COLOR[y][x]));
mvaddch(y, x*2, VIEW[y][x]);
mvaddch(y, x*2+1,' ');
COLOR[y][x]=0;
}
//prints bottles of jelly you have in the factory
char strng[]={" Bottles of jelly: "};
for(int i=0; strng[i]!='\0'; i++)
mvaddch(Y, i, strng[i]);
COLOR[Y-1][X/2]=1; //jelly bottleing plant color
char* strgntemp=convert(BOTTLES/5, strng);
*strgntemp='\0';
for(int i=0; strng[i]!='\0'; i++)
mvaddch(Y, i+20, strng[i]);
if(!countjelly())
endgame();
}
else if(instructions)
printinstructions();
refresh(); // refresh the screen
}
/***************************/
char* convert(int number, char* strng) //what this does is converts an integer into a string
{
if(number>9)
strng=convert(number/10, strng);
number=number%10;
strng[0]=char(number+'0');
return &strng[1];
}
/***************************/
void endgame() //this whole function is very ugly
{ //what is does is puts the endgame message in the middle of the screen
//and then wait for a keypress to exit the game.
char strng[]={" Bottles of jelly on the wall "};
char strng2[]={" "};
for(int i=0; strng2[i]!='\0'; i++)
{
mvaddch(Y/2-2, i+X-15, strng2[i]);
mvaddch(Y/2-1, i+X-15, strng2[i]);
mvaddch(Y/2, i+X-15, strng[i]);
mvaddch(Y/2+1, i+X-15, strng2[i]);
}
char* strgntemp=convert(BOTTLES/5, strng);
*strgntemp='\0'; //terminates the number with a '\0'
int count=0;
for(int i=0; strng[i]!='\0'; i++)
count++;
for(int i=0; strng[i]!='\0'; i++)
mvaddch(Y/2-1, i+X-count/2, strng[i]);
getch();
quit=1;
}
/***************************/
void printinstructions()
{
attrset(COLOR_PAIR(0));
char display[][60]=
{" ",
"Your uncle bought tickets for a vacation to Cancun and ",
"left you in charge of his jelly farm until he gets back. ",
"He is trusting you to keep the \"Old-Fasionsed Genuine- ",
"Imitation Potion-Flavored-Beverage\" bottling plant supplied",
"with jellies so they stay stocked with that smooth flavor ",
"everybody loves. ",
" ",
"Protect the jellies from hungry kobolds and help them find ",
"the food they need to multiply. ",
"To bottle the jellies herd them down into the intake ",
"you gain more bottles for fatter jellies ",
"When you place a trap it uses up one bottle of beverage ",
"When the jellies are gone your score is bottles in stock ",
" ",
"wasd keys to move ",
"spacebar to place or remove jelly-proof fences ",
"t places or removes kobold traps ",
"q quits the game ",
"? to bring back up the instructions ",
" ",
" ",
" <press space to start the game> ",
" "};
for(int y=0; y<Y; y++)
{
for(int x=0; x<59; x++)
{
mvaddch(y, x+X-30, display[y][x]);
}
}
}
/***************************/
void input()
{
int oldy=cursorY;
int oldx=cursorX;
inchar = getch();
if(inchar != ERR)
{
if(instructions==0)
{
if(inchar=='w')
cursorY=cursorY-1;
else if(inchar=='s')
cursorY=cursorY+1;
else if(inchar=='a')
cursorX=cursorX-1;
else if(inchar=='d')
cursorX=cursorX+1;
else if(inchar=='q' || inchar=='Q')
quit=1;
else if(inchar=='?')
instructions=1;
else if(inchar==' ')
MAP[cursorY][cursorX]^=fence;
else if(inchar=='t')
{
if(BOTTLES>=5 && !(MAP[cursorY][cursorX] & trap))
{
MAP[cursorY][cursorX] |= trap; //add trap
BOTTLES-=5;
}
else
MAP[cursorY][cursorX] &= ~trap; //remove trap
}
if((MAP[cursorY][cursorX] & blocking) || hitkobold(cursorY,cursorX,5)) //check to see if your are blocked
{
cursorY=oldy;
cursorX=oldx;
}
if(!superlegal(cursorY,1))
cursorY=oldy;
if(!superlegal(1,cursorX))
cursorX=oldx;
if(!shove(cursorY-oldy, cursorX-oldx, cursorY, cursorX))
{
for(jelly* temp=JELLYMAP[cursorY][cursorX]; temp!=NULL; temp=temp->samesquare)
{ //switch places with the jelly
moveto(oldy,oldx,temp);
}
}
}
else
{
if(inchar==' ')
instructions=0;
}
}
}
/***************************/
void move()
{
for(kobold* ktemp=koboldhead; ktemp!=NULL;) //kobolds move
{
if(ktemp->hp < 1)
{
ktemp = ktemp->remove();
continue;
}
ktemp->move();
ktemp=ktemp->next;
}
for( jelly *temp=jellyhead; temp!=NULL;) //jellies move
{
if(temp->hp < 1)
{
temp = temp->remove();
continue;
}
if(temp->hp > temp->hpmax)
temp->split();
if(temp->moved==false)
temp->move();
temp->moved=false;
temp->eat();
temp=temp->next;
}
}
/***************************/
bool overlap(int y, int x)
{
bool answer=false;
for(jelly* temp=JELLYMAP[y][x]; temp!=NULL; temp=temp->samesquare)
{
temp->split();
answer=true;
}
return answer;
}
/***************************/
jelly* jelly::remove()
{
if(jellyhead==NULL)
return NULL;
subtract(this);
if(this==jellyhead)
{
jellyhead=next;
delete this;
return jellyhead;
}
jelly* current=jellyhead;
while(current->next != this)
{
current=current->next;
}
current->next= next;
delete this;
return current->next;
}
/***************************/
void maze(int z,int walltype)
{
int y,x,temp,newy,newx;
int test;
for(int i=0; i<z; i++)
{
do
{
y=rand()%(Y/2)*2;
x=rand()%(X/2)*2;
}while(MAP[y][x]==0);
test=1;
while(test)
{
do
{
newy=y;
newx=x;
temp=((rand()%2)*4)-2;
if(rand()%2)
newy=y+temp;
else
newx=x+temp;
}while( !legal(newy,newx) );
if(MAP[newy][newx]!=0)
test=0;
else
{
MAP[(newy+y)/2][(newx+x)/2]=walltype;
MAP[newy][newx]=walltype;
y=newy;
x=newx;
}
}
}
}
/***************************/
bool shove(int deltay,int deltax, int oldY, int oldX)
{
int newY,newX,best,count;
int choice[6][2];
jelly* temp=JELLYMAP[oldY][oldX];
jelly* temp2;
while(temp!=NULL)
{
best=0;
count=-1;
for(int i=-1; i<=1; i++)
{
for(int j=-1; j<=1; j++)
{
newY = oldY+i;
newX = oldX+j;
if(legal(newY, newX) && MAP[newY][newX]==0 && ( i || j ))
{
if((i*deltay + j*deltax) > best)
{
count=0;
choice[count][0]=newY;
choice[count][1]=newX;
best = (i*deltay + j*deltax);
}
else if((i*deltay + j*deltax)==best)
{
count++;
choice[count][0]=newY;
choice[count][1]=newX;
}
}
}
}
if(count==-1)
return 0;
int r=rand()%(count+1);
temp2=temp->samesquare; // so that we keep pointing at the same aquare instead of moveing with the jelly
moveto(choice[r][0],choice[r][1],temp);
temp=temp2;
}
return 1;
}
/***************************/
bool subtract(jelly* temp)
{
if(temp==NULL)
return 0;
else if(JELLYMAP[temp->y][temp->x]==NULL)
return 1;
else if(temp==JELLYMAP[temp->y][temp->x])
{
JELLYMAP[temp->y][temp->x] = JELLYMAP[temp->y][temp->x]->samesquare;
return 1;
}
else
{
for(jelly* current=JELLYMAP[temp->y][temp->x]; current!=NULL; current=current->samesquare)
{
if(current->samesquare == temp)
{
current->samesquare=temp->samesquare;
}
}
}
return 1;
}
/***************************/
bool moveto(int y, int x, jelly* temp)
{
if(legal(y,x) && MAP[y][x]==0)
{
if(!subtract(temp))
return false;
temp->y=y;
temp->x=x;
temp->samesquare = JELLYMAP[y][x];
JELLYMAP[y][x]=temp;
temp->moved=true;
return true;
}
return false;
}
/***************************/
void kobold::move()
{
int oldY = y;
int oldX = x;
int best = X+Y;
int test;
int targetY = oldY+rand()%3-1;
int targetX = oldX+rand()%3-1;
for( jelly *temp=jellyhead; temp!=NULL; temp=temp->next)
{
test = fabs(temp->y-y) + fabs(temp->x-x);
if(test < best)
{
best=test;
targetY=temp->y;
targetX=temp->x;
}
}
y = oldY + sign(targetY - y);
x = oldX + sign(targetX - x);
if(MAP[y][x] & blocking)
{
y = oldY+rand()%3-1;
x = oldX+rand()%3-1;
}
if( overlap(y,x) || (y==cursorY && x==cursorX) || !(superlegal(y,x)) || (MAP[y][x] & blocking))
{
y=oldY;
x=oldX;
}
if(MAP[y][x] & trap)
explosion(y, x);
}
/***************************/
kobold* kobold::remove()
{
if(koboldhead==NULL)
return NULL;
if(this==koboldhead)
{
koboldhead = next;
delete this;
return koboldhead;
}
kobold* current=koboldhead;
while(current->next != this)
{
current=current->next;
}
current->next = this->next;
delete this;
return current->next;
}
/***************************/
int sign(int i)
{
if(i==0)
return 0;
if(i<0)
return -1;
if(i>0)
return 1;
}
/***************************/
void jelly::move()
{
int ry=y;
int rx=x;
ry += rand()%3-1;
rx += rand()%3-1;
if(!(ry==cursorY && rx==cursorX) && superlegal(y,x))
moveto(ry,rx,this);
}
/***************************/
void jelly::split()
{
if(hp > hpmin)
{
jelly* baby=new jelly(y,x);
hpmin += rand()%3-1;
hpmax += rand()%3-1;
hp /= 2;
*baby = *this;
baby->next = this->next;
this->next = baby;
}
else
hp--;
}
/***************************/
void jelly::eat()
{
if(FOOD[y][x]>0)
{
hp+=5;
FOOD[y][x]--;
}
}
/***************************/
int tilejellycount(int y, int x)
{
int count=0;
for(jelly* temp= JELLYMAP[y][x]; temp!=NULL; temp=temp->samesquare)
count++;
return count;
}
/***************************/
void bottle()
{
jelly* temp=JELLYMAP[Y-1][X/2];
jelly* temp2;
while(temp!=NULL)
{
temp2=temp;
temp=temp->samesquare;
BOTTLES += temp2->hp;
temp2->remove();
COLOR[Y-1][X/2]=5; //turn the mechanism white and red for a turn so that they know they bottled a jelly
}
}
/***************************/
void explosion(int y, int x)
{
for(int i=-1; i<=1; i++)
{
for(int j=-1; j<=1; j++)
{
shove(i,j,y,x);
EXP[y+i][x+j]=1;
hitkobold(y+1,x+j,5);
if(superlegal(y+i,x+j))
MAP[y+i][x+j] = MAP[y+i][x+j] & trap; //erases everything but traps
}
}
MAP[y][x]=0;
hitkobold(y,x,15);
}
/***************************/
int countjelly()
{
int count=0;
alljelly(count++;)
return count;
}
/***************************/
bool hitkobold(int y, int x, int damage)
{
bool hit=false;
allkobolds
(
if(ktemp->y==y && ktemp->x==x)
{
ktemp->hp-=damage;
hit=true;
}
)
return hit;
}
/***************************/
void insertkobold()
{
if(rand()%150==0)
{
kobold* ktemp=new kobold;
ktemp->next=koboldhead;
koboldhead=ktemp;
}
}
/***************************/
int foodcount()
{
int count=0;
for(int y=0; y<Y; y++)
{
for(int x=0; x<X; x++)
{
count+=FOOD[y][x];
}
}
return count;
}
/***************************/