/* Derived from scene.c in the The OpenGL Programming Guide */ /* Keyboard and mouse rotation taken from Swiftless Tutorials #23 Part 2 */ /* http://www.swiftless.com/tutorials/opengl/camera2.html */ /* Frames per second code taken from : */ /* http://www.lighthouse3d.com/opengl/glut/index.php?fps */ #include #include #include #include #include #include "graphics.h" /* mob controls */ extern void createMob(int, float, float, float, float); extern void setMobPosition(int, float, float, float, float); extern void getMobPosition(int, float*, float*, float*, float*, float*, float*); extern int isMobVisible(int); extern void hideMob(int); extern void showMob(int); extern void mobTrajectory(int, float, float); /* viewpoint control */ extern void setViewPosition(float, float, float); extern void getViewPosition(float *, float *, float *); extern void getOldViewPosition(float *, float *, float *); extern void setViewOrientation(float, float, float); extern void getViewOrientation(float *, float *, float *); void startLevel(); void endLevel(); typedef enum colour { empty, green, blue, red, black, white, purple, orange, yellow } colour; typedef struct enemy { int id; int size; int x; int y; int z; int dest_x; int dest_z; colour*** form; char type; colour col; } enemy; colour map[WORLDX][WORLDZ] = {{empty}}; colour key[11][3] = {{empty}}; colour message[4][78] = {{empty}}; int dropBox[3] = {0}; int dest[2] = {0}; enemy* enemies = NULL; int n_enemies = 0; int hasKey = 0; int dropParty = 0; int bouncing = 0; int shot = 0; int level = 0; int wall_moving = 0; int ind = 0; typedef struct wall_chunk { int x; int z; int dir; colour col; } wall_chunk; void quit() { endLevel(); printf("You made it to level %d.\n", level); exit(0); } enemy* getEnemy(int x, int y, int z) { for(int n=0; ndest_z = mob->z; mob->dest_x = mob->x; if(cell == 0 && mob->x < (WORLDX -16) -mob->size) { mob->dest_x = mob->x + 16; } else if(cell == 1 && mob->x > 16 +mob->size) { mob->dest_x = mob->x - 16; } else if(cell == 2 && mob->z < (WORLDZ -16) -mob->size) { mob->dest_z = mob->z + 16; } else if(cell == 3 && mob->z > 16 +mob->size) { mob->dest_z = mob->z - 16; } } enemy initEnemy(char type, int size, int x, int z, int temp, int dir) { static int id = 1; enemy ret; if((type != 'x' && type != 'o') || size < 0 || x < 0 || z < 0) { id = 1; } ret.id = id; ret.size = size; ret.x = x; ret.y = (size/2)+1; ret.z = z; ret.type = type; if(type == 'o') { ret.col = yellow; } else if(type == 'x') { ret.col = orange; } ret.form = malloc(sizeof(colour**)*size); for(int i=0; itype, mob->size, mob->x, mob->z, 1, 1); int off = mob->size/2; for(int i=0; isize; i++) { for(int j=0; jsize; j++) { for(int k=0; ksize; k++) { if(world[i+(mob->x)-off][j+(mob->y)-off][k+(mob->z)-off] == empty) { world[i+(mob->x)-off][j+(mob->y)-off][k+(mob->z)-off] = mob->form[i][j][k]; } if(map[i+(mob->x)-off][k+(mob->z)-off] == empty) { map[i+(mob->x)-off][k+(mob->z)-off] = mob->form[i][off][k]; } } } } for(int i=0; isize; i++) { for(int j=0; jsize; j++) { for(int k=0; ksize; k++) { temp.form[i][j][k] = mob->form[k][i][j]; } } } colour*** swap = mob->form; mob->form = temp.form; temp.form = swap; destroyEnemy(temp); } void behaveEnemy(enemy* mob, int random) { float x, y, z, rotx, roty, rotz, yrot; int see = 1; getViewPosition(&x, &y, &z); getViewOrientation(&rotx, &roty, &rotz); if(mob->x != mob->dest_x) { int off = 0; if(mob->dest_x > mob->x) { off = 1; } else { off = -1; } for(int i=0; isize; i++) { for(int j=0; jsize; j++) { if(world[mob->x+((mob->size-i)*off)][mob->y][mob->z+j-1] != empty) { randDestCell(mob, random); return; } } } } if(mob->z != mob->dest_z) { int off = 0; if(mob->dest_z > mob->z) { off = 1; } else { off = -1; } for(int i=0; isize; i++) { for(int j=0; jsize; j++) { if(world[mob->x+j-1][mob->y][mob->z+((mob->size-i)*off)] != empty) { randDestCell(mob, random); return; } } } } if(mob->dest_x == mob->x && mob->dest_z == mob->z) { randDestCell(mob, random); } else if(mob->x < mob->dest_x) { mob->x = mob->x+1; } else if(mob->x > mob->dest_x) { mob->x = mob->x-1; } if(mob->z < mob->dest_z) { mob->z = mob->z+1; } else if(mob->z > mob->dest_z) { mob->z = mob->z-1; } x = fabs(x); z = fabs(z); int zdir = 1; int xdir = 1; if(mob->z > z) { zdir = -1; } if(mob->x > x) { xdir = -1; } for(int i=0; ix-x); i++) { for(int j=0; jy-y); j++) { for(int k=0; kz-z); k++) { if(world[mob->x+i*xdir][mob->y+j][mob->z+k*zdir] != empty) { see = 0; break; } } if(!see) { break; } } if(!see) { break; } } float xrot, zrot; float mobx, moby, mobz, mobroty, mobrotx, mobrotz; int xoff=0, zoff=0; int origin = 0; float opp, adj, mult = 1.0; if(mob->x>x) { xoff = -1*mob->size; } else if(mob->xsize; } if(mob->z>z) { zoff = -1*mob->size; } else if(mob->zsize; } if(x > mob->x && z < mob->z) { origin = 90; opp = mob->z+zoff-z; adj = mob->x+xoff-x; } else if(z > mob->z && x > mob->x) { origin = 180; opp = mob->x+xoff-x; adj = mob->z+zoff-z; } else if(z > mob->z && x < mob->x) { origin = 270; opp = mob->z+zoff-z; adj = mob->x+xoff-x; mult = -1.0; } else if(z < mob->z && x < mob->x) { origin = 360; opp = mob->x+xoff-x; adj = mob->z+zoff-z; } else { return; } yrot = (float)origin-degree(atan(opp/adj))*mult; if(origin == 90) { yrot = 90-(yrot-90); } xrot = 0.0; zrot = 0.0; if(see && !isMobVisible(mob->id)) { getMobPosition(mob->id, &mobx, &moby, &mobz, &mobroty, &mobrotx, &mobrotz); createMob(mob->id, mob->x+xoff, mob->y, mob->z+zoff, yrot); mobTrajectory(mob->id, xrot, zrot); showMob(mob->id); } if(roty < 90-yrot+45 && roty > 90-yrot-45) { switch(origin) { case 90: mob->dest_x = mob->x-random; mob->dest_z = mob->z+random; break; case 180: mob->dest_x = mob->x-random; mob->dest_z = mob->z-random; break; case 270: mob->dest_x = mob->x+random; mob->dest_z = mob->z-random; break; case 360: mob->dest_x = mob->x+random; mob->dest_z = mob->z+random; break; default: break; } } } void teleEnemy(enemy* mob) { int dropOff = 0; int newx, newz; while(!dropOff) { newx = rand()%WORLDX; newz = rand()%WORLDZ; int occupied = 0; for(int x=newx; xx = newx; mob->z = newz; } GLfloat* rgb(colour col) { static GLfloat val[4] = {0.0, 0.0, 0.0, 1.0}; for(int i=0; i<3; i++) { val[i] = 0.0; } val[3] = 1.0; switch(col) { case red: val[0] = 1.0; break; case blue: val[2] = 1.0; break; case purple: val[2] = 1.0; val[0] = 1.0; break; case yellow: val[1] = 1.0; val[0] = 1.0; break; case white: val[0] = 1.0; val[1] = 1.0; val[2] = 1.0; break; case green: val[1] = 1.0; break; case orange: val[0] = 1.0; val[1] = 0.3; break; case black: val[0] = 0.8; val[3] = 0.4; case empty: default: break; } return val; } /* mouse function called by GLUT when a button is pressed or released */ void mouse(int, int, int, int); extern int getMapState(); /* initialize graphics library */ extern void graphicsInit(int *, char **); /* lighting control */ extern void setLightPosition(GLfloat, GLfloat, GLfloat); extern GLfloat* getLightPosition(); /* add cube to display list so it will be drawn */ extern int addDisplayList(int, int, int); /* player controls */ extern void createPlayer(int, float, float, float, float); extern void setPlayerPosition(int, float, float, float, float); extern void hidePlayer(int); extern void showPlayer(int); /* 2D drawing functions */ extern void draw2Dline(int, int, int, int, int); extern void draw2Dbox(int, int, int, int); extern void draw2Dtriangle(int, int, int, int, int, int); extern void set2Dcolour(float []); /* flag which is set to 1 when flying behaviour is desired */ extern int flycontrol; /* flag used to indicate that the test world should be used */ extern int testWorld; /* flag to print out frames per second */ extern int fps; /* flag to indicate the space bar has been pressed */ extern int space; /* flag indicates the program is a client when set = 1 */ extern int netClient; /* flag indicates the program is a server when set = 1 */ extern int netServer; /* size of the window in pixels */ extern int screenWidth, screenHeight; /* flag indicates if map is to be printed */ extern int displayMap; /* frustum corner coordinates, used for visibility determination */ extern float corners[4][3]; /* determine which cubes are visible e.g. in view frustum */ extern void ExtractFrustum(); extern void tree(float, float, float, float, float, float, int); /********* end of extern variable declarations **************/ void getDest(int* x, int* z) { int destX, destZ; int found = 0; while(!found) { destX = (rand()%(WORLDX-6))+3; destZ = (rand()%(WORLDZ-6))+3; for(int i=destX-1; i=0 && i=0 && j 0) { if(world[abs((int)(x+0.25))][abs((int)(y-1))][abs((int)z)] == 0) { newy = oldy-1; if(powerUp(col)) { world[abs((int)(x+0.25))][abs((int)y)][abs((int)z)] = empty; map[abs((int)(x+0.25))][abs((int)z)] = empty; } else { newy = oldy-1; } } else { if(col == white && world[abs((int)(x+0.25))][abs((int)(y-1))][abs((int)z)] == white && hasKey) { printf("Congratulations, you've cleared level %d!\n", level); endLevel(); startLevel(); return; } newx = oldx; } } } else if(dirx == 'w') { col = world[abs((int)(x-0.25))][abs((int)y)][abs((int)z)]; if(col > 0) { if(world[abs((int)(x-0.25))][abs((int)(y-1))][abs((int)z)] == 0) { if(powerUp(col)) { world[abs((int)(x-0.25))][abs((int)y)][abs((int)z)] = empty; map[abs((int)(x-0.25))][abs((int)z)] = empty; } else { newy = oldy-1; } } else { if(col == white && world[abs((int)(x-0.25))][abs((int)(y-1))][abs((int)z)] == white && hasKey) { printf("Congratulations, you've cleared level %d!\n", level); endLevel(); startLevel(); return; } newx = oldx; } } } if(dirz == 'n') { col = world[abs((int)x)][abs((int)y)][abs((int)(z+0.25))]; if(col > 0) { if(world[abs((int)x)][abs((int)(y-1))][abs((int)(z+0.25))] == 0) { if(powerUp(col)) { world[abs((int)x)][abs((int)y)][abs((int)(z+0.25))] = empty; map[abs((int)x)][abs((int)(z+0.25))] = empty; } else { newy = oldy-1; } } else { if(col == white && world[abs((int)x)][abs((int)(y-1))][abs((int)(z+0.25))] == white && hasKey) { printf("Congratulations, you've cleared level %d!\n", level); endLevel(); startLevel(); return; } newz = oldz; } } } else if(dirz == 's') { col = world[abs((int)x)][abs((int)y)][abs((int)(z-0.25))]; if(col > 0) { if(world[abs((int)x)][abs((int)(y-1))][abs((int)(z-0.25))] == 0) { if(powerUp(col)) { world[abs((int)x)][abs((int)y)][abs((int)(z-0.25))] = empty; map[abs((int)x)][abs((int)(z-0.25))] = empty; } else { newy = oldy-1; } } else { if(col == white && world[abs((int)x)][abs((int)(y-1))][abs((int)(z-0.25))] == white && hasKey) { printf("Congratulations, you've cleared level %d!\n", level); endLevel(); startLevel(); return; } newz = oldz; } } } if(fabs(newx) >= WORLDX) { newx = -1.0*(WORLDX-1); } else if(newx > 0) { newx = 0; } if(fabs(newz) >= WORLDZ) { newz = -1.0*(WORLDZ-1); } else if(newz > 0) { newz = 0; } setViewPosition(newx, newy, newz); mapx = abs((int)newx); mapy = abs((int)newz); for(i=mapx-1; i=0 && i=0 && j screenWidth) { smallestRes = screenWidth; } else { smallestRes = screenHeight; } mapInflation = (int)((float)smallestRes/(float)WORLDZ); xdis = (screenWidth-(WORLDX*mapInflation))/2; ydis = (screenHeight-(WORLDZ*mapInflation))/2; for(i=0; i 0.05) { int destX = dest[0], destZ = dest[1]; float xRatio = 0.0, zRatio = 0.0; int xdir = 1, zdir = 1; if((int)fabs(x) < destX) { xRatio = (destX-fabs(x))/10.0; } else if((int)fabs(x) > destX) { xRatio = (fabs(x)-destX)/10.0; xdir = -1; } if((int)fabs(z) < destZ) { zRatio = (destZ-fabs(z))/10.0; } else if((int)fabs(z) > destZ) { zRatio = (fabs(z)-destZ)/10.0; zdir = -1; } if(xRatio < 1 && zRatio < 1) { bouncing = 0; } for(i=(int)fabs(x)-1; i<(int)fabs(x)+2; i++) { for(j=(int)fabs(z)-1; j<(int)fabs(z)+2; j++) { if(map[i][j] == white) { map[i][j] = empty; } } } for(i=(int)fabs(x-(xRatio*xdir))-1; i<(int)fabs(x-(xRatio*xdir))+2; i++) { for(j=(int)fabs(z-(zRatio*zdir))-1; j<(int)fabs(z-(zRatio*zdir))+2; j++) { if(!map[i][j]) { map[i][j] = white; } } } float yoff = sqrt(((xRatio*10)*(xRatio*10))+((zRatio*10)*(zRatio*10))); setViewPosition(x-(xRatio*xdir), -1*yoff, z-(zRatio*zdir)); getViewPosition(&x, &y, &z); bounce_timer = end; } if((float)(end - projectile_timer) / (float)CLOCKS_PER_SEC > 0.01) { for(i=0; i<=n_enemies; i++) { if(isMobVisible(i)) { float mobx, moby, mobz, mobroty, mobrotx, mobrotz, difx, difz, dify; getMobPosition(i, &mobx, &moby, &mobz, &mobroty, &mobrotx, &mobrotz); while(mobroty >= 360.0) { mobroty -= 360.0; } while(mobrotz >= 360.0) { mobrotz -= 360.0; } while(mobrotx >= 360.0) { mobrotx -= 360.0; } difz = fabs(cos(radian(mobroty))); difx = fabs(sin(radian(mobroty))); dify = fabs(sin(radian(mobrotx))); if(mobrotx > 0 && mobrotx < 180) { dify = -1.0*dify; } if(mobroty > 180 && mobroty <= 270) { difx = -1.0*difx; } else if(mobroty > 270 && mobroty < 360) { difz = -1.0*difz; difx = -1.0*difx; } else if(mobroty >= 0 && mobroty < 90) { difz = -1.0*difz; } if(map[(int)round(mobx)][(int)round(mobz)] == yellow) { map[(int)round(mobx)][(int)round(mobz)] = empty; } if(mobx+difx > WORLDX || mobx+difx < 0 || mobz+difz > WORLDZ || mobz+difz < 0 || moby+dify > WORLDY || moby+dify < 0) { hideMob(i); } else { setMobPosition(i, mobx+difx, moby+dify, mobz+difz, mobroty); switch(world[(int)round(mobx+difx)][(int)round(moby+dify)][(int)round(mobz+difz)]) { case blue: case black: hideMob(i); break; case empty: if(map[(int)round(mobx+difx)][(int)round(mobz+difz)] == empty) { map[(int)round(mobx+difx)][(int)round(mobz+difz)] = yellow; } else if(map[(int)round(mobx+difx)][(int)round(mobz+difz)] == white) { if(round(mobx+difx) == round(fabs(x)) && round(mobz+difz) == round(fabs(z))) { if((moby+dify) < fabs(y)+1.0 && (moby+dify) > fabs(y)-1.0) { printf("You've been shot!\n"); shot = 12; hideMob(i); } } } break; default: if((int)round(mobx+difx) > 3 && (int)round(mobx+difx) < WORLDX-3 && (int)round(mobz+difz) > 3 && (int)round(mobz+difz) < WORLDZ-3 && world[(int)round(mobx+difx)][(int)round(moby+dify)][(int)round(mobz+difz)] != white) { world[(int)round(mobx+difx)][(int)round(moby+dify)][(int)round(mobz+difz)] = empty; map[(int)round(mobx+difx)][(int)round(mobz+difz)] = empty; } hideMob(i); } } } } } if((float)(end - gravity_timer) / (float)CLOCKS_PER_SEC > 0.02 && !bouncing) { if(abs((int)y)-1 >= WORLDY || world[abs((int)x)][abs((int)y)-1][abs((int)z)] == 0) { setViewPosition(x, y+1, z); gravity_timer = end; } if(y>-1.8) { setViewPosition(x, -1.8, z); } } if((float)(end - wall_timer) / (float)CLOCKS_PER_SEC > 5.0) { int w=0; for(w=0; w 0) { chunks[num_chunks] = chunk; num_chunks++; } } } } wall_moving = 1; wall_timer = end; } if(wall_moving && (float)(end - inner_wall) / (float)CLOCKS_PER_SEC > 0.08) { float xpos, ypos, zpos; for(i=0; iz = mob->z - mob->size; } else { mob->z = mob->z + mob->size; } mob->dest_x = mob->x; mob->dest_z = mob->z; } world[(chunks[i].x+15)-ind][k][j] = chunks[i].col; } map[(chunks[i].x+15)-ind][j] = chunks[i].col; } break; case 2: //east for(j=chunks[i].x+1; jx = mob->x - mob->size; } else { mob->x = mob->x + mob->size; } mob->dest_x = mob->x; mob->dest_z = mob->z; } world[j][k][(chunks[i].z+15)-ind] = chunks[i].col; } map[j][(chunks[i].z+15)-ind] = chunks[i].col; } break; case 3: //south for(j=chunks[i].z+1; jz = mob->z - mob->size; } else { mob->z = mob->z + mob->size; } mob->dest_x = mob->x; mob->dest_z = mob->z; } world[(chunks[i].x-1)-ind][k][j] = chunks[i].col; } map[(chunks[i].x-1)-ind][j] = chunks[i].col; } break; case 4: //west for(j=chunks[i].x+1; jx = mob->x - mob->size; } else { mob->x = mob->x + mob->size; } mob->dest_x = mob->x; mob->dest_z = mob->z; } world[j][k][(chunks[i].z-1)-ind] = chunks[i].col; } map[j][(chunks[i].z-1)-ind] = chunks[i].col; } break; } } ind++; if(ind == 12) { ind = 0; wall_moving = 0; num_chunks = 0; } inner_wall = end; } if((float)(end - mob_timer) / (float)CLOCKS_PER_SEC > 0.1) { for(i=0; i 0.1 && dropParty) { if(dropBox[2] > 1) { dropBox[2] = dropBox[2]-1; if(world[dropBox[0]-3][dropBox[2]][dropBox[1]-3] == empty) { colour col = (rand()%3)+1; map[dropBox[0]-3][dropBox[1]-3] = col; world[dropBox[0]-3][dropBox[2]][dropBox[1]-3] = col; world[dropBox[0]-3][dropBox[2]+1][dropBox[1]-3] = empty; } if(world[dropBox[0]+3][dropBox[2]][dropBox[1]-3] == empty) { colour col = (rand()%3)+1; map[dropBox[0]+3][dropBox[1]-3] = col; world[dropBox[0]+3][dropBox[2]][dropBox[1]-3] = col; world[dropBox[0]+3][dropBox[2]+1][dropBox[1]-3] = empty; } if(world[dropBox[0]-3][dropBox[2]][dropBox[1]+3] == empty) { colour col = (rand()%3)+1; map[dropBox[0]-3][dropBox[1]+3] = col; world[dropBox[0]-3][dropBox[2]][dropBox[1]+3] = col; world[dropBox[0]-3][dropBox[2]+1][dropBox[1]+3] = empty; } if(world[dropBox[0]+3][dropBox[2]][dropBox[1]+3] == empty) { colour col = (rand()%3)+1; map[dropBox[0]+3][dropBox[1]+3] = col; world[dropBox[0]+3][dropBox[2]][dropBox[1]+3] = col; world[dropBox[0]+3][dropBox[2]+1][dropBox[1]+3] = empty; } } else { dropParty = 0; } drop_timer = end; } } } /* called by GLUT when a mouse button is pressed or released */ /* -button indicates which button was pressed or released */ /* -state indicates a button down or button up event */ /* -x,y are the screen coordinates when the mouse is pressed or */ /* released */ void mouse(int button, int state, int x, int y) { float xpos, ypos, zpos; float xrot, yrot, zrot; float mobx, moby, mobz, mobroty, mobrotx, mobrotz; getViewPosition(&xpos, &ypos, &zpos); getViewOrientation(&xrot, &yrot, &zrot); getMobPosition(0, &mobx, &moby, &mobz, &mobroty, &mobrotx, &mobrotz); if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) { map[(int)(mobx)][(int)(mobz)] = empty; createMob(0, fabs(xpos), fabs(ypos), fabs(zpos), yrot); mobTrajectory(0, xrot, zrot); showMob(0); } else if (button == GLUT_MIDDLE_BUTTON) { } else { } if (state == GLUT_UP) { } else { } } void startLevel() { int x=0; int h=WORLDY; int l=0, randX, randZ; int i,j,k, keySet = 0; level++; for(x=0; x=z-12; i--) { for(j=x+1; j=x-12; j--) { map[j][i] = purple; for(k=1; k 16 && z > 16) { if(rand() % 3 == 0 && n_enemies < MOB_COUNT-1) { char type = 'x'; int size = 3; if(rand()%2 == 0) { type = 'o'; } n_enemies++; enemies = realloc(enemies, sizeof(enemy)*n_enemies); enemies[n_enemies-1] = initEnemy(type, size, x, z, 0, rand()); for(i=0; i