This repository has been archived on 2026-05-18. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
spaceshooter/cpp/main.cpp
2010-07-29 01:46:34 +00:00

885 lines
32 KiB
C++

#include <libgame/libgame.h>
#include "main.h"
#include <iostream>
#include <cstdlib>
#include <stdlib.h>
#include <fstream>
// TODO:
//
// - add level clear screens
// - handle appearance of the boss dependent upon player score
// - get the game to start in fullscreen
//
// THE PROJECTILE/CHARACTER SUBCLASSING IS FUCKED. THE ORDER OF THE 'damage' ELEMENT AND OTHER
// ITEMS CAUSES UNEXPECTED RESULTS AS ITEMS SUCH AS PROJECTILES ARE TYPECAST AS A (Character *)
// AND PASSED AROUND THRU COLLISION FUNCTIONS. CHANGE THE ORDER THAT THE 'damage' ELEMENT IS DEFINED
// IN THE CHARACTER CLASS AND YOU'LL SEE THE LASERS START DOING WIERD SHIT AS A RESULT.
// keyed by difficulty level
// see generateEnemies() for how this is used
const int enemyWeights[][10] = {
{1, 1, 1, 1, 1, 2, 2, 2, 3, 3},
{1, 1, 1, 1, 2, 2, 2, 3, 3, 4},
{1, 1, 1, 2, 2, 2, 3, 3, 3, 4},
{1, 1, 2, 2, 2, 3, 3, 3, 4, 4} };
// keyed by difficulty level
// see generateEnemies() for how this is used
const int maxVisibleEnemies[][5] = {
// {TYPE1, TYPE2, TYPE3, TYPE4, BOSS}
{2, 1, 1, 1, 1},
{2, 2, 1, 1, 1},
{3, 2, 2, 1, 1},
{3, 3, 2, 2, 1} };
// keyed by difficulty level
int curVisibleEnemies[][5] = {
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0} };
int loadSprites()
{
SpriteStrip *strip = NULL;
Game &myGame = Game::NewSingleton();
int failed = 0;
//std::cerr << "Looping from 0 to " << MAXSPRITES << " sprites...\n";
for ( int i = 0; i < MAXSPRITES ; i++ ) {
std::cerr .flush();
//std::cerr << "Trying to load sprite strip from (index " << i << ") file " << spriteStrips[i] << "\n";
strip = myGame.newSpriteStrip(spriteStrips[i]);
if ( strip == NULL ) {
//std::cerr << "Failed to allocate new sprite strip in memory.\n";
failed++;
continue ;
}
if ( strip->loadFromFile(spriteStrips[i], spriteStats[i][0], spriteStats[i][1], (Vector){0, 0, 0}) != 0 ) {
//std::cerr << "Failed to load sprite strip from file " << spriteStrips[i] << "\n";
delete strip;
failed++;
continue ;
}
//std::cerr << "Added sprite strip " << spriteStrips[i] << "(" << spriteStats[i][0] << "x" << spriteStats[i][1] << ") to memory\n";
}
// now do the same for the backgrounds
for ( int i = 0; i < MAXSCREENS ; i++ ) {
std::cerr .flush();
//std::cerr << "Trying to load sprite strip from (index " << i << ") file " << screenBackgrounds[i] << "\n";
strip = myGame.newSpriteStrip(screenBackgrounds[i]);
if ( strip == NULL ) {
//std::cerr << "Failed to allocate new sprite strip in memory.\n";
failed++;
continue ;
}
if ( strip->loadFromFile(screenBackgrounds[i], 0, 0, (Vector){0, 0, 0}) != 0 ) {
//std::cerr << "Failed to load sprite strip from file " << spriteStrips[i] << "\n";
failed++;
delete strip;
continue ;
}
//std::cerr << "Added sprite strip " << screenBackgrounds[i] << " (0x0) to memory\n";
}
//std::cerr << "returning with " << failed << " sprites failed to load.\n";
// init the enemy animations
myGame.newAnimation(ANIM_ENEMYFIGHTER1)->setStrip(myGame.getSpriteStrip(SPRITEFILE_ENEMYFIGHTER1), 0, 0, (Vector){0,0,0});
myGame.newAnimation(ANIM_ENEMYFIGHTER2)->setStrip(myGame.getSpriteStrip(SPRITEFILE_ENEMYFIGHTER2), 0, 0, (Vector){0,0,0});
myGame.newAnimation(ANIM_ENEMYFIGHTER3)->setStrip(myGame.getSpriteStrip(SPRITEFILE_ENEMYFIGHTER3), 0, 0, (Vector){0,0,0});
myGame.newAnimation(ANIM_ENEMYFIGHTER4)->setStrip(myGame.getSpriteStrip(SPRITEFILE_ENEMYFIGHTER4), 0, 0, (Vector){0,0,0});
myGame.newAnimation(ANIM_ENEMYDESTROYER1)->setStrip(myGame.getSpriteStrip(SPRITEFILE_ENEMYDESTROYER1), 0, 0, (Vector){0,0,0});
myGame.newAnimation(ANIM_ENEMYDESTROYER2)->setStrip(myGame.getSpriteStrip(SPRITEFILE_ENEMYDESTROYER2), 0, 0, (Vector){0,0,0});
myGame.newAnimation(ANIM_ENEMYLASERSINGLE)->setStrip(myGame.getSpriteStrip(SPRITEFILE_ENEMYLASER1), 0, 0, (Vector){0, 0, 0});
myGame.newAnimation(ANIM_ENEMYLASERDOUBLE)->setStrip(myGame.getSpriteStrip(SPRITEFILE_ENEMYLASER2), 0, 0, (Vector){0, 0, 0});
// init misc animations
myGame.newAnimation(ANIM_EXPLOSION)->setStrip(myGame.getSpriteStrip(SPRITEFILE_EXPLOSION), 12, 1, (Vector){0,0,0});
myGame.newAnimation(ANIM_PWUP_BIGSHIP)->setStrip(myGame.getSpriteStrip(SPRITEFILE_POWERUP_SHIP), 0, 0, (Vector){0,0,0});
myGame.newAnimation(ANIM_PWUP_ONEUP)->setStrip(myGame.getSpriteStrip(SPRITEFILE_POWERUP_ONEUP), 0, 0, (Vector){0,0,0});
myGame.newAnimation(ANIM_PWUP_SHIELD)->setStrip(myGame.getSpriteStrip(SPRITEFILE_POWERUP_SHIELD), 0, 0, (Vector){0,0,0});
myGame.newAnimation(ANIM_PWUP_SPREADSHOT)->setStrip(myGame.getSpriteStrip(SPRITEFILE_POWERUP_SPREAD), 0, 0, (Vector){0,0,0});
myGame.newAnimation(ANIM_PLAYERSPREAD1)->setStrip(myGame.getSpriteStrip(SPRITEFILE_PLAYERSPREAD1), 0, 0, (Vector){0,0,0});
myGame.newAnimation(ANIM_PLAYERSPREAD3)->setStrip(myGame.getSpriteStrip(SPRITEFILE_PLAYERSPREAD3), 0, 0, (Vector){0,0,0});
return failed;
}
int initPlayers(Player *player1, Player *player2)
{
Animation *shipAnim = NULL;
Player *player;
Game &game = Game::NewSingleton();
GameOptions &opts = GameOptions::NewSingleton();
if ( player1 == NULL || player2 == NULL ) {
//std::cerr << "Player1 : " << player1 << " Player2 : " << player2 << "\n";
delete shipAnim;
return 1;
}
//std::cerr << "Setting sprite strip for player actors...\n";
if ( (shipAnim = game.newAnimation(ANIM_PLAYERDOUBLE)) == NULL ) {
return 1;
}
if ( shipAnim->setStrip(game.getSpriteStrip(SPRITEFILE_PLAYERSHIP2), 1) != 0 ) {
//std::cerr << "Couldn't set sprite strip for player animations\n";
return 1;
}
if ( (shipAnim = game.newAnimation(ANIM_PLAYERSINGLE)) == NULL ) {
return 1;
}
if ( shipAnim->setStrip(game.getSpriteStrip(SPRITEFILE_PLAYERSHIP1), 1) != 0 ) {
//std::cerr << "Couldn't set sprite strip for player animations\n";
return 1;
}
player = player1;
while ( player != NULL ) {
player->addAnimation(game.getAnimation(ANIM_PLAYERSINGLE), STATE_DEFAULT);
player->addState(STATE_NONE);
player->lives = 0;
player->score = 0;
player->setUserType(ACTOR_TEAM_PLAYER | ACTORTYPE_PLAYER | ACTORTYPE_NODELETE);
player->damage = 5;
player->weaponDamage = opts.playerBaseDamage;
player->projectileAnim = game.getAnimation(ANIM_PLAYERLASERSINGLE);
player->projectileSound = SOUNDFILE_PLAYERLASERSHOT;
player->deathSound = SOUNDFILE_EXPLOSION;
if ( player == player2 )
break;
player = player2;
}
player1->addAnimation(game.getAnimation(ANIM_EXPLOSION), STATE_DYING);
player2->addAnimation(game.getAnimation(ANIM_EXPLOSION), STATE_DYING);
player1->addAnimation(NULL, STATE_DEAD);
player2->addAnimation(NULL, STATE_DEAD);
player1->setPosition((Vector){250, 500, 0});
player2->setPosition((Vector){550, 500, 0});
player1->setState(STATE_NONE);
player2->setState(STATE_NONE);
return 0;
}
int setupStaticDisplay(Display2D *staticDisplay, std::string bgfile)
{
Actor *staticBackActor;
Animation *staticBackAnim;
Game &game = Game::NewSingleton();
if ( staticDisplay == NULL ) {
return 1;
}
staticBackActor = game.newActor(bgfile);
staticBackAnim = game.newAnimation(bgfile);
if ( staticBackActor == NULL ) {
return 1;
}
if ( staticBackAnim == NULL ) {
game.freeActor(bgfile);
return 1;
}
//staticDisplay->initVideo((Vector){0,0,0}, 800, 600, 32, SDL_SWSURFACE);
staticDisplay->shareCanvas(&(Game::NewSingleton()));
staticBackAnim->setStrip(game.getSpriteStrip(bgfile), 0);
staticBackActor->addAnimation(staticBackAnim, STATE_NONE);
staticBackActor->addState(STATE_NONE);
staticDisplay->addActor(staticBackActor, 0);
game.windows.push_back(staticDisplay);
return 0;
}
int setupGameDisplay(GameDisplay *gameDisplay)
{
StarfieldBackground *gameBackActor;
Game &game = Game::NewSingleton();
if ( gameDisplay == NULL ) {
return 1;
}
gameBackActor = new StarfieldBackground();
if ( gameBackActor == NULL ) {
return 1;
}
//std::cerr << "Scrolling background actor is at " << gameBackActor << "\n";
//gameDisplay->initVideo((Vector){0,0,0}, 800, 600, 32, SDL_SWSURFACE);
gameDisplay->shareCanvas(&(Game::NewSingleton()));
gameBackActor->setVelocity((Vector){0, 5, 0});
gameBackActor->initStarfield(800, 600);
gameBackActor->addState(STATE_NONE);
gameBackActor->lockFPS(24);
gameDisplay->addActor(gameBackActor, 0);
game.windows.push_back(gameDisplay);
game.addActor(gameBackActor, ACTOR_STARBACKGROUND);
return 0;
}
int configureOptionsMenu(MenuDisplay *menuDisplay)
{
Animation *menuAnimation;
Animation *pointerAnim;
Actor *menuBackground;
char joyName[128];
Game &myGame = Game::NewSingleton();
GameOptions &opts = GameOptions::NewSingleton();
int i = 0;
if ( pointerAnim == NULL ) {
return 1;
}
menuAnimation = myGame.newAnimation(ANIM_OPTIONMENU);
pointerAnim = myGame.newAnimation(ANIM_OPTIONPTR);
menuBackground = myGame.newActor(ACTOR_OPTMENUBACKGROUND);
if ( menuBackground == NULL ) {
myGame.freeAnimation(ANIM_OPTIONPTR);
return 1;
}
if ( menuAnimation == NULL ) {
myGame.freeAnimation(ANIM_OPTIONPTR);
myGame.freeActor(ACTOR_OPTMENUBACKGROUND);
return 1;
}
menuDisplay->initVideo((Vector){200,100,0}, 400, 400, 32, SDL_SWSURFACE);
menuAnimation->setStrip(myGame.getSpriteStrip(BACKGROUNDFILE_OPTIONS), 0);
pointerAnim->setStrip(myGame.getSpriteStrip(SPRITEFILE_PLAYERSHIP3), 0);
menuBackground->addAnimation(menuAnimation, STATE_NONE);
menuBackground->setPosition((Vector){0, 0, 0});
menuDisplay->addActor(menuBackground);
menuDisplay->setPointer(pointerAnim);
menuDisplay->setMenuOrigin((Vector){20, 20, 0} );
menuDisplay->setFont("arial", 20, (SDL_Color){0x2E,0x8F,0x2C,0}, (SDL_Color){0,0,0,0});
menuDisplay->setSpacing(20);
menuDisplay->addOption(GAMEOPT_DIFFICULTY, 0, 0, 0, 0, NULL);
menuDisplay->addSubOption(GAMEOPT_DIFFICULTY, DIFFICULTY_EASY);
menuDisplay->addSubOption(GAMEOPT_DIFFICULTY, DIFFICULTY_NORMAL);
menuDisplay->addSubOption(GAMEOPT_DIFFICULTY, DIFFICULTY_HARD);
menuDisplay->addSubOption(GAMEOPT_DIFFICULTY, DIFFICULTY_IMMORTAL);
menuDisplay->addOption(GAMEOPT_MUSIC, 0, 0, 0, 0, NULL);
menuDisplay->addSubOption(GAMEOPT_MUSIC, "ON");
menuDisplay->addSubOption(GAMEOPT_MUSIC, "OFF");
menuDisplay->addOption(GAMEOPT_SOUNDEFFECTS, 0, 0, 0, 0, NULL);
menuDisplay->addSubOption(GAMEOPT_SOUNDEFFECTS, "ON");
menuDisplay->addSubOption(GAMEOPT_SOUNDEFFECTS, "OFF");
menuDisplay->addOption(GAMEOPT_MUSICVOL, 0, 128, opts.musicVolume, 1, NULL);
menuDisplay->addOption(GAMEOPT_SOUNDVOL, 0, 128, opts.soundVolume, 1, NULL);
menuDisplay->addOption(GAMEOPT_P1CONTROL, 0, 0, 0, 0, NULL);
menuDisplay->addSubOption(GAMEOPT_P1CONTROL, CONTROLOPT_KEYBOARD);
for (i = 0; i < SDL_NumJoysticks() ; i++ ) {
memset((char *)&joyName, 128, 0);
sprintf((char *)&joyName, "J%d %s", i, SDL_JoystickName(i));
menuDisplay->addSubOption(GAMEOPT_P1CONTROL, std::string(joyName));
}
menuDisplay->addSubOption(GAMEOPT_P1CONTROL, CONTROLOPT_NONE);
menuDisplay->addOption(GAMEOPT_P2CONTROL, 0, 0, 0, 0, NULL);
menuDisplay->addSubOption(GAMEOPT_P2CONTROL, CONTROLOPT_NONE);
menuDisplay->addSubOption(GAMEOPT_P2CONTROL, CONTROLOPT_KEYBOARD);
for (i = 0; i < SDL_NumJoysticks() ; i++ ) {
memset((char *)&joyName, 128, 0);
sprintf((char *)&joyName, "J%d %s", i, SDL_JoystickName(i));
menuDisplay->addSubOption(GAMEOPT_P2CONTROL, std::string(joyName));
}
menuDisplay->setRelation(GAMEOPT_P2CONTROL, GAMEOPT_P1CONTROL);
menuDisplay->setRelation(GAMEOPT_P1CONTROL, GAMEOPT_P2CONTROL);
myGame.windows.push_back(menuDisplay);
return 0;
}
int configureTitleMenu(MenuDisplay *menuDisplay)
{
Animation *menuAnimation;
Animation *pointerAnim;
Actor *menuBackground;
Game &myGame = Game::NewSingleton();
if ( pointerAnim == NULL ) {
return 1;
}
menuAnimation = myGame.newAnimation(ANIM_TITLEMENU);
pointerAnim = myGame.newAnimation(ANIM_TITLEPTR);
menuBackground = myGame.newActor(ACTOR_TITLEBACKGROUND);
if ( menuBackground == NULL ) {
delete pointerAnim;
return 1;
}
if ( menuAnimation == NULL ) {
delete pointerAnim;
delete menuBackground;
return 1;
}
//menuDisplay->initVideo((Vector){0,0,0}, 800, 600, 32, SDL_SWSURFACE);
menuDisplay->shareCanvas(&(Game::NewSingleton()));
menuAnimation->setStrip(myGame.getSpriteStrip(BACKGROUNDFILE_MENU), 0);
pointerAnim->setStrip(myGame.getSpriteStrip(SPRITEFILE_PLAYERSHIP3), 0);
menuBackground->addAnimation(menuAnimation, STATE_NONE);
menuBackground->setPosition((Vector){0, 0, 0});
menuDisplay->addActor(menuBackground);
menuDisplay->setPointer(pointerAnim);
menuDisplay->setMenuOrigin((Vector){ 380, 150, 0} );
menuDisplay->setFont("arial", 30, (SDL_Color){0x2E,0x8F,0x2C,0}, (SDL_Color){0,0,0,0});
for (int i = 0; i < MAX_OPTS_TITLEMENU ; i++ ) {
//std::cerr << "Adding title menu option " << titleMenuOpts[i] << "\n";
menuDisplay->addOption(titleMenuOpts[i], 0, 0, 0, 0, NULL);
}
myGame.windows.push_back(menuDisplay);
return 0;
}
void checkPlayerInput(SDL_Event *event, int playerNum, Player *player, GameDisplay *gameDisplay)
{
GameOptions &opts = GameOptions::NewSingleton();
// FIXME: The static allocation of Animation objects is fucked. Have to dynamic EVERY SINGLE ONE.
// this one is GUARANTEED to be a loss at application exit.
ControlMap *controlMap = &opts.controlMaps[playerNum-1];
int joyNum = 0;
char tmpBuf[512];
memset((char *)&tmpBuf, 0x00, 512);
SDL_JoystickUpdate();
if ( controlMap == NULL || event == NULL ) {
//std::cerr << "NULL CONTROL MAP!\n";
return;
}
joyNum = SDL_JoystickIndex(controlMap->joystick);
//std::cerr << "Player " << playerNum << " has control type " << controlMap->controlType << "\n";
//sprintf((char *)&tmpBuf, "Current player state (pre): %d", player->getState() );
//std::cerr << tmpBuf << "\n";
if ( controlMap->controlType == CONTROL_TYPE_KEYBOARD ) {
if ( event->type == SDL_KEYUP ) {
if ( event->key.keysym.sym == controlMap->moveLeft ) {
player->removeState(STATE_MOVELEFT);
} else if ( event->key.keysym.sym == controlMap->moveRight ) {
player->removeState(STATE_MOVERIGHT);
} else if ( event->key.keysym.sym == controlMap->moveUp ) {
player->removeState(STATE_MOVEUP);
} else if ( event->key.keysym.sym == controlMap->moveDown ) {
player->removeState(STATE_MOVEDOWN);
} else if ( event->key.keysym.sym == controlMap->fire ) {
player->fireProjectile();
}
} else if ( event->type == SDL_KEYDOWN ) {
if ( event->key.keysym.sym == controlMap->moveLeft ) {
player->addState(STATE_MOVELEFT);
} else if ( event->key.keysym.sym == controlMap->moveRight ) {
player->addState(STATE_MOVERIGHT);
} else if ( event->key.keysym.sym == controlMap->moveUp ) {
player->addState(STATE_MOVEUP);
} else if ( event->key.keysym.sym == controlMap->moveDown ) {
player->addState(STATE_MOVEDOWN);
}
}
} else if ( controlMap->controlType == CONTROL_TYPE_JOYSTICK ) {
std::cerr << "Joystick event is " << (int)event->type << " (hat motion up is " << SDL_JOYHATMOTION << ")" << std::endl;
if ( event->type == SDL_JOYHATMOTION ) {
// OKAY you know what SCREW axis movements
// They suck suck SUCK
// just use the hat for this game
std::cerr << "Joystick event is for stick " << event->jhat.which << " but we're monitoring " << joyNum << std::endl;
if ( (event->type == SDL_JOYHATMOTION && event->jhat.which != joyNum) ) {
return;
}
std::cerr << "Joy hat value is : " << event->jhat.value << std::endl;
// the reason we also check axes 5 and 6 here is because some gamepads (like the
// logitech wingman this was developed with) map the joystick hat events to axes
// 5 and 6
if ( (event->jhat.value & controlMap->moveLeft) == controlMap->moveLeft) {
std::cerr << "Player is moving left\n";
player->addState(STATE_MOVELEFT);
} else {
player->removeState(STATE_MOVELEFT);
}
if ( (event->jhat.value & controlMap->moveRight) == controlMap->moveRight) {
std::cerr << "Player is moving right\n";
player->addState(STATE_MOVERIGHT);
} else {
player->removeState(STATE_MOVERIGHT);
}
if ( (event->jhat.value & controlMap->moveDown) == controlMap->moveDown) {
//std::cerr << "Player is moving up\n";
player->addState(STATE_MOVEDOWN);
} else {
player->removeState(STATE_MOVEDOWN);
}
if ( (event->jhat.value & controlMap->moveUp) == controlMap->moveUp) {
//std::cerr << "Player is moving down\n";
player->addState(STATE_MOVEUP);
} else {
player->removeState(STATE_MOVEUP);
}
} else if ( event->type == SDL_JOYBUTTONUP ) {
if ( event->jbutton.which == joyNum ) {
//std::cerr << "FIRING LASER\n";
player->fireProjectile();
}
}
}
//sprintf((char *)&tmpBuf, "Current player state (post): %d", player->getState() );
//std::cerr << tmpBuf << "\n";
}
void processInput(MenuDisplay *menuDisplay,
GameDisplay *gameDisplay,
Display2D *creditDisplay,
Display2D *helpDisplay,
Display2D *failDisplay,
MenuDisplay *optionDisplay,
Player *player1,
Player *player2,
HUDDisplay *hudDisplay1,
HUDDisplay *hudDisplay2)
{
Game &myGame = Game::NewSingleton();
GameStatus &gamestatus = GameStatus::NewSingleton();
SDL_Event nextEvent;
if ( gamestatus.status == GAMESTATE_OPTIONSCREEN ) {
if ( myGame.keyHeldDown(SDLK_LEFT) ) {
nextEvent.type = SDL_KEYDOWN;
nextEvent.key.keysym.sym = SDLK_LEFT;
nextEvent.key.state = SDL_PRESSED;
optionDisplay->handleEvent(&nextEvent);
}
if ( myGame.keyHeldDown(SDLK_RIGHT) ) {
nextEvent.type = SDL_KEYDOWN;
nextEvent.key.keysym.sym = SDLK_RIGHT;
nextEvent.key.state = SDL_PRESSED;
optionDisplay->handleEvent(&nextEvent);
}
}
while ( SDL_PollEvent(&nextEvent) != 0 ) {
//std::cerr << "Polling event from SDL queue ...\n";
switch (nextEvent.type) {
case SDL_KEYUP:
//std::cerr << "Keyup event received\n";
if ( nextEvent.key.state != SDL_RELEASED ) {
break;
}
if ( nextEvent.key.keysym.sym == SDLK_ESCAPE ) {
//std::cerr << gamestatus.status << "\n";
if ( gamestatus.status == GAMESTATE_CREDITSCREEN ||
gamestatus.status == GAMESTATE_HELPSCREEN ||
gamestatus.status == GAMESTATE_FAILSCREEN ) {
creditDisplay->setActive(0);
helpDisplay->setActive(0);
failDisplay->setActive(0);
gamestatus.status = GAMESTATE_TITLEMENU;
menuDisplay->setActive(1);
myGame.haltMusic();
myGame.playMusic(MUSICFILE_TITLESCREEN);
} else if ( gamestatus.status == GAMESTATE_OPTIONSCREEN ) {
optionDisplay->setActive(0);
//gamestatus.status = GAMESTATE_TITLEMENU;
} else if ( gamestatus.status == GAMESTATE_PLAYSINGLE || gamestatus.status == GAMESTATE_PLAYMULTI) {
gamestatus.status = GAMESTATE_TITLEMENU;
gameDisplay->setActive(0);
menuDisplay->setActive(1);
//std::cerr << "Clearing sounds...\n";
myGame.cleanSounds(1);
myGame.haltMusic();
myGame.playMusic(MUSICFILE_TITLESCREEN);
} else {
gamestatus.running = 0;
}
} else {
// processing keys per-gamestatus.status
if ( gamestatus.status == GAMESTATE_TITLEMENU ) {
menuDisplay->handleEvent(&nextEvent);
} else if ( gamestatus.status == GAMESTATE_OPTIONSCREEN) {
optionDisplay->handleEvent(&nextEvent);
}
}
case SDL_KEYDOWN:
if ( nextEvent.key.state != SDL_PRESSED ) {
break;
}
}
if ( gamestatus.status == GAMESTATE_PLAYSINGLE || gamestatus.status == GAMESTATE_PLAYMULTI ) {
checkPlayerInput(&nextEvent, 1, player1, gameDisplay);
checkPlayerInput(&nextEvent, 2, player2, gameDisplay);
}
}
}
void setControlMap(MenuOption *opt, Player *player, int playerNum)
{
GameOptions &opts = GameOptions::NewSingleton();
int joyNum;
char joyStr[2] = {'\0', '\0'};
ControlMap *controlMap = &opts.controlMaps[playerNum-1];
if ( opt == NULL ) {
return;
}
//std::cerr << "Setting player " << playerNum << "control scheme to " << opt->getStringValue() << "\n";
if ( opt->getStringValue() == CONTROLOPT_KEYBOARD ) {
//std::cerr << "Setting up keyboard control for player " << playerNum << "\n";
controlMap->controlType = CONTROL_TYPE_KEYBOARD;
controlMap->joystick = NULL;
controlMap->moveUp = CONTROL_KEY_MOVEUP;
controlMap->moveDown = CONTROL_KEY_MOVEDOWN;
controlMap->moveLeft = CONTROL_KEY_MOVELEFT;
controlMap->moveRight = CONTROL_KEY_MOVERIGHT;
controlMap->fire = CONTROL_KEY_FIRE;
//std::cerr << "Control is ready\n";
} else if ( opt->getStringValue() == CONTROLOPT_NONE ) {
controlMap->controlType = CONTROL_TYPE_NONE;
controlMap->joystick = NULL;
controlMap->moveUp = 0;
controlMap->moveDown = 0;
controlMap->moveLeft = 0;
controlMap->moveRight = 0;
controlMap->fire = 0;
} else if ( opt->getStringValue()[0] == 'J' ) {
//std::cerr << "Setting up joystick control for player " << playerNum << "\n";
joyStr[0] = opt->getStringValue()[1];
joyNum = atoi((char *)&joyStr);
if ( joyNum < SDL_NumJoysticks() ) {
if ( controlMap->joystick == NULL ) {
controlMap->joystick = SDL_JoystickOpen(joyNum);
if ( controlMap->joystick == NULL ) {
// shit..
std::cerr << "Failed opening joystick; re-setting this control to keyboard and hoping for the best.\n";
opt->name == CONTROLOPT_KEYBOARD;
setControlMap(opt, player, playerNum);
return;
}
std::cerr << "Successfully opened joystick " << joyNum << " " << opt->getStringValue() << "\n";
std::cerr << "Number of buttons " << SDL_JoystickNumButtons(controlMap->joystick) << "\n";
std::cerr << "Number of axes " << SDL_JoystickNumAxes(controlMap->joystick) << "\n";
}
controlMap->controlType = CONTROL_TYPE_JOYSTICK;
controlMap->moveUp = CONTROL_JS_MOVEUP;
controlMap->moveDown = CONTROL_JS_MOVEDOWN;
controlMap->moveLeft = CONTROL_JS_MOVELEFT;
controlMap->moveRight = CONTROL_JS_MOVERIGHT;
controlMap->fire = CONTROL_JS_FIRE;
controlMap->lastFireButtonState = 0;
//std::cerr << "Control is ready\n";
}
}
}
void processMenus(MenuDisplay *menuDisplay,
GameDisplay *gameDisplay,
Display2D *creditDisplay,
Display2D *helpDisplay,
Display2D *failDisplay,
MenuDisplay *optionDisplay,
Player *player1,
Player *player2,
HUDDisplay *hudDisplay1,
HUDDisplay *hudDisplay2)
{
Game &myGame = Game::NewSingleton();
GameStatus &gamestatus = GameStatus::NewSingleton();
GameOptions &opts = GameOptions::NewSingleton();
MenuOption *opt;
// this is mostly used to handle title menu option handling, not much else goes on here
if ( gamestatus.status == GAMESTATE_TITLEMENU ) {
// --------------- title screen menu processing ------------------------
if ( menuDisplay->isActive() == 0 ) {
opt = menuDisplay->getOption();
//std::cerr << opt->getStringValue() << "\n";
if ( opt != NULL && opt->getStringValue() == "1P START" ) {
menuDisplay->setActive(0);
gamestatus.status = GAMESTATE_PLAYSINGLE;
gameDisplay->setActive(1);
if ( opts.playMusic == 1 ) {
myGame.haltMusic();
myGame.playMusic(MUSICFILE_GAMESCREEN);
}
gamestatus.nextLevel(player1, NULL, 0);
player1->setPosition((Vector){350, 500, 0});
player1->setState(STATE_NONE);
gameDisplay->setHUDs(hudDisplay1, NULL);
if ( opts.playSound == 1 )
myGame.playSound(SOUNDFILE_PLAYERSTART);
player2->lives = -1;
} else if ( opt != NULL && opt->getStringValue() == "MP START" ) {
menuDisplay->setActive(0);
gamestatus.status = GAMESTATE_PLAYMULTI;
gameDisplay->setActive(1);
if ( opts.playMusic == 1 ) {
myGame.haltMusic();
myGame.playMusic(MUSICFILE_GAMESCREEN);
}
if ( opts.playSound == 1 )
myGame.playSound(SOUNDFILE_PLAYERSTART);
gameDisplay->setHUDs(hudDisplay1, hudDisplay2);
gamestatus.nextLevel(player1, player2, 0);
} else if ( opt != NULL && opt->getStringValue() == "CREDITS" ) {
menuDisplay->setActive(0);
gamestatus.status = GAMESTATE_CREDITSCREEN;
creditDisplay->setActive(1);
if ( opts.playMusic == 1 ) {
myGame.haltMusic();
myGame.playMusic(MUSICFILE_CREDITSCREEN);
}
} else if ( opt != NULL && opt->getStringValue() == "HELP" ) {
menuDisplay->setActive(0);
gamestatus.status = GAMESTATE_HELPSCREEN;
helpDisplay->setActive(1);
} else if ( opt != NULL && opt->getStringValue() == "OPTIONS" ) {
menuDisplay->setActive(1);
gamestatus.status = GAMESTATE_OPTIONSCREEN;
optionDisplay->setActive(1);
} else if ( opt != NULL && opt->getStringValue() == "QUIT" ) {
//std::cerr << "Quitting\n";
exit(0);
}
}
// we do this here instead of below, in the post-opt screen processing,
// so the default control maps are enforced even if they never enter the option screen
setControlMap(optionDisplay->getOption(GAMEOPT_P1CONTROL), player1, 1);
setControlMap(optionDisplay->getOption(GAMEOPT_P2CONTROL), player2, 2);
// ------------- OPTION SCREEN MENU PROCESSING -------------------------
} else if ( gamestatus.status == GAMESTATE_OPTIONSCREEN ) {
if ( optionDisplay->isActive() == 0 ) {
//std::cerr << "Trying to update options\n";
gamestatus.status = GAMESTATE_TITLEMENU;
// set music/sound/difficulty options
opt = optionDisplay->getOption(GAMEOPT_MUSIC);
if ( opt->getStringValue() == "OFF" ) {
myGame.haltMusic();
opts.playMusic = 0;
} else {
if ( opts.playMusic == 0 ) {
myGame.playMusic(MUSICFILE_TITLESCREEN);
}
opts.playMusic = 1;
}
opt = optionDisplay->getOption(GAMEOPT_SOUNDEFFECTS);
if ( opt->getStringValue() == "Off" ) {
opts.playSound = 0;
} else {
opts.playSound = 1;
}
opt = optionDisplay->getOption(GAMEOPT_DIFFICULTY);
if ( opt->getStringValue() == DIFFICULTY_EASY ) {
opts.difficultyLevel = 1;
} else if ( opt->getStringValue() == DIFFICULTY_NORMAL ) {
opts.difficultyLevel = 2;
} else if ( opt->getStringValue() == DIFFICULTY_HARD ) {
opts.difficultyLevel = 3;
} else if ( opt->getStringValue() == DIFFICULTY_IMMORTAL ) {
opts.difficultyLevel = 4;
}
opt = optionDisplay->getOption(GAMEOPT_MUSICVOL);
myGame.setMusicVolume(opt->getIntValue());
opt = optionDisplay->getOption(GAMEOPT_SOUNDVOL);
myGame.setSoundVolume(opt->getIntValue());
}
}
}
void generateEnemies(GameDisplay *display, Player *player1, Player *player2)
{
GameOptions &opts = GameOptions::NewSingleton();
GameStatus &status = GameStatus::NewSingleton();
Character *enemy = NULL;
Game &game = Game::NewSingleton();
char enemyName[64];
int enemyType = enemyWeights[opts.difficultyLevel-1][(rand()%10)+1];
//static Animation *enemyAnim = NULL;
if ( status.status != GAMESTATE_PLAYSINGLE && status.status != GAMESTATE_PLAYMULTI )
return;
if ( ((rand()%100)+1 < status.enemySpawnChance) &&
( SDL_GetTicks() - status.enemySpawnInterval) > status.enemyLastSpawned ) {
status.enemyLastSpawned = SDL_GetTicks();
enemy = new Character();
sprintf((char *)&enemyName, "ENEMY FIGHTER %d", enemyType);
enemy->addAnimation(game.getAnimation(std::string((char *)&enemyName)), STATE_DEFAULT);
enemy->addAnimation(game.getAnimation(ANIM_EXPLOSION), STATE_DYING);
enemy->addAnimation(NULL, STATE_DEAD);
enemy->setPosition((Vector){100+(rand()%600), 0, 0});
if ( enemyType == 4 ) {
enemy->setVelocity((Vector){status.enemyVelocity.y, status.enemyVelocity.y, 0});
enemy->addState(STATE_MOVERIGHT);
} else if ( enemyType == 3 ) {
enemy->setVelocity((Vector){status.enemyVelocity.y, status.enemyVelocity.y/2, 0});
} else
enemy->setVelocity((Vector){0, status.enemyVelocity.y, 0});
enemy->addState(STATE_MOVEDOWN);
// the math below yields us one of the four ACTORTYPE_ENEMYx defines.
enemy->setUserType(ACTOR_TEAM_ENEMY | ACTORTYPE_CHARACTER | (ENEMYTYPE_ENEMY1 << (enemyType-1)));
std::cerr << "Creating new enemy with userType " << enemy->getUserType() << " enemy type " << (ENEMYTYPE_ENEMY1 << (enemyType - 1)) << " and animation \"" << (char *)&enemyName << "\"\n";
enemy->damage = 50;
enemy->weaponDamage = 20;
enemy->health = 1;
std::cerr << "Getting enemy animation...\n";
if ( enemyType > 1 )
enemy->projectileAnim = game.getAnimation(ANIM_ENEMYLASERDOUBLE);
else
enemy->projectileAnim = game.getAnimation(ANIM_ENEMYLASERSINGLE);
enemy->projectileSound = SOUNDFILE_ENEMYLASERSHOT;
enemy->deathSound = SOUNDFILE_EXPLOSION;
enemy->score = 100 * enemyType;
enemy->target = player1;
std::cerr << "(SPAWN) curVisibleEnemies[" << opts.difficultyLevel-1 << "][" << enemyType-1 << "] = " << curVisibleEnemies[opts.difficultyLevel-1][enemyType-1] << "\n";
display->addActor(enemy, LAYER_SPRITE1);
display->colliders.push_back(enemy);
}
return;
}
int main(int argc, char *argv[])
{
// -- menu stuff
MenuDisplay menuDisplay;
GameDisplay &gameDisplay = GameDisplay::NewSingleton();
Display2D creditDisplay;
Display2D helpDisplay;
Display2D failDisplay;
MenuDisplay optionDisplay;
HUDDisplay hudDisplay1;
HUDDisplay hudDisplay2;
Actor *hudLivesActor;
Animation *hudLivesAnimation;
//unsigned int lastTimer = SDL_GetTicks();
// -- control stuff
//SDL_Event nextEvent;
// --- gamestate stuff
GameOptions &opts = GameOptions::NewSingleton();
GameStatus &gamestatus = GameStatus::NewSingleton();
Game &myGame = Game::NewSingleton();
std::vector<Character *> collidables;
Player player1;
Player player2;
std::ofstream logfile;
std::map<int, Display2D *> screenList;
myGame.initSDL();
myGame.initVideo(800, 600, 32, SDL_HWSURFACE|SDL_DOUBLEBUF);
srand(time(0));
TTF_Init();
FontRenderer &textengine = FontRenderer::NewSingleton();
textengine.loadFont("fonts/arialbd.ttf", "arial", 30);
textengine.loadFont("fonts/arial.ttf", "arial", 20);
if ( loadSprites() > 0 ) {
exit(1);
}
myGame.newAnimation(ANIM_PLAYERLASERSINGLE)->setStrip(myGame.getSpriteStrip(SPRITEFILE_PLAYERLASER1), 0, 0, (Vector){0,0,0});
myGame.newAnimation(ANIM_PLAYERLASERDOUBLE)->setStrip(myGame.getSpriteStrip(SPRITEFILE_PLAYERLASER2), 0, 0, (Vector){0,0,0});
if ( configureTitleMenu(&menuDisplay) == 1 )
exit(1);
if ( setupGameDisplay(&gameDisplay) == 1 )
exit(1);
if ( setupStaticDisplay(&creditDisplay, BACKGROUNDFILE_CREDITS) == 1 )
exit(1);
if ( setupStaticDisplay(&helpDisplay, BACKGROUNDFILE_HELP) == 1 )
exit(1);
if ( setupStaticDisplay(&failDisplay, BACKGROUNDFILE_FAIL) == 1 )
exit(1);
if ( configureOptionsMenu(&optionDisplay) == 1)
exit(1);
//gameDisplay.addActor(&player1, LAYER_SPRITE3);
//gameDisplay.addActor(&player2, LAYER_SPRITE3);
gameDisplay.setPlayers(&player1, &player2) ;
gameDisplay.colliders.push_back(&player1);
gameDisplay.colliders.push_back(&player2);
hudLivesActor = myGame.newActor(ACTOR_HUDLIVES);
hudLivesAnimation = myGame.newAnimation(ANIM_HUDLIVES);
hudLivesAnimation->setStrip(myGame.getSpriteStrip(SPRITEFILE_PLAYERSHIP3), 0, 0, (Vector){0,0,0});
hudLivesActor->addAnimation(hudLivesAnimation, STATE_NONE);
hudLivesActor->addState(STATE_NONE);
hudDisplay1.initVideo((Vector){0,0,0}, 120, 120, 32, SDL_SWSURFACE);
hudDisplay1.setLivesActor(hudLivesActor);
hudDisplay2.initVideo((Vector){800-120, 0, 0}, 120, 120, 32, SDL_SWSURFACE);
hudDisplay2.setLivesActor(hudLivesActor);
hudDisplay1.setTarget(&player1);
hudDisplay2.setTarget(&player2);
hudDisplay1.setText("PLAYER ONE");
hudDisplay2.setText("PLAYER TWO");
gamestatus.status = GAMESTATE_TITLEMENU;
menuDisplay.setActive(1);
gameDisplay.setActive(0);
creditDisplay.setActive(0);
failDisplay.setActive(0);
helpDisplay.setActive(0);
hudDisplay1.setActive(1);
hudDisplay2.setActive(1);
//myGame.playMusic(MUSICFILE_TITLESCREEN);
if ( initPlayers(&player1, &player2) != 0 ) {
//std::cerr << "I was unable to initialize the players. WTF?\n";
}
opts.musicVolume = 0;
opts.soundVolume = 0;
myGame.setMusicVolume(opts.musicVolume);
myGame.setSoundVolume(opts.soundVolume);
myGame.lockFPS(60);
//SDL_WM_GrabInput(SDL_GRAB_ON);
while ( gamestatus.running == 1 ) {
//opts.playSound = 0;
SDL_PumpEvents();
//std::cerr << "Menu display at " << &menuDisplay << " is active? " << menuDisplay.isActive() << "\n";
//std::cerr << "Game display at " << &gameDisplay << " is active? " << gameDisplay.isActive() << "\n";
//std::cerr << "Gamestate = " << GAMESTATE_TITLEMENU << " menuDisplay.isActive() " << menuDisplay.isActive() << "\n";
//std::cerr << "Game time : " << SDL_GetTicks() << "\n";
if ( player1.lives < 0 && player2.lives < 0 && gamestatus.status != GAMESTATE_FAILSCREEN) {
gamestatus.status = GAMESTATE_FAILSCREEN;
gameDisplay.setActive(0);
failDisplay.setActive(1);
//std::cerr << "Clearing sounds...\n";
myGame.cleanSounds(1);
myGame.haltMusic();
myGame.playMusic(MUSICFILE_FAILSCREEN);
player1.lives = player2.lives = 0;
}
processInput(&menuDisplay, &gameDisplay, &creditDisplay, &helpDisplay, &failDisplay,
&optionDisplay, &player1, &player2, &hudDisplay1, &hudDisplay2);
processMenus(&menuDisplay, &gameDisplay, &creditDisplay, &helpDisplay, &failDisplay,
&optionDisplay, &player1, &player2, &hudDisplay1, &hudDisplay2);
// bottom of event loop
gameDisplay.clampActor(&player1);
gameDisplay.clampActor(&player2);
generateEnemies(&gameDisplay, &player1, &player2);
gameDisplay.runCollisions();
myGame.update();
myGame.finishFrame();
}
exit(0);
}