/* This software is the propery of 'SaraCraft' - developed by Allanis. * Only members directly assosiated with the SaraCraft project may view/change * this code. */ #ifdef WIN32 #define WIN32_LEAN_AND_MEAN #include #endif #include #include #include #include #include #include #include "../ccmath.h" #include "../Log.h" #include "../Config.h" #include "../Player.h" #include "../Camera.h" #include "../image.h" #include "../GameState.h" #include "../Ships.h" #include "../sound.h" #include "Bullet.h" #include "ShipAI.h" #include "StateDone.h" #include "Battle.h" #define RELOADTICKS 1500 #define WATER_TEXSCALE 6 #define WATER_SIZE 200 using namespace std; Battle::Battle(Player *playerIn): GameState(NULL) { int shipId; // Temp storage for window width and height int width = Config::configuration->getWinWidth(); int height = Config::configuration->getWinHeight(); // Just to be safe leaveState = NULL; // Initialize variables for left and right arrows keys[0] = false; keys[1] = false; // Initialize sway of the ship rotx = 0.0; player = playerIn; // Get a copy of the player's ship ship = new Ship(player->ship); ship->x = 0; ship->z = 0; ship->rot = randInt(359); ship->speed = 0.002; //ship->speed = 0; playerTicksToReload = 0; // Set up the enemy ship shipId = randInt(3); enemyShip = ShipManager::list->newShip(shipId, "Enemy"); enemyShip->x = randInt(5); enemyShip->z = randInt(5); if(((enemyShip->x*enemyShip->x)+(enemyShip->z*enemyShip->z)) < 4) { if(enemyShip->x > 0) { enemyShip->x += 2; } else { enemyShip->x -= 2; } } enemyShip->rot = randInt(359); enemyShip->speed = 0.002; //enemyShip->speed = 0; enemyTicksToReload = 0; enemyAI = new ShipAI(enemyShip, ship); Bullet::generateList(); // Set up the camera cameraX = 9; cameraY = 5; cameraZ = 0; camera = new Camera((float) width/(float) height, cameraX, cameraY, cameraZ); // Set the light color and position ambientLight[0] = 0.17; ambientLight[1] = 0.17; ambientLight[2] = 0.17; ambientLight[3] = 1.0; diffuseLight[0] = 1.0; diffuseLight[1] = 1.0; diffuseLight[2] = 1.0; diffuseLight[3] = 1.0; lightPosition[0] = 7.0; lightPosition[1] = 15.0; lightPosition[2] = 2.0; lightPosition[3] = 0.0; waterMaterial[0] = 0.1; waterMaterial[1] = 0.15; waterMaterial[2] = 0.3; waterMaterial[3] = 1.0; bulletMaterial[0] = 0.1; bulletMaterial[1] = 0.1; bulletMaterial[2] = 0.1; bulletMaterial[3] = 1.0; BuildTexture("./data/water.png", &waterTexture, GL_REPEAT, true); // Begin setting up the rendering glClearColor(0, 0, 0, 0); glEnable(GL_TEXTURE_2D); glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); //glEnable(GL_NORMALIZE); glShadeModel(GL_SMOOTH); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_BLEND); glPointSize(5); // Set up lighting // For some reason this messes up the lighting in StateSailing //glEnable(GL_LIGHTING); //glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight); //glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight); //glLightfv(GL_LIGHT0, GL_POSITION, lightPosition); //glEnable(GL_LIGHT0); SetListener(); if(!LoadOgg("./data/cannon.ogg", &cannonBuffer)) { Log::logger->message("Warning: Could not load data/cannon.ogg"); } playerCannonSource = GenSource(cannonBuffer); enemyCannonSource = GenSource(cannonBuffer); if(!LoadOgg("./data/hit.ogg", &hitBuffer)) { Log::logger->message("Warning: Could not load data/hit.ogg"); } playerHitSource = GenSource(hitBuffer); enemyHitSource = GenSource(hitBuffer); lastTicks = SDL_GetTicks(); } Battle::~Battle() { Bullet *temp; while(!bullets.empty()) { temp = bullets.front(); bullets.pop_front(); delete temp; } delete enemyAI; delete ship; delete enemyShip; delete camera; if(leaveState != NULL) { delete leaveState; leaveState = NULL; } Bullet::deleteList(); alSourceStop(playerCannonSource); alSourceStop(enemyCannonSource); alDeleteSources(1, &playerCannonSource); alDeleteSources(1, &enemyCannonSource); alDeleteBuffers(1, &cannonBuffer); // Don't delete the player, StateSailing will do that Log::logger->message("Battle deleted"); } void Battle::loop() { // Draw the scene display(); // Process incoming events processEvents(); // Update the scene timer(); } void Battle::processEvents() { /* Our SDL event placeholder. */ SDL_Event event; static unsigned midx = Config::configuration->getWinWidth()/2,midy = Config::configuration->getWinHeight()/2; // Grab all the events off the queue. while( SDL_PollEvent( &event ) ) { switch( event.type ) { case SDL_KEYDOWN: // Handle key presses. handle_key_down( &event.key.keysym ); break; case SDL_KEYUP: handle_key_up(&event.key.keysym); break; case SDL_QUIT: // Handle quit requests (like Ctrl-c). mainMenu->doExit(); break; case SDL_MOUSEMOTION: if(event.motion.x != midx || event.motion.y != midy) { this->camera->changeAngle(0.2*event.motion.yrel,0.2*event.motion.xrel); SDL_WarpMouse(midx,midy); } break; case SDL_MOUSEBUTTONDOWN: vec3 v; this->camera->getPosition(v); float mag = sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]); v[0] /= mag; v[1] /= mag; v[2] /= mag; if(v[0] < 0) v[0] = -v[0]; if(v[1] < 0) v[1] = -v[1]; if(v[2] < 0) v[2] = -v[2]; if(event.button.button == SDL_BUTTON_WHEELUP && mag >= 1) this->camera->changePosition(-v[0],-v[1],-v[2]); else if(event.button.button == SDL_BUTTON_WHEELDOWN) this->camera->changePosition(v[0],v[1],v[2]); else break; this->camera->getPosition(v); break; } } } void Battle::handle_key_up(SDL_keysym* keysym) { switch( keysym->sym ) { case SDLK_a: case SDLK_LEFT: keys[0] = false; break; case SDLK_d: case SDLK_RIGHT: keys[1] = false; break; case SDLK_ESCAPE: switchState(mainMenu, this); break; default: break; } } void Battle::handle_key_down(SDL_keysym* keysym) { switch( keysym->sym ) { case SDLK_e: playerFire(-1*M_PI_2); break; case SDLK_q: playerFire(M_PI_2); break; case SDLK_o: enemyFire(-1*M_PI_2); break; case SDLK_p: enemyFire(M_PI_2); break; case SDLK_c: ship->rot += M_PI; break; case SDLK_x: battleFinished(sbNone); break; case SDLK_z: takeScreenshot(); break; case SDLK_a: case SDLK_LEFT: keys[0] = true; break; case SDLK_d: case SDLK_RIGHT: keys[1] = true; break; case SDLK_w: case SDLK_UP: ship->speed += .002; break; case SDLK_s: case SDLK_DOWN: ship->speed -= .002; default: break; } if(ship->speed < 0) ship->speed = 0; if(ship->speed > .008) ship->speed = .008; } void Battle::timer() { float shipSine, shipCos; GLfloat dX, dZ; list< Bullet* >::iterator iter; list< Bullet* >::iterator iterEnd; Bullet *temp; Ship *tempShip; ALuint hitSource; GLfloat distBetweenShips; float tempAngle; unsigned int tTicks = SDL_GetTicks(); unsigned int ticks = abs((int) (tTicks - lastTicks)); lastTicks = tTicks; if(playerTicksToReload > 0) { playerTicksToReload -= ticks; } if(enemyTicksToReload > 0) { enemyTicksToReload -= ticks; } enemyAI->update(ticks, enemyTicksToReload <= 0); if(enemyAI->shouldFire(&tempAngle)) { enemyFire(tempAngle); } if(keys[0]) ship->rot += .001*ticks; if(keys[1]) ship->rot -= .001*ticks; if(ship->rot >= TWO_PI) ship->rot -= TWO_PI; if(ship->rot < 0) ship->rot += TWO_PI; shipSine = sin(ship->rot); shipCos = cos(ship->rot); dX = shipCos * ship->speed * ticks; dZ = shipSine * ship->speed * ticks; ship->x += dX; ship->z -= dZ; shipSine = sin(enemyShip->rot); shipCos = cos(enemyShip->rot); dX = shipCos * enemyShip->speed * ticks; dZ = shipSine * enemyShip->speed * ticks; enemyShip->x += dX; enemyShip->z -= dZ; rotx += .001 * ticks; if(rotx > TWO_PI) rotx -= TWO_PI; temp = bullets.front(); while(!bullets.empty() && temp->location[1] < -.01) { bullets.pop_front(); delete temp; temp = bullets.front(); } iter = bullets.begin(); iterEnd = bullets.end(); while(iter != iterEnd) { temp = *iter; if(temp->location[1] >= -.01) { temp->update(ticks); if(temp->owner == ship) { tempShip = enemyShip; hitSource = enemyHitSource; } else { tempShip = ship; hitSource = playerHitSource; } if(temp->checkCollision(tempShip)) { temp->location[1] = -10; --tempShip->damage; alSourcePlay(hitSource); Log::logger->message("Damage: %d (%f)", tempShip->damage, temp->location[1]); } } ++iter; } if(ship->damage <= 0) { battleFinished(sbDefeat); } else if(enemyShip->damage <= 0) { battleFinished(sbVictory); } distBetweenShips = (ship->x - enemyShip->x)*(ship->x - enemyShip->x)+(ship->z - enemyShip->z)*(ship->z - enemyShip->z); if(distBetweenShips > 500) { battleFinished(sbNone); } } void Battle::display() { float texShiftX = ship->x / WATER_TEXSCALE; float texShiftZ = ship->z / WATER_TEXSCALE; Bullet *temp; list< Bullet* >::iterator iter; list< Bullet* >::iterator iterEnd; // Don't need to clear color buffer, since every pixel is redrawn // Just do it anyway, while it's in development glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT); glLoadIdentity(); camera->setCamera(); glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, waterMaterial); glBindTexture(GL_TEXTURE_2D, waterTexture); glBegin(GL_QUADS); glNormal3f(0, 1, 0); glTexCoord2f(0+texShiftX, 0+texShiftZ); glVertex3f(-WATER_SIZE/2, 0, -WATER_SIZE/2); glTexCoord2f(0+texShiftX, WATER_SIZE/WATER_TEXSCALE+texShiftZ); glVertex3f(-WATER_SIZE/2, 0, WATER_SIZE/2); glTexCoord2f(WATER_SIZE/WATER_TEXSCALE+texShiftX, WATER_SIZE/WATER_TEXSCALE+texShiftZ); glVertex3f(WATER_SIZE/2, 0, WATER_SIZE/2); glTexCoord2f(WATER_SIZE/WATER_TEXSCALE+texShiftX, 0+texShiftZ); glVertex3f(WATER_SIZE/2, 0, -WATER_SIZE/2); glEnd(); // Draw the ship glPushMatrix(); glRotatef(radiansToDegrees(ship->rot), 0, 1, 0); glRotatef(5*sin(rotx), 1, 0, 0); ship->draw(); glPopMatrix(); // Draw the enemy ship glPushMatrix(); glTranslatef(enemyShip->x-ship->x, 0, enemyShip->z-ship->z); glRotatef(radiansToDegrees(enemyShip->rot), 0, 1, 0); glRotatef(5*sin(rotx), 1, 0, 0); enemyShip->draw(); glPopMatrix(); glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, bulletMaterial); glPushMatrix(); glTranslatef(-1*ship->x, 0, -1*ship->z); glDisable(GL_TEXTURE_2D); iter = bullets.begin(); iterEnd = bullets.end(); while(iter != iterEnd) { temp = *iter; temp->draw(); ++iter; } glEnable(GL_TEXTURE_2D); glPopMatrix(); SDL_GL_SwapBuffers(); } void Battle::playerFire(float rotDiff) { // Change this to make sure reloaded if(playerTicksToReload <= 0) { float angle = ship->rot + rotDiff; bullets.push_back(new Bullet(ship, -1*angle)); playerTicksToReload = RELOADTICKS; alSourcePlay(playerCannonSource); } } void Battle::enemyFire(float rotDiff) { // Change this to make sure reloaded if(enemyTicksToReload <= 0) { float angle = enemyShip->rot + rotDiff; bullets.push_back(new Bullet(enemyShip, -1*angle)); enemyTicksToReload = RELOADTICKS; alSourcePlay(enemyCannonSource); } } void Battle::playerHit() { Log::logger->message("Player hit"); } void Battle::enemyHit() { Log::logger->message("Enemy hit"); } void Battle::battleFinished(BattleResult result) { // Just to be safe if(leaveState != NULL) { delete leaveState; } leaveState = new StateDone(player, enemyShip, result); switchState(leaveState, previous); } void Battle::switchTo(GameState *oldState) { keys[0] = false; keys[1] = false; glMatrixMode(GL_MODELVIEW); glLoadIdentity(); camera->setProjection(); glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_BLEND); glEnable(GL_LIGHTING); SetListener(); lastTicks = SDL_GetTicks(); } void Battle::switchFrom() { }