void cbzone_while(void) { #ifdef WIN32 if (GetAsyncKeyState( VK_F1 ) < 0) { free(o); return; // myexit(scores(score)); //HACK OUT by Eric Fogelin } #endif gettimeofday(&tstart, 0); gprinqcursor((Position_t *)position); event = gprcondeventwait(&key, (Position_t *)position); if (event && key == 'Q') { free(o); return; // myexit(scores(score)); //HACK OUT by Eric Fogelin } if (event && key == 'R') { clearentirescreen(); staticscreen(); updatedisplay(False, False, -1, 0, False, True); updatedisplay(missilerun, lander, score, opt->numleft, sens, False); if (sight_flag) message(1, False); if (pl->attr & IS_BLOCKED) message(2, False); if (salvo_flag) message(3, False); scanner(o); xhairs(aligned); drawhorizon(pl->azm); } joystick(position, sens, pl); if (!paused) { for (i=0; i<opt->msalvos; i++) { /* now find a shot we can use */ s = pl->salvo+i; if (!(s->attr & STILL_THERE)) break; s = NULL; } if (event && pl->attr & IS_ALIVE) if (keylast) { for (i=0; i<opt->msalvos; i++) { /* now find a shot we can use */ s = pl->salvo+i; if (!(s->attr & STILL_THERE)) break; s = NULL; } if (key == 'a' && s!=NULL) { /* fire up one shot */ playsound(opt->loud?sfire:suser_shoots); s->attr = START_LIVING; s->ecount = 0; s->x = pl->x; s->y = pl->y; s->z = 0.0; s->prox = 0; s->proy = 0; s->azm = pl->azm; s->speed = 40.0; keylast = False; } else if (key == 'b') { /* center our joystick */ position[0] = 500; position[1] = 355; gprsetcursorposition((Position_t *)position); joystick(position, sens, pl); keylast = False; } else if (key == 'c') { /* toggle sensitivity */ sens = !sens; joystick(position, sens, pl); keylast = False; } } else if (key == 'A' || key == 'B' || key == 'C') keylast = True; /* button released */ /* if we can move, update our rotation, bearing (azimuth), and */ /* position. */ if (pl->attr & IS_ALIVE && !(pl->attr & IS_BLOCKED)) { pl->azm += pl->rotate; if (pl->azm > PI2) pl->azm -= PI2; if (pl->azm <= 0.0) pl->azm += PI2; pl->ca = cos(pl->azm); pl->sa = sin(pl->azm); } if (pl->attr & IS_ALIVE) { pl->x -= pl->sa * pl->speed; pl->y += pl->ca * pl->speed; } else pl->speed = 0.0; /* now call the move generation routines for the objects */ /* which require thought, speed and/or rotation may be */ /* affected. */ for (g=o+opt->estart; g<o+opt->sstart; g++) if (g->attr & IS_ALIVE) switch (g->type) { case IS_TANK: movetank(g, pl); break; case IS_SUPER: movesuper(g, pl); break; case IS_MISSILE: movemissile(g, pl, first); break; case IS_COPTER: movecopter(g, pl); break; case IS_LANDER: movelander(g, pl); break; default: printf("Help! Something's alive and I don't know what...\n"); #ifdef WIN32 return; #else //X11 myexit(1); #endif } /* now update their bearing and position */ for (g=o+opt->estart; g<o+opt->lstart; g++) { if (g->attr & IS_ALIVE && !(g->attr & IS_BLOCKED)) g->azm += g->rotate; g->ca = cos(g->azm); g->sa = sin(g->azm); g->x -= g->sa * g->speed; g->y += g->ca * g->speed; } for (g=o+opt->lstart; g<o+opt->bstart; g++) if (g->attr & IS_ALIVE) { g->ca = cos(g->azm); g->sa = sin(g->azm); g->x -= g->sa * g->speed; g->y += g->ca * g->speed; } /* now compute ranges from objects to the player */ for (g=o+opt->estart; g<o+opt->mobjects; g++) if (g->attr & STILL_THERE) g->range = sqrt(DIST(g, pl)); for (g=o; g<o+opt->lstart; g++) /* assume all objects are */ g->attr &= ~IS_BLOCKED; /* unblocked */ /* now check to see if they really were unblocked. If not, then */ /* project them back along their path until they are. This */ /* section just checks for being blocked by blocks. */ for (g=o+opt->bstart; g<o+opt->mobjects; g++) { if (g->range < blocksize) { pl->attr |= BLOCKED_BY_BLOCK; dx = pl->x - g->x; dy = pl->y - g->y; diff = dy * pl->ca - dx * pl->sa; if (pl->speed > 0.0) v = diff + sqrt(diff*diff + blocksizesqrd - g->range*g->range); else if (pl->speed < 0.0) v = diff - sqrt(diff*diff + blocksizesqrd - g->range*g->range); pl->x += pl->sa * v; pl->y -= pl->ca * v; } for (g2=o+opt->estart; g2<o+opt->lstart; g2++) if (g2->attr & IS_ALIVE && (dist = DIST(g, g2)) < blocksizesqrd) { g2->attr |= BLOCKED_BY_BLOCK; if (!(g2->type & (IS_MISSILE | IS_COPTER))) { dx = g2->x - g->x; dy = g2->y - g->y; diff = dy * g2->ca - dx * g2->sa; if (g2->speed > 0.0) v = diff + sqrt(diff*diff + blocksizesqrd - dist); else if (g2->speed < 0.0) v = diff - sqrt(diff*diff + blocksizesqrd - dist); g2->x += g2->sa * v; g2->y -= g2->ca * v; } } } /* if the player moved, or if an enemy did, we need to recompute */ /* the range to that enemy. */ for (g=o+opt->estart; g<o+opt->lstart; g++) if (g->attr & IS_ALIVE && (g->attr & IS_BLOCKED || pl->attr & IS_BLOCKED)) g->range = sqrt(DIST(g, pl)); /* now check to see if the player is blocked by any enemy. */ /* if so, project them back. */ for (g=o+opt->estart; g<o+opt->lstart; g++) if (g->attr & IS_ALIVE && g->range < blocksize) if (!(g->type & (IS_MISSILE | IS_COPTER))) { if (g->attr & IS_BLOCKED) { pl->speed = 0.0; if (fabs(g->speed) < 0.001) g->speed = sign(0.001, g->speed); } pl->attr |= BLOCKED_BY_ENEMY; g->attr |= BLOCKED_BY_ENEMY; ddx = pl->speed * pl->sa - g->speed * g->sa; ddy = pl->speed * pl->ca - g->speed * g->ca; ddx2 = ddx*ddx; ddy2 = ddy*ddy; dx = pl->x - g->x; dy = pl->y - g->y; dif = ddy * dy - ddx * dx; alpha = (dif + sqrt(dif*dif + (blocksizesqrd - g->range*g->range) * (ddx2 + ddy2))) / (ddx2 + ddy2); pl->x += alpha * pl->speed * pl->sa; pl->y -= alpha * pl->speed * pl->ca; g->x += alpha * g->speed * g->sa; g->y -= alpha * g->speed * g->ca; } /* if we've moved, recompute distance to all the salvos */ if (pl->attr & IS_BLOCKED) for (g=o+opt->sstart; g<o+opt->bstart; g++) if (g->attr & IS_ALIVE) g->range = sqrt(DIST(g, pl)); /* enemies disappear if their range is greater than 2200. */ /* We check last[0] to see if they need to be erased. In */ /* most cases probably not, unless we really screw with */ /* their speed. */ tank_stranded = False; for (g=o+opt->estart; g<o+opt->lstart; g++) { g->ecount++; if (g->attr & IS_ALIVE) if (g->range > 2200.0) if (g->dc[0].last) g->attr = ERASE; else g->attr = 0; else if (g->type & (IS_SUPER | IS_TANK) && g->ecount > TANK_STRAND_COUNT) tank_stranded = True; } /* landers are out of range at 2750 */ for (g=o+opt->lstart; g<o+opt->sstart; g++) { g->ecount++; if (g->attr & IS_ALIVE && g->range > 2750.0) if (g->dc[0].last) g->attr = ERASE; else g->attr = 0; } /* blocks also at 2200 */ for (g=o+opt->bstart; g<o+opt->mobjects; g++) if (g->range > 2200.0) if (g->dc[0].last) g->attr = ERASE; else g->attr = 0; /* salvos are never out of range, but their lifetime is limited */ for (g=o+opt->sstart; g<o+opt->bstart; g++) { g->ecount++; if (g->attr & IS_ALIVE && g->ecount > 50) if (g->dc[0].last) g->attr = ERASE; else g->attr = 0; } /* we never set the 'salvo fired' message in this routine. */ /* however, we do have to turn it off. if salvos are alive */ /* we assume the message is on, once no enemy salvos are */ /* alive we turn it off. */ new_salvo_flag = False; for (g=o+opt->sstart; g<o+opt->bstart; g++) if (g->attr & IS_ALIVE) { /* if salvo exist and */ if (g->salvo != pl) /* not owned by player */ new_salvo_flag = True; /* then the flag is set */ /* check to see if a salvo hits a block */ for (g2=o+opt->bstart; g2<o+opt->mobjects; g2++) if (fabs(g2->x - g->x) < g2->criticalx && fabs(g2->y - g->y) < g2->criticaly) { g->attr = START_EXPLODING; g->ecount = 0; } /* now check to see if the salvo kills a lander. */ /* If so, and the player fired the salvo, update */ /* the score. */ for (g2=o+opt->lstart; g2<o+opt->sstart; g2++) if (g2->attr & IS_ALIVE) if (DIST(g, g2) < g2->criticalx) { g->attr = START_EXPLODING; g2->attr = START_EXPLODING; g->ecount = 0; g2->ecount = 0; if (g->salvo == pl) { score += 10000; icheck = score / 100000; if (icheck > scorebase) { opt->numleft++; if (opt->numleft > 4) opt->numleft = 4; scorebase = icheck; } } } /* now check to see if the salvo hit any enemy. The salvo */ /* cannot hit the one who fired it. This prevents range */ /* checking problems when first fired. */ for (g2=o+opt->estart; g2<o+opt->lstart; g2++) if (g2->attr & IS_ALIVE && g->salvo != g2) { dx = g->x - g2->x; dy = g->y - g2->y; testx = fabs( dx * g2->ca + dy * g2->sa); testy = fabs(-dx * g2->sa + dy * g2->ca); if (testx < g2->criticalx && testy < g2->criticaly && (!(g2->type & (IS_MISSILE | IS_COPTER)) || g2->z < 80.0)) { g->attr = START_EXPLODING; g2->attr = START_EXPLODING; g->ecount = 0; g2->ecount = 0; /* if the player fired, give him credit */ if (g->salvo == pl) { if (g2->type & IS_SUPER) score += 5000; else if (g2->type & (IS_MISSILE | IS_COPTER)) { score += 5000; nummissile--; } else score += 3000; icheck = score / 100000; if (icheck > scorebase) { opt->numleft++; if (opt->numleft > 4) opt->numleft = 4; scorebase = icheck; } } } } } /* check to see if a missile or copter rams a lander */ for (g=o+opt->estart; g<o+opt->lstart; g++) if (g->type & (IS_MISSILE | IS_COPTER) && g->attr & IS_ALIVE) for (g2=o+opt->lstart; g2<o+opt->sstart; g2++) if (g2->attr & IS_ALIVE && DIST(g, g2) < g2->criticalx && g->z < 80) { nummissile--; g->attr = START_EXPLODING; g2->attr = START_EXPLODING; g->ecount = 0; g2->ecount = 0; } /* now check if we need to draw the object. */ /* convert into player-centric coordinates */ /* and project a cone forward to see if the */ /* enemy is within it. Also align the gun */ /* gun sights if necessary. */ new_sight_flag = False; aligned = False; lander = False; for (g=o+opt->estart; g<o+opt->mobjects; g++) if (g->attr & (IS_ALIVE|IS_EXPLODING)) { g->dc[0].seen = False; if (g->range < 2000.0) { dx = g->x - pl->x; dy = g->y - pl->y; g->proy = -dx * pl->sa + dy * pl->ca; g->prox = dx * pl->ca + dy * pl->sa; check = g->proy / (fabs(g->prox) + 1.0); if (check > threshold) { g->dc[0].seen = True; if (g->type & IS_ENEMY && g->attr & IS_ALIVE) new_sight_flag = True; if (fabs(g->prox) < 50 && g->attr & IS_ALIVE && !(g->type & (IS_ABLOCK | IS_SALVO))) aligned = True; } if (g->type & IS_LANDER && g->attr & IS_ALIVE && check > landerthreshold) { lander = True; if (fabs(g->prox) < 60) aligned = True; } } } /* change the various messages, if necessary. Never use */ /* the bell, unless opt->loud is True. */ if (sight_flag && !new_sight_flag) { message(-1, False); sight_flag = False; } else if (!sight_flag && new_sight_flag) { message(1, False); sight_flag = True; playsound(senemy_seen); } if (pl->attr & IS_BLOCKED && !blocked_flag) { message(2, True); blocked_flag = True; playsound(smove_blocked); } else if (!(pl->attr & IS_BLOCKED) && blocked_flag) { message(-2, False); blocked_flag = False; } if (salvo_flag && !new_salvo_flag) { message(-3, False); salvo_flag = False; } else if (!salvo_flag && new_salvo_flag) { salvo_flag = True; playsound(ssalvo_fired); } scanner(o); updatedisplay(missilerun, lander, score, opt->numleft, sens, False); xhairs(aligned); drawhorizon(pl->azm); /* now draw all the objects */ for (g=o+opt->estart; g<o+opt->mobjects; g++) { if (g->attr & (IS_ALIVE | ERASE)) drawobject(g, pl); else if (g->attr & (IS_EXPLODING | EXERASE)) switch (g->type) { case IS_SALVO: explodesalvo(g, pl); break; case IS_COPTER: case IS_MISSILE: case IS_LANDER: case IS_TANK: case IS_SUPER: if (g->ecount == 1) playsound(opt->loud?skill:sobject_explodes); explodeobject(g, pl); break; default: printf("Help! Cannot explode what doesn't exist.\n"); #ifdef WIN32 return; #else //X11 myexit(1); #endif } g->attr &= ~(ERASE | EXERASE); } /* now start checking for player death. if there is a missile, */ /* check to see if it rammed the player. */ if (missilerun) for (g=o+opt->estart; g<o+opt->lstart; g++) if (g->attr & IS_ALIVE && g->type & (IS_MISSILE | IS_COPTER) && g->range < blocksize && g->z < 80) { g->attr = START_EXPLODING; drawcracks(); pl->attr &= ~IS_ALIVE; dead = True; deadcount = 0; } /* check to see if any salvos hit. */ for (g=o+opt->sstart; g<o+opt->bstart; g++) if (g->attr & IS_ALIVE && g->salvo != pl && g->range < 100.0 && fabs(g->prox) < pl->criticalx && fabs(g->proy) < pl->criticaly) { drawobject(g, pl); g->attr = 0; drawcracks(); pl->attr &= ~IS_ALIVE; dead = True; deadcount = 0; } /* if we are dead, redraw the cracks every five turns. after 50 */ /* turns, we can start playing again if we have any lives left. */ if (dead) { if (deadcount == 0) playsound(opt->loud?suser_died:sobject_explodes); if (deadcount%5 == 0) drawcracks(); if (deadcount > 50) { dead = False; if (!opt->training && (--opt->numleft < 0)) { #ifdef DEVELOPER gettimeofday(&game_end, 0); if (opt->output) printf("The game took an average %10.8f secs.\n", (game_end.tv_sec-game_start.tv_sec + (game_end.tv_usec-game_start.tv_usec)*1.0e-6)/passes); #endif //DEVELOPER free(o); #ifdef WIN32 return; #else //X11 myexit(scores(score)); #endif } if (missilerun) { nummissile -= 2; if (nummissile <= 0 && opt->mtanks) { missilerun = False; nextmissile = 750 * frand() + 750; } } clearscreen(); pl->x = 0.0; /* reset all our attributes */ pl->y = 0.0; pl->speed = 0.0; pl->azm = 0.0; pl->ca = 1.0; pl->sa = 0.0; pl->attr = START_LIVING; message(-1, False); /* turn off all the messages */ sight_flag = False; message(-2, False); // blocked_flag = False; message(-3, False); salvo_flag = False; for (g=o+opt->estart; g<o+opt->mobjects; g++) g->attr = 0; /* remove all objects */ } } /* Now schedule the missile runs. There will be a missile run if */ /* mtanks==0 or we are in copter practice or if a tank has been */ /* around too long or we haven't had a missile in a while. */ if (pl->attr & IS_ALIVE && opt->mmissiles && (!opt->mtanks || opt->copters || tank_stranded || missilecount > nextmissile)) if (!missilerun) { missilecount = 0; for (g=o+opt->estart; g<o+opt->bstart; g++) if (!(g->type & (IS_LANDER | IS_MISSILE | IS_COPTER))) if (g->attr & IS_ALIVE) g->attr = ERASE; else if (g->attr & IS_EXPLODING) g->attr = EXERASE; nummissile = frand() * 3 * opt->mmissiles + 1; if (firstmissile) nummissile = 1; first = firstmissile; firstmissile = False; missilerun = True; } /* once this run is over, schedule another one for a later date */ if (missilerun && opt->mtanks && nummissile <= 0) { missilerun = False; nextmissile = 750 * frand() + 750; } /* now place whatever objects need to be placed. */ if (!dead) placeobjects(o, missilerun, score); pl->attr &= ~IS_NEW; /* in case the player was new */ deadcount++; if (!missilerun) missilecount++; /* use timeclock here instead of gettimeofday to get a sync(d, 0) * just in case there are graphics we need to draw. */ timeclock(&tend); tdiff = limit - ((tend.tv_sec-tstart.tv_sec)*1e6+tend.tv_usec-tstart.tv_usec); if (tdiff > 0) { tend.tv_sec = 0; tend.tv_usec = tdiff; select(0, 0, 0, 0, &tend); } #ifdef DEVELOPER passes++; #endif //DEVELOPER } }
void run(){ Display gDisplay; Assets gAssets; ControlState gControlState; SDL_Event e; bool quit = false; srand(time(NULL)); if (!initDisplay(&gDisplay)) { fprintf(stderr, "ERROR: failed to initialize\n"); exit(1); } if (!loadAssets(&gAssets, &gDisplay)) { fprintf(stderr, "ERROR: failed to load game assets\n"); exit(1); } Player p = P_createPlayer(); AI *ai = AI_createAI(); LinkedList playerBulletList = LL_createLinkedList(); LinkedList enemyBulletList = LL_createLinkedList(); LinkedList enemyList = LL_createLinkedList(); Timer fpsCapTimer = T_createTimer(); Timer gameTimer = T_createTimer(); unsigned int lastShooting = 0; unsigned int lastEnemenySpawn = 0; unsigned int check = 0; T_start(&gameTimer); int controlarray[4] = {0}; SDL_Rect healthbar; initialisehealthbar(&healthbar); quit = staticscreen(gDisplay.renderer, "Assets/startmenu.bmp"); SDL_Surface* temp; SDL_Texture* background; temp = SDL_LoadBMP("Assets/background.bmp"); background = SDL_CreateTextureFromSurface(gDisplay.renderer, temp); SDL_FreeSurface(temp); temp = NULL; /*Event loop*/ do{ // start frame timer T_start(&fpsCapTimer); // check for exit event SDL_PollEvent(&e); quit = (e.type == SDL_QUIT); // check to open ai interface if(e.type == SDL_KEYDOWN){ if(e.key.keysym.sym == SDLK_ESCAPE){ quit = openaiscreen(gDisplay.renderer, controlarray); e.key.keysym.sym = SDLK_0; SDL_PushEvent(&e); } } // move player getKeyState(&gControlState); getMouseState(&gControlState); movePlayer(&p, &gControlState, &gAssets); AI_move(ai, P_getPosition(&p)); if ((check = T_getTicks(&gameTimer)) - lastEnemenySpawn > DEFAULT_SPAWN_INTERVAL) { spawnEnemy(&enemyList); lastEnemenySpawn = check; } aiaction(ai, &playerBulletList, &enemyList, T_getTicks(&gameTimer), controlarray, &p); moveEnemies(&enemyList, P_getPosition(&p)); enemiesShoot(&enemyList, &enemyBulletList, &p, T_getTicks(&gameTimer)); if (leftMouseIsDown() && ((check = T_getTicks(&gameTimer)) - lastShooting) > SHOOT_DELAY) { double mx = (double)gControlState.mouseX / SCREEN_WIDTH; double my = (double)gControlState.mouseY / SCREEN_HEIGHT; Point origin = P_getPosition(&p); Point destination = {mx, my}; shootBullet(&playerBulletList, origin, getShotDirection(origin, destination), PLAYER); lastShooting = check; } moveBullets(&playerBulletList); moveBullets(&enemyBulletList); detectCollision(&playerBulletList, &enemyList, &gAssets); detectCollisionPlayer(&enemyBulletList, &p, &gAssets); /* Update Screen */ SDL_RenderCopy(gDisplay.renderer, background, NULL, NULL); displayhealth(gDisplay.renderer, healthbar, p.health); renderBullets(&playerBulletList, &gDisplay, &gAssets, PLAYER); renderBullets(&enemyBulletList, &gDisplay, &gAssets, ENEMY); renderEnemies(&enemyList, &gDisplay, &gAssets); renderPlayer(&gDisplay, &gAssets, &gControlState); renderAI(ai, &gDisplay, &gAssets); // draw screen SDL_RenderPresent(gDisplay.renderer); delayNextFrame(T_getTicks(&fpsCapTimer)); if (gameOver(&p)) { printf("GAME OVER\n"); quit = staticscreen(gDisplay.renderer, "Assets/gameover.bmp"); p.health = 100; } } while (!quit); /* Memory Cleanup */ LL_destroyLinkedList(&playerBulletList); LL_destroyLinkedList(&enemyBulletList); AI_destroyAI(ai); SDL_DestroyTexture(background); freeAssets(&gAssets); closeDisplay(&gDisplay); }