538 lines
12 KiB
C++
538 lines
12 KiB
C++
/* 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 <windows.h>
|
|
#endif
|
|
|
|
#include <string>
|
|
#include <list>
|
|
#include <SDL/SDL.h>
|
|
#include <GL/gl.h>
|
|
#include <GL/glu.h>
|
|
#include <AL/al.h>
|
|
#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() {
|
|
}
|