Import of version 1.1 minus music, sound and graphics.

This commit is contained in:
Guus Sliepen 2011-08-24 14:14:44 +02:00
commit 09b007411c
61 changed files with 14598 additions and 0 deletions

148
code/Starfighter.cpp Normal file
View File

@ -0,0 +1,148 @@
/*
Project: Starfighter
Copyright (C) 2003 Parallel Realities
All Rights Reserved
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "version.h"
#include "Starfighter.h"
int main(int argc, char *argv[])
{
defineGlobals(); // Must do this first!
signed char cheatAttempt = 0;
if (argc > 1)
{
if (strcmp("--help", argv[1]) == 0)
{
printf("\nProject: Starfighter %s\n", VERSION);
printf("Copyright Parallel Realities 2003\n\n");
printf("Additional Commands\n");
printf("\t-noaudio Disables sound and music\n");
printf("\t-mono Mono sound output (best for headphones)\n\n");
printf("www.parallelrealities.co.uk\n");
printf("\n");
exit(0);
}
}
for (int i = 1 ; i < argc ; i++)
{
#if USEPACK
#else
if (strcmp(argv[i], "-nomove") == 0)
{printf("Enemy movement disabled\n"); dev.moveAliens = 0;}
if (strcmp(argv[i], "-nofire") == 0)
{printf("Enemy firing disabled\n"); dev.fireAliens = 0;}
#endif
if (strcmp(argv[i], "-cheat") == 0)
cheatAttempt = 1;
if (strcmp(argv[i], "-noaudio") == 0)
{printf("No Audio\n"); engine.useAudio = 0;}
if (strcmp(argv[i], "-mono") == 0)
{printf("Mono sound output\n"); engine.useAudio = 1;}
}
atexit(cleanUp);
initSystem(); // Opens video mode and sound
loadFont();
if (cheatAttempt)
{
graphics.clearScreen(graphics.black);
graphics.drawString("That doesn't work anymore", -1, 285, FONT_WHITE);
graphics.drawString("Try harder...", -1, 315, FONT_WHITE);
graphics.updateScreen();
SDL_Delay(2000);
graphics.clearScreen(graphics.black);
graphics.updateScreen();
SDL_Delay(500);
}
graphics.freeGraphics();
loadSound();
initWeapons();
initVars();
defineAliens();
graphics.setColorIndexes();
setAllyMessages();
showStory();
// Determine which part of the game we will go to...
int section = 0;
newGame();
/*
currentGame.system = 3;
currentGame.area = 24;
currentGame.shieldUnits = 4;
currentGame.hasWingMate1 = 1;
currentGame.hasWingMate2 = 1;
player.shield = (currentGame.shieldUnits * 25);
player.weaponType[1] = W_LASER;
player.ammo[0] = 1;
weapon[1].ammo[0] = 3;
weapon[1].damage = 5;
weapon[1].reload[0] = 7;
engine.cheatAmmo = 1;
engine.cheatShield = 1;
engine.cheatCash = 1;
updateSystemStatus();
*/
while (true)
{
switch(section)
{
case 0:
section = doTitle();
break;
case 1:
section = galaxyMap();
break;
case 2:
if (currentGame.stationedPlanet == -1) {doCutscene(0);}
section = mainGameLoop();
break;
}
}
//doTitle();
//galaxyMap();
//mainGameLoop();
//doCutscene(2);
//doCredits();
return(0);
}

70
code/Starfighter.h Normal file
View File

@ -0,0 +1,70 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include <string.h>
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_mixer.h"
#include "defs.h"
#include "structs.h"
#include "classes.h"
extern void initSystem();
extern void loadGameGraphics();
extern void loadSound();
extern void initWeapons();
extern void initMissions();
extern void initVars();
extern void showStory();
extern int doTitle();
extern void defineAliens();
extern void loadFont();
extern int galaxyMap();
extern void defineGlobals();
extern void cleanUp();
extern int mainGameLoop();
extern void setAllyMessages();
extern void newGame();
extern void doCredits();
extern void getPlayerInput();
extern void initPlanetMissions(signed char system);
extern void updateSystemStatus();
extern void doCutscene(int scene);
globalEngineVariables engine;
devVariables dev;
Game currentGame;
object player;
mission currentMission;
Graphics graphics;
object enemy[MAX_ALIENS];
Star star[200];
Planet systemPlanet[10];
mission missions[MAX_MISSIONS];
ShopItem shopItems[MAX_SHOPITEMS];
Mix_Chunk *sound[MAX_SOUNDS];
object weapon[MAX_WEAPONS];
object cargo[MAX_CARGO];
event gameEvent[10];
cutMsg cutMessage[10];

200
code/ai.cpp Normal file
View File

@ -0,0 +1,200 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "ai.h"
/*
Some very simple artificial intelligence routines for the aliens.
Shouldn't really be called AI since they just do things at random.
Aliens are assigned various AI types and this routine makes use of them.
Levels of aggression, defence and evasion are all here.
*/
void setEnemyAI(object *theEnemy)
{
// Make friendly craft generally concentrate on smaller fighters
if ((theEnemy->flags & FL_FRIEND) && (theEnemy->target == &enemy[WC_BOSS]))
{
if ((rand() % 5) == 0)
{
theEnemy->target = theEnemy;
theEnemy->thinktime = 0;
return;
}
}
int i = rand() % 10;
float tx = theEnemy->target->x;
float ty = theEnemy->target->y;
int chase = 0; // Chance in 10 of chasing player
int area = 0; // Chance in 10 of moving to an area around the player
int stop = 0; // Chance in 10 of hanging back
int point = 0; // Size of area alien will move into
switch (theEnemy->AIType)
{
case AI_NORMAL:
chase = 3;
point = 6;
stop = 9;
area = 250;
break;
case AI_OFFENSIVE:
chase = 7;
point = 8;
stop = 9;
area = 50;
break;
case AI_DEFENSIVE:
chase = 2;
point = 6;
stop = 8;
area = 300;
break;
case AI_EVASIVE:
chase = 1;
point = 8;
stop = 9;
area = 600;
break;
case AI_WANDER:
chase = -1;
point = 0;
stop = 10;
area = 1200;
break;
}
if (i <= chase)
{
// Chase the target
theEnemy->dx = ((theEnemy->x - tx) / ((300 / theEnemy->speed) + rand() % 100));
theEnemy->dy = ((theEnemy->y - ty) / ((300 / theEnemy->speed) + rand() % 100));
return;
}
else if ((i >= point) && (i <= stop))
{
// Fly to a random point around the target
tx += (rand() % area - (rand() % area * 2));
ty += (rand() % area - (rand() % area * 2));
theEnemy->dx = ((theEnemy->x - tx) / ((300 / theEnemy->speed) + rand() % 100));
theEnemy->dy = ((theEnemy->y - ty) / ((300 / theEnemy->speed) + rand() % 100));
return;
}
else
{
// Hang back
theEnemy->dx = 0;
theEnemy->dy = 0;
return;
}
}
void setKlineAttackMethod(object *theEnemy)
{
theEnemy->maxShield -= 500;
if (theEnemy->maxShield == 0)
theEnemy->flags -= FL_CANNOTDIE;
if (theEnemy->maxShield == 1000)
{
setRadioMessage(FACE_KLINE, "Very good, Bainfield. Now let's get a little more serious...", 1);
theEnemy->weaponType[0] = W_SPREADSHOT;
theEnemy->chance[1] = 40;
}
else if (theEnemy->maxShield == 500)
{
setRadioMessage(FACE_KLINE, "Your ability to stay alive irritates me!! Try dodging some of these!!", 1);
theEnemy->weaponType[0] = W_DIRSHOCKMISSILE;
theEnemy->weaponType[1] = W_DIRSHOCKMISSILE;
theEnemy->chance[0] = 2;
theEnemy->chance[1] = 2;
theEnemy->flags += FL_AIMS;
}
else if (theEnemy->maxShield == 0)
{
setRadioMessage(FACE_KLINE, "ENOUGH!! THIS ENDS NOW!!!", 1);
theEnemy->weaponType[0] = W_AIMED_SHOT;
theEnemy->weaponType[1] = W_MICRO_HOMING_MISSILES;
theEnemy->flags += FL_CANCLOAK;
theEnemy->chance[0] = 100;
theEnemy->chance[1] = 2;
}
theEnemy->shield = 500;
}
/*
This AI is exclusively for Kline.
*/
void setKlineAI(object *theEnemy)
{
// Weapon type change
if ((rand() % 3) == 0)
{
if (currentGame.area != 26)
{
if (theEnemy->flags & FL_AIMS)
theEnemy->flags -= FL_AIMS;
switch(rand() % 2)
{
case 0:
theEnemy->weaponType[0] = W_TRIPLE_SHOT;
break;
case 1:
theEnemy->weaponType[0] = W_AIMED_SHOT;
theEnemy->flags += FL_AIMS;
break;
}
}
}
if (theEnemy->flags & FL_CIRCLES)
theEnemy->flags -= FL_CIRCLES;
if (theEnemy->flags & FL_CONTINUOUS_FIRE)
theEnemy->flags -= FL_CONTINUOUS_FIRE;
if (theEnemy->flags & FL_DROPMINES)
theEnemy->flags -= FL_DROPMINES;
switch(rand() % 10)
{
case 0:
if ((theEnemy->weaponType[0] != W_DIRSHOCKMISSILE) && (theEnemy->weaponType[1] != W_MICRO_HOMING_MISSILES))
theEnemy->flags += FL_CONTINUOUS_FIRE;
theEnemy->dx = ((theEnemy->x - theEnemy->target->x) / ((300 / theEnemy->speed) + rand() % 100));
theEnemy->dy = ((theEnemy->y - theEnemy->target->y) / ((300 / theEnemy->speed) + rand() % 100));
break;
case 1:
case 2:
// Kline only attacks then he is ready!
if ((!(theEnemy->flags & FL_NOFIRE)) && (currentGame.area == 11))
theEnemy->flags += FL_DROPMINES;
break;
case 3:
case 4:
theEnemy->flags += FL_CIRCLES;
break;
default:
setEnemyAI(theEnemy);
break;
}
}

37
code/ai.h Normal file
View File

@ -0,0 +1,37 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_mixer.h"
#include "defs.h"
#include "structs.h"
#include "classes.h"
extern void setRadioMessage(signed char face, char *in, int priority);
extern object enemy[MAX_ALIENS];
extern object player;
extern Game currentGame;

2038
code/aliens.cpp Normal file

File diff suppressed because it is too large Load Diff

58
code/aliens.h Normal file
View File

@ -0,0 +1,58 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_mixer.h"
#include "defs.h"
#include "structs.h"
#include "classes.h"
extern void setEnemyAI(object *theEnemy);
extern void setKlineAI(object *theEnemy);
extern void fireBullet(object *attacker, int weaponType);
extern void addExplosion(float x, float y, int type);
extern void addEngine(object *craft);
extern void fireRay(object *attacker);
extern void addDebris(int x, int y, int amount);
extern void playSound(int sid);
extern int locateDataInPak(char *file, signed char required);
extern object *addCargo(object *owner, int cargoType);
extern void addCollectable(float x, float y, int type, int value, int life);
extern void updateMissionRequirements(int type, int id, int value);
extern void setInfoLine(char *in, int color);
extern void addBullet(object *theWeapon, object *attacker, int y, int dy);
extern void showErrorAndExit(int errorId, char *name);
extern globalEngineVariables engine;
extern devVariables dev;
extern Game currentGame;
extern object player;
extern object enemy[MAX_ALIENS];
extern Graphics graphics;
extern mission currentMission;
extern object weapon[MAX_WEAPONS];
object defEnemy[MAX_DEFALIENS]; // A predefined enemy

136
code/audio.cpp Normal file
View File

@ -0,0 +1,136 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "audio.h"
void playSound(int sid)
{
if ((!currentGame.useSound) || (!engine.useAudio))
return;
switch(sid)
{
case SFX_DEATH:
case SFX_CLOCK:
case SFX_FLY:
case SFX_SHIELDUP:
case SFX_PICKUP:
case SFX_CLOAK:
case SFX_PLASMA2:
case SFX_PLASMA3:
Mix_PlayChannel(-1, sound[sid], 0);
break;
case SFX_PLASMA:
case SFX_LASER:
Mix_PlayChannel(0, sound[sid], 0);
break;
case SFX_ENERGYRAY:
case SFX_MISSILE:
Mix_PlayChannel(1, sound[sid], 0);
break;
case SFX_HIT:
Mix_PlayChannel(4, sound[sid], 0);
break;
case SFX_EXPLOSION:
case SFX_DEBRIS:
case SFX_DEBRIS2:
Mix_PlayChannel(3, sound[sid], 0);
break;
}
}
Mix_Chunk *loadSound(char *filename)
{
Mix_Chunk *chunk;
#if USEPACK
unpack(filename, PAK_WAV);
chunk = Mix_LoadWAV_RW(engine.sdlrw, 1);
#else
chunk = Mix_LoadWAV(filename);
#endif
return chunk;
}
void loadMusic(char *filename)
{
if (Mix_PlayingMusic())
Mix_HaltMusic();
if (engine.music != NULL)
Mix_FreeMusic(engine.music);
#if USEPACK
unpack(filename, PAK_MOD);
char musicFilename[PATH_MAX];
strcpy(musicFilename, "");
sprintf(musicFilename, "%smusic.mod", engine.userHomeDirectory);
engine.music = Mix_LoadMUS(musicFilename);
#else
engine.music = Mix_LoadMUS(filename);
#endif
}
void playRandomTrack()
{
if ((!currentGame.useMusic) || (!engine.useAudio))
return;
int tracks = 0;
char track[][30] = {
"music/Frantic.mod", "music/Artificial.mod", "music/Lunatic.mod", "music/ToxicFriend.mod",
"music/DigitalInferno.mod", "music/TempoTrance.mod", "music/IntoTheMachine.mod"
};
switch(currentGame.system)
{
case 0:
tracks = 3;
break;
case 1:
tracks = 5;
break;
case 2:
case 3:
tracks = 7;
break;
}
switch(currentGame.area)
{
case 5:
case 11:
case 18:
case 25:
loadMusic("music/HardTranceDub.mod");
break;
case 26:
loadMusic("music/LoopsAndTings.mod");
break;
default:
loadMusic(track[rand() % tracks]);
}
Mix_PlayMusic(engine.music, -1);
}

36
code/audio.h Normal file
View File

@ -0,0 +1,36 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include <string.h>
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_mixer.h"
#include "defs.h"
#include "structs.h"
extern void unpack(char *file, signed char fileType);
extern void freePackBuffer();
extern globalEngineVariables engine;
extern Game currentGame;
extern Mix_Chunk *sound[MAX_SOUNDS];

797
code/bullets.cpp Normal file
View File

@ -0,0 +1,797 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "bullets.h"
void addBullet(object *theWeapon, object *attacker, int y, int dy)
{
object *bullet;
signed char imageIndex;
int tempX, tempY, steps;
bullet = new object;
if (attacker == &player)
currentGame.shots++;
bullet->next = NULL;
bullet->active = 1;
bullet->x = attacker->x - ((attacker->image[0]->w / 2) * attacker->face);
bullet->y = attacker->y + y;
bullet->flags = theWeapon->flags;
bullet->shield = 300; // bullets live for (approximately) 5 seconds
// Timed explosions live between 1 and 3 seconds
if (bullet->flags & WF_TIMEDEXPLOSION)
bullet->shield = 60 + ((rand() % 3) * 60);
if (attacker->face == 0)
{
bullet->dx = theWeapon->speed;
if ((currentGame.area == 18) || (currentGame.area == 24))
bullet->dx += fabs(engine.ssx);
}
else
{
bullet->dx = (0 - theWeapon->speed);
}
if (bullet->flags & WF_VARIABLE_SPEED)
{
bullet->dx = Math::rrand(100, 200);
bullet->dx /= 10;
if (attacker->face == 1)
bullet->dx = 0 - bullet->dx;
}
bullet->dy = dy;
if (bullet->flags & WF_SCATTER)
{
bullet->dy = Math::rrand(-200, 200);
if (bullet->dy != 0)
bullet->dy /= 200;
}
if (attacker->flags & FL_WEAPCO)
bullet->flags += WF_WEAPCO;
else
bullet->flags += WF_FRIEND;
bullet->owner = attacker->owner;
bullet->id = theWeapon->id;
bullet->damage = theWeapon->damage;
if (bullet->id == WT_CHARGER)
{
bullet->damage = attacker->ammo[1];
if (bullet->damage < 50)
{
bullet->damage = 1;
bullet->id = WT_PLASMA;
}
}
bullet->target = NULL;
if (attacker->flags & FL_FRIEND)
imageIndex = 0;
else
imageIndex = 1;
// Use the enemy's images if applicable
if (bullet->id != WT_ROCKET)
bullet->image[0] = theWeapon->image[imageIndex];
else
bullet->image[0] = theWeapon->image[attacker->face];
if (bullet->flags & WF_AIMED)
{
tempX = (int)fabs(attacker->target->x - attacker->x);
tempY = (int)fabs(attacker->target->y - attacker->y);
steps = max(tempX, tempY);
if (steps == 0)
steps = 12;
if (!(bullet->flags & WF_TIMEDEXPLOSION))
steps /= 8;
else
steps /= 6 + (rand() % 6);
tempX = (int)(attacker->target->x - attacker->x);
tempY = (int)(attacker->target->y - attacker->y);
bullet->dx = tempX / steps;
bullet->dy = tempY / steps;
}
if (attacker->classDef == CD_ASTEROID)
{
bullet->dx = Math::rrand(-20, 20);
bullet->dy = Math::rrand(-20, 20);
bullet->image[0] = graphics.shape[4];
}
engine.bulletTail->next = bullet;
engine.bulletTail = bullet;
}
/*
Fill in later...
*/
void fireBullet(object *attacker, int weaponType)
{
if (attacker->reload[weaponType] > 0)
return;
int y = (attacker->image[0]->h) / 5;
// Remove some ammo from the player
if ((attacker == &player) && (weaponType == 1) && (!engine.cheatAmmo))
player.ammo[1]--;
object *theWeapon = &weapon[attacker->weaponType[weaponType]];
switch(theWeapon->id)
{
case WT_PLASMA:
case WT_SPREAD:
case WT_DIRECTIONAL:
playSound(SFX_PLASMA);
break;
case WT_ROCKET:
playSound(SFX_MISSILE);
break;
case WT_LASER:
playSound(SFX_LASER);
break;
case WT_CHARGER:
playSound(SFX_PLASMA3);
break;
}
if (theWeapon->flags & WF_STRAIGHT)
{
switch (theWeapon->ammo[0])
{
case 1:
addBullet(theWeapon, attacker, y * 3, 0);
break;
case 2:
addBullet(theWeapon, attacker, y * 2, 0);
addBullet(theWeapon, attacker, y * 4, 0);
break;
case 3:
addBullet(theWeapon, attacker, y * 2, 0);
addBullet(theWeapon, attacker, y * 3, 0);
addBullet(theWeapon, attacker, y * 4, 0);
break;
case 4:
addBullet(theWeapon, attacker, y, 0);
addBullet(theWeapon, attacker, y * 2, 0);
addBullet(theWeapon, attacker, y * 4, 0);
addBullet(theWeapon, attacker, y * 5, 0);
break;
case 5:
for (int i = 1 ; i < 6; i++)
addBullet(theWeapon, attacker, y * i, 0);
break;
}
}
else if (theWeapon->flags & WF_THIN_SPREAD)
{
addBullet(theWeapon, attacker, y * 2, -1);
if (theWeapon->ammo[0] == 3)
{
addBullet(theWeapon, attacker, y * 3, 0);
}
else
{
addBullet(theWeapon, attacker, y * 2, 0);
addBullet(theWeapon, attacker, y * 4, 0);
}
addBullet(theWeapon, attacker, y * 4, 1);
}
else if (theWeapon->flags & WF_WIDE_SPREAD)
{
addBullet(theWeapon, attacker, y * 1, -2);
addBullet(theWeapon, attacker, y * 2, -1);
addBullet(theWeapon, attacker, y * 3, 0);
addBullet(theWeapon, attacker, y * 4, 1);
addBullet(theWeapon, attacker, y * 5, 2);
}
// Reset the weapon reload time. Double it if it is not friendly or a boss or Kline
attacker->reload[weaponType] = theWeapon->reload[0];
if ((attacker->flags & FL_WEAPCO) && (attacker != &enemy[WC_BOSS]) && (attacker != &enemy[WC_KLINE]) && (theWeapon->id != W_LASER))
attacker->reload[weaponType] *= 2;
if ((engine.cheatAmmo) || (theWeapon->id == WT_LASER))
return;
if ((attacker == &player) && (weaponType == 0))
{
if (player.ammo[0] > 0)
{
player.ammo[0]--;
if (player.ammo[0] == 0)
{
player.weaponType[0] = W_PLAYER_WEAPON;
weapon[W_PLAYER_WEAPON2] = weapon[W_PLAYER_WEAPON]; // reset to weapon 1 defaults
}
}
}
}
/*
Used for homing missiles. When a missile is active and it is told to home in
on an enemy, it will attempt to randomly grab one every frame if it does not
already have a target. If the target it is currently chasing is killed, it will
begin to look for a new one (done in doBullets()). The homing missile will make
one attempt per call (one call per frame) to find a suitable target. If the target
it picks is dead or outside the screen range, then it returns NULL. A suitable
target will be returned as the object address.
*/
object *getRandomEnemy(object *bullet)
{
int i;
if (bullet->owner->flags & FL_WEAPCO)
{
i = (rand() % 10);
if (i < 1)
return &player;
}
i = rand() % MAX_ALIENS;
if ((enemy[i].shield < 1) || (!enemy[i].active))
return NULL;
if ((bullet->owner->flags & FL_WEAPCO) && (enemy[i].flags & FL_WEAPCO))
return NULL;
if ((bullet->owner->flags & FL_FRIEND) && (enemy[i].flags & FL_FRIEND))
return NULL;
if (abs((int)bullet->x - (int)enemy[i].target->x) > 800)
return NULL;
if (abs((int)bullet->y - (int)enemy[i].target->y) > 200)
return NULL;
return &enemy[i];
}
/*
Fill in later...
*/
void destroyAlien(object *bullet, object *theEnemy)
{
playSound(SFX_EXPLOSION);
// Chain reaction destruction if needed
if (theEnemy->flags & FL_DAMAGEOWNER)
{
theEnemy->owner->shield -= theEnemy->maxShield;
if (theEnemy->owner->shield < 1)
destroyAlien(bullet, theEnemy->owner);
}
if (theEnemy->flags & FL_FRIEND)
{
if (theEnemy->classDef == CD_PHOEBE)
currentGame.wingMate1Ejects++;
else if (theEnemy->classDef == CD_URSULA)
currentGame.wingMate2Ejects++;
// Phoebe cannot eject on the rescue mission
if (currentGame.area != 7)
{
if ((theEnemy->classDef == CD_PHOEBE) || (theEnemy->classDef == CD_URSULA))
setInfoLine(">> Ally has ejected! <<\n", FONT_RED);
else
setInfoLine(">> Friendly craft has been destroy!! <<\n", FONT_RED);
}
}
if (bullet->owner == &player)
{
// Once again, stop point leeching
if (currentGame.area != MAX_MISSIONS - 1)
currentGame.cash += theEnemy->score;
currentGame.cashEarned += theEnemy->score;
currentGame.totalKills++;
}
else if (bullet->owner->classDef == CD_PHOEBE)
{
currentGame.wingMate1Kills++;
}
else if (bullet->owner->classDef == CD_URSULA)
{
currentGame.wingMate2Kills++;
}
else
{
currentGame.totalOtherKills++;
}
if ((bullet->owner->classDef == CD_PHOEBE) || (bullet->owner->classDef == CD_URSULA))
{
if ((rand() % 8) == 0)
{
getKillMessage(bullet->owner);
}
}
updateMissionRequirements(M_DESTROY_TARGET_TYPE, theEnemy->classDef, 1);
updateMissionRequirements(M_PROTECT_TARGET, theEnemy->classDef, 1);
if (rand() % 100 <= theEnemy->collectChance)
{
unsigned char value;
if ((rand() % 10) == 0)
theEnemy->collectValue *= 2;
while (theEnemy->collectValue > 0)
{
value = (10 + (rand() % theEnemy->collectValue));
if (value > theEnemy->collectValue)
value =theEnemy->collectValue;
addCollectable(theEnemy->x, theEnemy->y, theEnemy->collectType, value, 600);
theEnemy->collectValue -= value;
}
}
// Make it explode immediately
if (theEnemy->classDef == CD_ASTEROID)
{
theEnemy->shield = -999;
if ((currentGame.area == 10) && (theEnemy != &enemy[0]) && (currentMission.completed1[0] == 0) && (currentMission.targetValue1[1] == 1))
engine.targetArrowTimer = 120;
}
if ((theEnemy->classDef == CD_KRASS) && (bullet->owner == &player))
setRadioMessage(FACE_CHRIS, "My NAME is CHRIS!!!!!!!!", 1);
if (theEnemy->classDef == CD_KLINE)
{
setRadioMessage(FACE_KLINE, "It was an honor... to have fought you...", 1);
theEnemy->dx = theEnemy->dy = 0;
theEnemy->maxShield = 1500;
theEnemy->shield = -200;
}
}
char checkPlayerShockDamage(float x, float y, int radius)
{
// Don't let the player be hurt by an explosion after they have completed
// all the mission objectives. That would be *really* annoying!
if ((engine.cheatShield) || (engine.missionCompleteTimer != 0))
return 0;
float distX = fabs(x - player.x);
float distY = fabs(y - player.y);
if ((distX <= 50) && (distY <= 50))
{
if (distX >= 1)
distX /= 5;
if (distY >= 1)
distY /= 5;
player.shield -= (int)(10 - distX);
player.shield -= (int)(10 - distY);
Math::limitInt(&player.shield, 0, player.maxShield);
player.hit = 10;
return 1;
}
return 0;
}
/*
Fill in later...
*/
void fireRay(object *attacker)
{
SDL_Rect ray;
if (attacker->face == 0)
{
ray.x = (int)(attacker->x + attacker->image[0]->w);
}
else
{
ray.x = (int)(attacker->x - 800);
}
ray.y = (int)(attacker->y + attacker->engineY - 1);
ray.h = 3;
ray.w = 800;
int red = SDL_MapRGB(graphics.screen->format, rand() % 256, 0x00, 0x00);
SDL_FillRect(graphics.screen, &ray, red);
graphics.addBuffer(ray.x, ray.y, ray.w, ray.h);
if (attacker != &player)
{
if (player.shield > 0)
{
if (Collision::collision(player.x, player.y, player.image[0]->w, player.image[0]->h, ray.x, ray.y, ray.w, ray.h) && (!engine.cheatShield))
{
if (player.shield > engine.lowShield)
{
if (player.shield - 1 <= engine.lowShield)
{
setInfoLine("!!! WARNING: SHIELD LOW !!!", FONT_RED);
}
}
player.shield--;
addExplosion(player.x, player.y, E_SMALL_EXPLOSION);
playSound(SFX_HIT);
if (player.shield < 1)
{
playSound(SFX_DEATH);
playSound(SFX_EXPLOSION);
}
}
}
}
object *anEnemy = enemy;
for (int i = 0 ; i < MAX_ALIENS ; i++)
{
if (anEnemy->flags & FL_IMMORTAL)
continue;
if ((anEnemy->shield > 0) && (attacker != anEnemy) && (attacker->classDef != anEnemy->classDef))
{
if (Collision::collision(anEnemy->x, anEnemy->y, anEnemy->image[0]->w, anEnemy->image[0]->h, ray.x, ray.y, ray.w, ray.h))
{
anEnemy->shield--;
addExplosion(anEnemy->x, anEnemy->y, E_SMALL_EXPLOSION);
playSound(SFX_HIT);
if (anEnemy->shield < 1)
{
destroyAlien(attacker, anEnemy);
}
}
}
*anEnemy++;
}
attacker->ammo[0]--;
if (attacker->ammo[0] < 1)
attacker->flags -= FL_FIRERAY;
}
/*
This handles active bullets in a linked list. The current bullet and
previous bullet pointers are first assigned to the main header bullet
and each successive bullet is pulled out. Bullets are moved in their
delta coordinates, with rockets having fire trails added to them. Seperate
collision checks are done for a bullet that belongs to the enemy and one
that belongs to a player. However rockets can hit anyone. Upon an enemy
being killed, mission requirements are checked and collectables are randomly
spawned.
*/
void doBullets()
{
object *bullet = engine.bulletHead;
object *prevBullet = engine.bulletHead;
engine.bulletTail = engine.bulletHead;
object *theEnemy, *theCargo;
signed char okayToHit = 0;
float homingMissileSpeed = 0;
while (bullet->next != NULL)
{
bullet = bullet->next;
if (bullet->active == 1)
{
if (bullet->flags & WF_HOMING)
{
if (bullet->target == NULL)
bullet->target = getRandomEnemy(bullet);
if (bullet->owner->flags & FL_FRIEND)
homingMissileSpeed = 0.25;
else
homingMissileSpeed = 0.05;
}
if (bullet->id == WT_ROCKET)
{
addExplosion(bullet->x, bullet->y, E_SMALL_EXPLOSION);
}
else if (bullet->id == WT_MICROROCKET)
{
addExplosion(bullet->x, bullet->y, E_TINY_EXPLOSION);
}
if ((bullet->flags & WF_AIMED) || (bullet->flags & WF_THIN_SPREAD))
{
graphics.blit(bullet->image[0], (int)(bullet->x - bullet->dx), (int)(bullet->y - bullet->dy));
}
if (bullet->id == WT_CHARGER)
{
for (int i = 0 ; i < bullet->damage ; i++)
graphics.blit(bullet->image[0], (int)(bullet->x - Math::rrand(-(bullet->damage / 3), 0)), (int)(bullet->y + Math::rrand(-3, 3)));
}
graphics.blit(bullet->image[0], (int)bullet->x, (int)bullet->y);
bullet->x += bullet->dx;
bullet->y += bullet->dy;
if (bullet->target != NULL)
{
if (bullet->x < bullet->target->x)
Math::limitFloat(&(bullet->dx += homingMissileSpeed), -15, 15);
if (bullet->x > bullet->target->x)
Math::limitFloat(&(bullet->dx -= homingMissileSpeed), -15, 15);
//Rocket is (more or less) inline with target. Fly straight
if ((bullet->x > bullet->target->x - 1) && (bullet->x < bullet->target->x + 5))
bullet->dx = 0;
if (bullet->y < bullet->target->y)
Math::limitFloat(&(bullet->dy += homingMissileSpeed), -15, 15);
if (bullet->y > bullet->target->y)
Math::limitFloat(&(bullet->dy -= homingMissileSpeed), -15, 15);
//Rocket is (more or less) inline with target. Fly straight
if ((bullet->y > bullet->target->y - 1) && (bullet->y < bullet->target->y + 5))
bullet->dy = 0;
if ((bullet->target->shield < 1) || (bullet->target->flags & FL_ISCLOAKED))
bullet->target = NULL;
}
bullet->x += engine.ssx;
bullet->y += engine.ssy;
for (int i = 0 ; i < MAX_ALIENS ; i++)
{
theEnemy = &enemy[i];
if ((theEnemy->shield < 1) || (!theEnemy->active))
continue;
okayToHit = 0;
if ((bullet->flags & WF_FRIEND) && (theEnemy->flags & FL_WEAPCO))
okayToHit = 1;
if ((bullet->flags & WF_WEAPCO) && (theEnemy->flags & FL_FRIEND))
okayToHit = 1;
if ((bullet->id == WT_ROCKET) || (bullet->id == WT_LASER) || (bullet->id == WT_CHARGER))
okayToHit = 1;
if (bullet->owner == theEnemy->owner)
okayToHit = 0;
if (okayToHit)
{
if ((bullet->active == 1) && (Collision::collision(bullet, theEnemy)))
{
if (bullet->owner == &player)
{
currentGame.hits++;
if ((theEnemy->classDef == CD_PHOEBE) || (theEnemy->classDef == CD_URSULA))
getMissFireMessage(theEnemy);
}
if (!(theEnemy->flags & FL_IMMORTAL))
{
if (!(bullet->flags & WF_DISABLE))
theEnemy->shield -= bullet->damage;
else
theEnemy->systemPower -= bullet->damage;
theEnemy->hit = 5;
}
if (theEnemy->flags & FL_CANNOTDIE)
{
Math::limitInt(&theEnemy->shield, 1, theEnemy->maxShield);
if (theEnemy->shield == 1)
{
if (currentGame.area != 26)
{
if (!(theEnemy->flags & FL_LEAVESECTOR))
{
theEnemy->flags += FL_LEAVESECTOR;
if (theEnemy->flags & FL_CIRCLES)
theEnemy->flags -= FL_CIRCLES;
if (currentGame.area == 11)
setRadioMessage(FACE_KLINE, "Seems I underestimated you, Bainfield! We'll meet again!", 1);
else if (currentGame.area == 25)
setRadioMessage(FACE_SID, "Chris, Kethlan is getting away!", 1);
}
}
else
{
setKlineAttackMethod(theEnemy);
}
}
}
if ((theEnemy->flags & FL_RUNSAWAY) && ((rand() % 50) == 0))
{
if (!(theEnemy->flags & FL_LEAVESECTOR))
theEnemy->flags += FL_LEAVESECTOR;
}
if (bullet->id != WT_CHARGER)
{
bullet->active = 0;
bullet->shield = 0;
}
else if (bullet->id == WT_CHARGER)
{
bullet->shield -= theEnemy->shield;
if (bullet->shield < 0)
bullet->active = 0;
}
playSound(SFX_HIT);
if (theEnemy->AIType == AI_EVASIVE)
theEnemy->thinktime = 0;
if (theEnemy->shield < 1)
destroyAlien(bullet, theEnemy);
if (theEnemy->systemPower < 1)
{
if (!(theEnemy->flags & FL_DISABLED))
{
theEnemy->flags += FL_DISABLED;
updateMissionRequirements(M_DISABLE_TARGET, theEnemy->classDef, 1);
}
theEnemy->systemPower = 0;
if (theEnemy->classDef == CD_KLINE)
theEnemy->systemPower = theEnemy->maxShield;
}
if (bullet->id == WT_ROCKET)
addExplosion(bullet->x, bullet->y, E_BIG_EXPLOSION);
else
addExplosion(bullet->x, bullet->y, E_SMALL_EXPLOSION);
}
}
}
// Check for bullets hitting player
if ((bullet->flags & WF_WEAPCO) || (bullet->id == WT_ROCKET) || (bullet->id == WT_LASER) || (bullet->id == WT_CHARGER))
{
if ((bullet->active == 1) && (player.shield > 0) && (Collision::collision(bullet, &player)) && (bullet->owner != &player))
{
if ((!engine.cheatShield) || (engine.missionCompleteTimer != 0))
{
if (player.shield > engine.lowShield)
{
if (player.shield - bullet->damage <= engine.lowShield)
{
setInfoLine("!!! WARNING: SHIELD LOW !!!", FONT_RED);
}
}
player.shield -= bullet->damage;
Math::limitInt(&player.shield, 0, player.maxShield);
player.hit = 5;
}
if ((bullet->owner->classDef == CD_PHOEBE) || (bullet->owner->classDef == CD_URSULA))
getPlayerHitMessage(bullet->owner);
if (bullet->id != WT_CHARGER)
{
bullet->active = 0;
bullet->shield = 0;
}
else if (bullet->id == WT_CHARGER)
{
bullet->shield -= theEnemy->shield;
if (bullet->shield < 0)
bullet->active = 0;
}
playSound(SFX_HIT);
if (bullet->id == WT_ROCKET)
addExplosion(bullet->x, bullet->y, E_BIG_EXPLOSION);
else
addExplosion(bullet->x, bullet->y, E_SMALL_EXPLOSION);
}
}
}
if (((bullet->owner == &player)) || (bullet->id == WT_ROCKET))
{
for (int j = 0 ; j < 20 ; j++)
{
theCargo = &cargo[j];
if (theCargo->active)
{
if (Collision::collision(bullet, theCargo))
{
bullet->active = 0;
addExplosion(bullet->x, bullet->y, E_SMALL_EXPLOSION);
playSound(SFX_HIT);
if (theCargo->collectType != P_PHOEBE)
{
theCargo->active = 0;
playSound(SFX_EXPLOSION);
for (int i = 0 ; i < 10 ; i++)
addExplosion(theCargo->x + Math::rrand(-15, 15), theCargo->y + Math::rrand(-15, 15), E_BIG_EXPLOSION);
updateMissionRequirements(M_PROTECT_PICKUP, P_CARGO, 1);
}
}
}
}
}
// check to see if a bullet (on any side) hits a mine
checkMineBulletCollisions(bullet);
bullet->shield--;
if (bullet->shield < 1)
{
if ((bullet->flags & WF_TIMEDEXPLOSION) || (bullet->id == WT_CHARGER))
{
playSound(SFX_EXPLOSION);
for (int i = 0 ; i < 10 ; i++)
addExplosion(bullet->x + Math::rrand(-35, 35), bullet->y + Math::rrand(-35, 35), E_BIG_EXPLOSION);
if (bullet->flags & WF_TIMEDEXPLOSION)
if (checkPlayerShockDamage(bullet->x, bullet->y, 75))
setInfoLine("Warning: Missile Shockwave Damage!!", FONT_RED);
}
bullet->active = 0;
}
if (bullet->active == 1)
{
prevBullet = bullet;
engine.bulletTail = bullet;
}
else
{
prevBullet->next = bullet->next;
delete bullet;
bullet = prevBullet;
}
}
}

54
code/bullets.h Normal file
View File

@ -0,0 +1,54 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_mixer.h"
#include "defs.h"
#include "structs.h"
#include "classes.h"
extern void playSound(int sid);
extern void updateMissionRequirements(int type, int id, int value);
extern void addCollectable(float x, float y, int type, int value, int life);
extern void addExplosion(float x, float y, int type);
extern void generateShockWave(object *bullet);
extern void setInfoLine(char *in, int color);
extern void getKillMessage(object *ally);
extern void getMissFireMessage(object *ally);
extern void getPlayerHitMessage(object *ally);
extern void checkMineBulletCollisions(object *bullet);
extern void setKlineAttackMethod(object *theEnemy);
extern void setRadioMessage(signed char face, char *in, int priority);
extern globalEngineVariables engine;
extern devVariables dev;
extern object weapon[MAX_WEAPONS];
extern object player;
extern mission currentMission;
extern object enemy[MAX_ALIENS];
extern object cargo[20];
extern Game currentGame;
extern Graphics graphics;

120
code/cargo.cpp Normal file
View File

@ -0,0 +1,120 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "cargo.h"
void initCargo()
{
for (int i = 0 ; i < MAX_CARGO ; i++)
{
cargo[i].active = 0;
cargo[i].owner = NULL;
}
}
/*
* I think you all know what this does by now! ;)
*/
int getCargo()
{
for (int i = 0 ; i < MAX_CARGO ; i++)
{
if (cargo[i].active == 0)
return i;
}
return -1;
}
object *addCargo(object *owner, int cargoType)
{
int index = getCargo();
if (index == -1)
return NULL;
cargo[index].active = 1;
cargo[index].owner = owner;
cargo[index].x = owner->x;
cargo[index].y = owner->y;
cargo[index].dx = 0;
cargo[index].dy = 0;
cargo[index].collectType = cargoType;
cargo[index].image[0] = graphics.shape[32];
if (cargoType == P_PHOEBE)
cargo[index].image[0] = graphics.shipShape[20];
return &cargo[index];
}
void becomeCollectable(int i)
{
if (cargo[i].collectType != P_PHOEBE)
{
addCollectable(cargo[i].x, cargo[i].y, cargo[i].collectType, 1, 600);
}
else
{
enemy[FR_PHOEBE].active = 1;
enemy[FR_PHOEBE].x = cargo[i].x;
enemy[FR_PHOEBE].y = cargo[i].y;
setRadioMessage(FACE_PHOEBE, "Thanks!! Watch out, WEAPCO! Phoebe's loose and she's ANGRY!!!", 1);
}
cargo[i].active = 0;
}
void doCargo()
{
float dx, dy, chainX, chainY;
for (int i = 0 ; i < MAX_CARGO ; i++)
{
if (cargo[i].active)
{
if (!cargo[i].owner->active)
{
becomeCollectable(i);
continue;
}
graphics.blit(cargo[i].image[0], (int)cargo[i].x, (int)cargo[i].y);
cargo[i].x += engine.ssx;
cargo[i].y += engine.ssy;
Math::limitFloat(&cargo[i].x, cargo[i].owner->x - 50, cargo[i].owner->x + 50);
Math::limitFloat(&cargo[i].y, cargo[i].owner->y - 50, cargo[i].owner->y + 50);
dx = (cargo[i].x - cargo[i].owner->x) / 10;
dy = (cargo[i].y - cargo[i].owner->y) / 10;
chainX = cargo[i].x - cargo[i].dx;
chainY = cargo[i].y - cargo[i].dy;
// draw the chain link line
for (int j = 0 ; j < 10 ; j++)
{
graphics.blit(graphics.shape[30], (int)chainX, (int)chainY);
chainX -= dx;
chainY -= dy;
}
}
}
}

40
code/cargo.h Normal file
View File

@ -0,0 +1,40 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include <string.h>
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_mixer.h"
#include "defs.h"
#include "structs.h"
#include "classes.h"
extern void addCollectable(float x, float y, int type, int value, int life);
extern void setRadioMessage(signed char face, char *in, int priority);
extern globalEngineVariables engine;
extern Game currentGame;
extern Graphics graphics;
extern object enemy[MAX_ALIENS];
extern object player;
extern object cargo[MAX_CARGO];

710
code/classes.h Normal file
View File

@ -0,0 +1,710 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
extern void showErrorAndExit(int errorId, char *name);
class Collision {
private:
Collision(){}
public:
static signed char collision(float x0, float y0, int w0, int h0, float x2, float y2, int w1, int h1)
{
float x1 = x0 + w0;
float y1 = y0 + h0;
float x3 = x2 + w1;
float y3 = y2 + h1;
return !(x1<x2 || x3<x0 || y1<y2 || y3<y0);
}
static signed char collision(object *object1, object *object2)
{
float x0 = object1->x;
float y0 = object1->y;
float w0 = object1->image[0]->w;
float h0 = object1->image[0]->h;
float x2 = object2->x;
float y2 = object2->y;
float w1 = object2->image[0]->w;
float h1 = object2->image[0]->h;
float x1 = x0 + w0;
float y1 = y0 + h0;
float x3 = x2 + w1;
float y3 = y2 + h1;
return !(x1<x2 || x3<x0 || y1<y2 || y3<y0);
}
static signed char collision(collectables *object1, object *object2)
{
float x0 = object1->x;
float y0 = object1->y;
float w0 = object1->image->w;
float h0 = object1->image->h;
float x2 = object2->x;
float y2 = object2->y;
float w1 = object2->image[0]->w;
float h1 = object2->image[0]->h;
float x1 = x0 + w0;
float y1 = y0 + h0;
float x3 = x2 + w1;
float y3 = y2 + h1;
return !(x1<x2 || x3<x0 || y1<y2 || y3<y0);
}
};
class Math {
private:
Math(){}
public:
static void limitChar(signed char *in, int low, int high)
{
if (*in < low)
*in = low;
if (*in > high)
*in = high;
}
static void limitChar(unsigned char *in, int low, int high)
{
if (*in < low)
*in = low;
if (*in > high)
*in = high;
}
static void limitInt(int *in, int low, int high)
{
if (*in < low)
*in = low;
if (*in > high)
*in = high;
}
static void limitFloat(float *in, float low, float high)
{
if (*in < low)
*in = low;
if (*in > high)
*in = high;
}
static void wrapChar(signed char *in, signed char low, signed char high)
{
if (*in < low)
*in = high;
if (*in > high)
*in = low;
}
static void wrapInt(int *in, int low, int high)
{
if (*in < low)
*in = high;
if (*in > high)
*in = low;
}
static void wrapFloat(float *in, float low, float high)
{
if (*in < low)
*in = high;
if (*in > high)
*in = low;
}
static int rrand(int min, int max)
{
int r = min;
max++;
if ((max - min) == 0)
return min;
r += rand() % (max - min);
return r;
}
};
class Graphics {
public:
Uint32 red;
Uint32 darkRed;
Uint32 yellow;
Uint32 darkYellow;
Uint32 green;
Uint32 darkGreen;
Uint32 blue;
Uint32 darkBlue;
Uint32 darkerBlue;
Uint32 black;
Uint32 white;
Uint32 lightGrey;
Uint32 darkGrey;
SDL_Surface *screen, *background;
SDL_Surface *shape[MAX_SHAPES];
SDL_Surface *shipShape[MAX_SHIPSHAPES];
SDL_Surface *fontShape[MAX_FONTSHAPES];
SDL_Surface *shopSurface[MAX_SHOPSHAPES];
bRect *bufferHead;
bRect *bufferTail;
textObject textShape[MAX_TEXTSHAPES];
SDL_Rect blitRect;
SDL_Surface *messageBox;
Graphics()
{
bufferHead = new bRect;
bufferHead->next = NULL;
bufferTail = bufferHead;
for (int i = 0 ; i < MAX_SHAPES ; i++)
shape[i] = NULL;
for (int i = 0 ; i < MAX_SHIPSHAPES ; i++)
shipShape[i] = NULL;
for (int i = 0 ; i < MAX_TEXTSHAPES ; i++)
textShape[i].image = NULL;
for (int i = 0 ; i < MAX_SHOPSHAPES ; i++)
shopSurface[i] = NULL;
background = NULL;
messageBox = NULL;
}
SDL_Surface *setTransparent(SDL_Surface *sprite)
{
SDL_SetColorKey(sprite, (SDL_SRCCOLORKEY|SDL_RLEACCEL), SDL_MapRGB(sprite->format, 0, 0, 0));
return sprite;
}
void addBuffer(int x, int y, int w, int h)
{
bRect *rect = new bRect;
rect->next = NULL;
rect->x = x;
rect->y = y;
rect->w = w;
rect->h = h;
bufferTail->next = rect;
bufferTail = rect;
}
void blit(SDL_Surface *image, int x, int y, SDL_Surface *dest)
{
// Set up a rectangle to draw to
blitRect.x = x;
blitRect.y = y;
blitRect.w = image->w;
blitRect.h = image->h;
/* Blit onto the screen surface */
if(SDL_BlitSurface(image, NULL, dest, &blitRect) < 0)
{
printf("BlitSurface error: %s\n", SDL_GetError());
showErrorAndExit(2, "");
}
addBuffer(blitRect.x, blitRect.y, blitRect.w, blitRect.h);
}
void blit(SDL_Surface *image, int x, int y)
{
blit(image, x, y, screen);
}
void blitText(int i)
{
blit(textShape[i].image, (int)textShape[i].x, (int)textShape[i].y, screen);
}
void flushBuffer()
{
bRect *prevRect = bufferHead;
bRect *rect = bufferHead;
bufferTail = bufferHead;
while (rect->next != NULL)
{
rect = rect->next;
prevRect->next = rect->next;
delete rect;
rect = prevRect;
}
bufferHead->next = NULL;
}
void unBuffer()
{
bRect *prevRect = bufferHead;
bRect *rect = bufferHead;
bufferTail = bufferHead;
while (rect->next != NULL)
{
rect = rect->next;
blitRect.x = rect->x;
blitRect.y = rect->y;
blitRect.w = rect->w;
blitRect.h = rect->h;
if (SDL_BlitSurface(background, &blitRect, screen, &blitRect) < 0)
{
printf("BlitSurface error: %s\n", SDL_GetError());
showErrorAndExit(2, "");
}
prevRect->next = rect->next;
delete rect;
rect = prevRect;
}
bufferHead->next = NULL;
}
/*
In 16 bit mode this is slow. VERY slow. Don't write directly to a surface
that constantly needs updating (eg - the main game screen)
*/
int renderString(char *in, int x, int y, int fontColor, signed char wrap, SDL_Surface *dest)
{
SDL_Rect area;
area.x = x;
area.y = y;
area.w = 8;
area.h = 14;
SDL_Rect letter;
letter.y = 0;
letter.w = 8;
letter.h = 14;
while (*in != '\0')
{
if (*in != 32)
{
letter.x = (*in - 33);
letter.x *= 8;
letter.x--; // Temp fix
/* Blit onto the screen surface */
if(SDL_BlitSurface(fontShape[fontColor], &letter, dest, &area) < 0)
{
printf("BlitSurface error: %s\n", SDL_GetError());
showErrorAndExit(2, "");
}
}
area.x += 9;
if (wrap)
{
if ((area.x > (dest->w - 70)) && (*in == 32))
{
area.y += 16;
area.x = x;
}
}
*in++;
}
return area.y;
}
int drawString(char *in, int x, int y, int fontColor, signed char wrap, SDL_Surface *dest)
{
renderString(in, x, y - 1, FONT_OUTLINE, wrap, dest);
renderString(in, x, y + 1, FONT_OUTLINE, wrap, dest);
renderString(in, x, y + 2, FONT_OUTLINE, wrap, dest);
renderString(in, x - 1, y, FONT_OUTLINE, wrap, dest);
renderString(in, x - 2, y, FONT_OUTLINE, wrap, dest);
renderString(in, x + 1, y, FONT_OUTLINE, wrap, dest);
return renderString(in, x, y, fontColor, wrap, dest);
}
int drawString(char *in, int x, int y, int fontColor, SDL_Surface *dest)
{
if (x == -1)
x = (dest->w - (strlen(in) * 9)) / 2;
return drawString(in, x, y, fontColor, 0, dest);
}
int drawString(char *in, int x, int y, int fontColor)
{
if (x == -1)
x = (800 - (strlen(in) * 9)) / 2;
return drawString(in, x, y, fontColor, 0, screen);
}
/*
Finds the location of the requested color within the palette and returns
it's number. This colors are used for drawing rectangles, circle, etc in
the correct colors.
*/
void setColorIndexes()
{
red = SDL_MapRGB(screen->format, 0xff, 0x00, 0x00);
darkRed = SDL_MapRGB(screen->format, 0x66, 0x00, 0x00);
yellow = SDL_MapRGB(screen->format, 0xff, 0xff, 0x00);
darkYellow = SDL_MapRGB(screen->format, 0x66, 0x66, 0x00);
green = SDL_MapRGB(screen->format, 0x00, 0xff, 0x00);
darkGreen = SDL_MapRGB(screen->format, 0x00, 0x66, 0x00);
blue = SDL_MapRGB(screen->format, 0x00, 0x00, 0xff);
darkBlue = SDL_MapRGB(screen->format, 0x00, 0x00, 0x99);
darkerBlue = SDL_MapRGB(screen->format, 0x00, 0x00, 0x44);
black = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);
white = SDL_MapRGB(screen->format, 0xff, 0xff, 0xff);
lightGrey = SDL_MapRGB(screen->format, 0xcc, 0xcc, 0xcc);
darkGrey = SDL_MapRGB(screen->format, 0x99, 0x99, 0x99);
}
/*
Draws the background surface that has been loaded
*/
void drawBackGround()
{
blit(background, 0, 0, screen);
}
void clearScreen(Uint32 color)
{
SDL_FillRect(screen, NULL, color);
}
void updateScreen()
{
SDL_Flip(screen);
// Give the audio (and possibly the X server) time to work...
SDL_Delay(1);
}
/*
* Set the pixel at (x, y) to the given value
* NOTE: The surface must be locked before calling this!
*/
void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
{
int bpp = surface->format->BytesPerPixel;
/* Here p is the address to the pixel we want to set */
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
switch(bpp) {
case 1:
*p = pixel;
break;
case 2:
*(Uint16 *)p = pixel;
break;
case 3:
if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
p[0] = (pixel >> 16) & 0xff;
p[1] = (pixel >> 8) & 0xff;
p[2] = pixel & 0xff;
} else {
p[0] = pixel & 0xff;
p[1] = (pixel >> 8) & 0xff;
p[2] = (pixel >> 16) & 0xff;
}
break;
case 4:
*(Uint32 *)p = pixel;
break;
}
}
void drawLine(SDL_Surface *dest, int x1, int y1, int x2, int y2, int col)
{
int counter = 0;
if ( SDL_MUSTLOCK(dest) ) {
if ( SDL_LockSurface(dest) < 0 ) {
printf("Can't lock screen: %s\n", SDL_GetError());
showErrorAndExit(2, "");
}
}
while(1)
{
putpixel(dest, x1, y1, col);
if (x1 > x2) x1--;
if (x1 < x2) x1++;
if (y1 > y2) y1--;
if (y1 < y2) y1++;
if ((x1 == x2) && (y1 == y2))
{break;}
if (counter == 1000)
{printf("Loop Error!\n"); break;}
counter++;
}
if ( SDL_MUSTLOCK(dest) ) {
SDL_UnlockSurface(dest);
}
}
void drawLine(int x1, int y1, int x2, int y2, int col)
{
drawLine(screen, x1, y1, x2, y2, col);
}
/*
A quick(?) circle draw function. This code was posted to the SDL
mailing list... I didn't write it myself.
*/
void circle(int xc, int yc, int R, SDL_Surface *PIX, int col)
{
int x = 0, xx = 0;
int y = R, yy = R+R;
int p = 1-R;
putpixel(PIX, xc, yc - y, col);
putpixel(PIX, xc, yc + y, col);
putpixel(PIX, xc - y, yc, col);
putpixel(PIX, xc + y, yc, col);
while(x < y)
{
xx += 2;
++x;
if (p >= 0)
{
yy -= 2;
--y;
p -= yy;
}
p += xx + 1;
putpixel(PIX, xc - x, yc - y, col);
putpixel(PIX, xc + x, yc - y, col);
putpixel(PIX, xc - x, yc + y, col);
putpixel(PIX, xc + x, yc + y, col);
putpixel(PIX, xc - y, yc - x, col);
putpixel(PIX, xc + y, yc - x, col);
putpixel(PIX, xc - y, yc + x, col);
putpixel(PIX, xc + y, yc + x, col);
}
if ((x = y))
{
putpixel(PIX, xc - x, yc - y, col);
putpixel(PIX, xc + x, yc - y, col);
putpixel(PIX, xc - x, yc + y, col);
putpixel(PIX, xc + x, yc + y, col);
}
}
void blevelRect(SDL_Surface *dest, int x, int y, int w, int h, Uint8 red, Uint8 green, Uint8 blue)
{
SDL_Rect r = {x, y, w, h};
SDL_FillRect(dest, &r, SDL_MapRGB(screen->format, red, green, blue));
drawLine(dest, x, y, x + w, y, SDL_MapRGB(screen->format, 255, 255, 255));
drawLine(dest, x, y, x, y + h, SDL_MapRGB(screen->format, 255, 255, 255));
drawLine(dest, x, y + h, x + w, y + h, SDL_MapRGB(screen->format, 128, 128, 128));
drawLine(dest, x + w, y + 1, x + w, y + h, SDL_MapRGB(screen->format, 128, 128, 128));
}
void blevelRect(int x, int y, int w, int h, Uint8 red, Uint8 green, Uint8 blue)
{
blevelRect(screen, x, y, w, h, red, green, blue);
}
SDL_Surface *createSurface(int width, int height)
{
SDL_Surface *surface, *newImage;
Uint32 rmask, gmask, bmask, amask;
/* SDL interprets each pixel as a 32-bit number, so our masks must depend
on the endianness (byte order) of the machine */
#if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
rmask = 0xff000000;
gmask = 0x00ff0000;
bmask = 0x0000ff00;
amask = 0x000000ff;
#else
rmask = 0x000000ff;
gmask = 0x0000ff00;
bmask = 0x00ff0000;
amask = 0xff000000;
#endif
surface = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 32, rmask, gmask, bmask, amask);
if (surface == NULL) {
printf("CreateRGBSurface failed: %s\n", SDL_GetError());
showErrorAndExit(2, "");
}
newImage = SDL_DisplayFormat(surface);
SDL_FreeSurface(surface);
return newImage;
}
SDL_Surface *textSurface(char *inString, int color)
{
SDL_Surface *surface = createSurface(strlen(inString) * 9, 16);
drawString(inString, 1, 1, color, surface);
return setTransparent(surface);
}
void textSurface(int index, char *inString, int x, int y, int fontColor)
{
strcpy(textShape[index].text, inString);
textShape[index].x = x;
textShape[index].y = y;
textShape[index].fontColor = fontColor;
if (textShape[index].image != NULL)
{
SDL_FreeSurface(textShape[index].image);
}
textShape[index].image = textSurface(inString, fontColor);
if (x == -1)
textShape[index].x = (800 - textShape[index].image->w) / 2;
}
SDL_Surface *alphaRect(int width, int height, Uint8 red, Uint8 green, Uint8 blue)
{
SDL_Surface *surface = createSurface(width, height);
SDL_FillRect(surface, NULL, SDL_MapRGB(surface->format, red, green, blue));
SDL_SetAlpha(surface, SDL_SRCALPHA|SDL_RLEACCEL, 128);
return surface;
}
void createMessageBox(SDL_Surface *face, char *message, signed char transparent)
{
if (messageBox != NULL)
{
SDL_FreeSurface(messageBox);
messageBox = NULL;
}
if (transparent)
messageBox = alphaRect(550, 60, 0x00, 0x00, 0x00);
else
messageBox = createSurface(550, 60);
signed char x = 60;
if (face != NULL)
{
blevelRect(messageBox, 0, 0, messageBox->w - 1, messageBox->h - 1, 0x00, 0x00, 0xaa);
blit(face, 5, 5, messageBox);
}
else
{
blevelRect(messageBox, 0, 0, messageBox->w - 1, messageBox->h - 1, 0x00, 0x00, 0x00);
x = 10;
}
drawString(message, x, 5, FONT_WHITE, 1, messageBox);
}
void freeGraphics()
{
for (int i = 0 ; i < MAX_SHAPES ; i++)
{
if (shape[i] != NULL)
{
SDL_FreeSurface(shape[i]);
shape[i] = NULL;
}
}
for (int i = 0 ; i < MAX_SHIPSHAPES ; i++)
{
if (shipShape[i] != NULL)
{
SDL_FreeSurface(shipShape[i]);
shipShape[i] = NULL;
}
}
for (int i = 0 ; i < MAX_TEXTSHAPES ; i++)
{
if (textShape[i].image != NULL)
{
SDL_FreeSurface(textShape[i].image);
textShape[i].image = NULL;
}
}
for (int i = 0 ; i < MAX_SHOPSHAPES ; i++)
{
if (shopSurface[i] != NULL)
{
SDL_FreeSurface(shopSurface[i]);
shopSurface[i] = NULL;
}
}
if (messageBox != NULL)
{
SDL_FreeSurface(messageBox);
messageBox = NULL;
}
}
};

430
code/collectable.cpp Normal file
View File

@ -0,0 +1,430 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "collectable.h"
/*
Create a new collectable item based on supplied arguments.
*/
void addCollectable(float x, float y, int type, int value, int life)
{
if (type == P_ANYTHING)
{
type = P_CASH;
int r = rand() % 9;
switch (r)
{
case 0:
type = P_PLASMA_AMMO;
break;
case 1:
type = P_SHIELD;
break;
case 2:
type = P_ROCKET;
value /= 10;
break;
}
}
else if (type == P_WEAPONS)
{
type = P_PLASMA_RATE;
int r = rand() % 61;
if (r <= 19)
type = P_PLASMA_DAMAGE;
else if (r <= 39)
type = P_PLASMA_SHOT;
else if (r <= 59)
type = P_PLASMA_RATE;
else
type = P_SUPER;
}
if (type == P_SUPER)
value = 1;
/*
Cash is rare on interceptions. Stops people from point leeching(!)
*/
if ((currentGame.area == MAX_MISSIONS - 1) && (type == P_CASH))
{
if (rand() % 10 > 0)
return;
}
if (value == 0)
return; // don't bother!
// If the player has a charge cannon or a laser cannon, don't give them
// rockets. Causes problems otherwise :)
if (type == P_ROCKET)
{
if ((player.weaponType[1] == W_CHARGER) || (player.weaponType[1] == W_LASER))
{
type = P_CASH;
}
}
collectables *collectable = new collectables;
collectable->next = NULL;
collectable->active = 1;
collectable->x = x;
collectable->y = y;
collectable->dx = Math::rrand(-100, 100);
if (collectable->dx != 0)
collectable->dx /= 100;
collectable->dy = Math::rrand(-100, 100);
if (collectable->dy != 0)
collectable->dy /= 100;
collectable->type = type;
collectable->value = value;
collectable->life = life;
switch(type)
{
case P_CASH:
collectable->image = graphics.shape[24];
break;
case P_ROCKET:
collectable->image = graphics.shape[49];
break;
case P_PLASMA_AMMO:
collectable->image = graphics.shape[25];
break;
case P_SHIELD:
collectable->image = graphics.shape[26];
break;
case P_PLASMA_SHOT:
collectable->image = graphics.shape[27];
break;
case P_PLASMA_RATE:
collectable->image = graphics.shape[28];
break;
case P_PLASMA_DAMAGE:
collectable->image = graphics.shape[29];
break;
case P_CARGO:
collectable->image = graphics.shape[32];
break;
case P_SUPER:
collectable->image = graphics.shape[50];
break;
case P_MINE:
collectable->image = graphics.shape[31];
break;
case P_SLAVES:
case P_ESCAPEPOD:
collectable->image = graphics.shape[45];
break;
case P_ORE:
collectable->image = graphics.shape[46 + rand() % 3];
break;
}
engine.collectableTail->next = collectable;
engine.collectableTail = collectable;
}
void explodeMine(collectables *collectable)
{
if ((collectable->x >= 0) && (collectable->x <= 800) && (collectable->y >= 0) && (collectable->y <= 600))
playSound(SFX_EXPLOSION);
for (int i = 0 ; i < 10 ; i++)
addExplosion(collectable->x + rand() % 25 - rand() % 25, collectable->y + rand() % 25 - rand() % 25, E_BIG_EXPLOSION);
if (checkPlayerShockDamage(collectable->x, collectable->y, 50))
setInfoLine("Warning: Mine damage to shield!!", FONT_RED);
}
void checkMineBulletCollisions(object *bullet)
{
collectables *collectable = engine.collectableHead;
collectables *prevCollectable = engine.collectableHead;
engine.collectableTail = engine.collectableHead;
while (collectable->next != NULL)
{
collectable = collectable->next;
if (collectable->type == P_MINE)
{
if (Collision::collision(collectable, bullet))
{
collectable->active = 0;
if (bullet->id != WT_CHARGER)
{
bullet->active = 0;
}
else
{
bullet->shield--;
if (bullet->shield < 0)
bullet->active = 0;
}
if (bullet->owner == &player)
{
currentGame.minesKilled++;
currentGame.hits++;
}
}
}
if (collectable->active == 1)
{
prevCollectable = collectable;
engine.collectableTail = collectable;
}
else
{
explodeMine(collectable);
prevCollectable->next = collectable->next;
delete collectable;
collectable = prevCollectable;
}
}
}
/*
Loops through the currently active collectables (in a linked list). The collectable
will travel in the direction that was defined when it was made. Its life will decreased
whilst it remains active. It will be removed if the player touches it or if its life
reaches 0. When it is picked up, depending on the type of collectable it is, mission requirements
will be updated. Information will be displayed and appropriate player variables altered.
*/
void doCollectables()
{
collectables *collectable = engine.collectableHead;
collectables *prevCollectable = engine.collectableHead;
engine.collectableTail = engine.collectableHead;
while (collectable->next != NULL)
{
collectable = collectable->next;
if (collectable->active == 1)
{
if ((collectable->x + collectable->image->w > 0) && (collectable->x < 800) && (collectable->y + collectable->image->h > 0) && (collectable->y < 600))
graphics.blit(collectable->image, (int)collectable->x, (int)collectable->y);
collectable->x += engine.ssx;
collectable->y += engine.ssy;
collectable->x += collectable->dx;
collectable->y += collectable->dy;
collectable->life--;
if ((player.shield > 0) && (Collision::collision(collectable, &player)))
{
char temp[40];
switch(collectable->type)
{
case P_CASH:
currentGame.cash += collectable->value;
currentGame.cashEarned += collectable->value;
sprintf(temp, "Got $%d ", collectable->value);
break;
case P_ROCKET:
Math::limitChar(&(player.ammo[1] += collectable->value), 0, currentGame.maxRocketAmmo);
if (player.ammo[1] == currentGame.maxRocketAmmo)
sprintf(temp, "Rocket Ammo at Maximum");
else
{
if (collectable->value > 1)
sprintf(temp, "Got %d rockets", collectable->value);
else
sprintf(temp, "Got a rocket");
}
currentGame.rocketPickups += collectable->value;
break;
case P_SHIELD:
Math::limitInt(&(player.shield += 10), 0, player.maxShield);
currentGame.shieldPickups ++;
sprintf(temp, "Restored 10 shield points");
break;
case P_PLASMA_RATE:
Math::limitChar(&(weapon[1].reload[0] -= 2), currentGame.maxPlasmaRate, 15);
player.weaponType[0] = 1;
if (player.ammo[0] < 50)
player.ammo[0] = 50;
Math::limitChar(&(player.ammo[0]), 0, currentGame.maxPlasmaAmmo);
if (weapon[1].reload[0] == currentGame.maxPlasmaRate)
sprintf(temp, "Firing Rate at Maximum");
else
sprintf(temp, "Firing rate increased");
currentGame.powerups++;
break;
case P_PLASMA_SHOT:
Math::limitChar(&(weapon[1].ammo[0] += 1), 1, currentGame.maxPlasmaOutput);
if (player.ammo[0] < 50)
player.ammo[0] = 50;
Math::limitChar(&(player.ammo[0]), 0, currentGame.maxPlasmaAmmo);
if (weapon[1].ammo[0] == currentGame.maxPlasmaOutput)
sprintf(temp, "Plasma output at Maximum");
else
sprintf(temp, "Plasma output increased");
player.weaponType[0] = 1;
currentGame.powerups++;
break;
case P_PLASMA_DAMAGE:
Math::limitChar(&(weapon[1].damage += 1), 1, currentGame.maxPlasmaDamage);
if (player.ammo[0] < 50)
player.ammo[0] = 50;
Math::limitChar(&(player.ammo[0]), 0, currentGame.maxPlasmaAmmo);
if (weapon[1].damage == currentGame.maxPlasmaDamage)
sprintf(temp, "Plasma damage at Maximum");
else
sprintf(temp, "Plasma damage increased");
player.weaponType[0] = 1;
currentGame.powerups++;
break;
case P_SUPER:
weapon[1].ammo[0] = 5;
weapon[1].damage = 5;
weapon[1].reload[0] = 7;
if (weapon[1].flags & WF_STRAIGHT)
weapon[1].flags -= WF_STRAIGHT;
if (weapon[1].flags & WF_THIN_SPREAD)
weapon[1].flags -= WF_THIN_SPREAD;
if (!(weapon[1].flags & WF_WIDE_SPREAD))
weapon[1].flags += WF_WIDE_SPREAD;
sprintf(temp, "Picked up a Super Charge!!");
if (player.ammo[0] < 50)
player.ammo[0] = 50;
player.weaponType[0] = 1;
currentGame.powerups++;
break;
case P_PLASMA_AMMO:
Math::limitChar(&(player.ammo[0] += collectable->value), 0, currentGame.maxPlasmaAmmo);
if (player.ammo[0] == currentGame.maxPlasmaAmmo)
sprintf(temp, "Plasma cells at Maximum");
else
{
if (collectable->value > 1)
{
sprintf(temp, "Got %d plasma cells", collectable->value);
}
else
{
sprintf(temp, "Got a plasma cell");
if ((rand() % 25) == 0)
sprintf(temp, "Got one whole plasma cell (wahoo!)");
}
}
player.weaponType[0] = 1;
currentGame.cellPickups += collectable->value;
break;
case P_CARGO:
strcpy(temp, "Picked up some Cargo");
currentGame.cargoPickups++;
break;
case P_SLAVES:
sprintf(temp, "Rescued %d slaves", collectable->value);
currentGame.slavesRescued += collectable->value;
break;
case P_ESCAPEPOD:
sprintf(temp, "Picked up an Escape Pod");
break;
case P_ORE:
sprintf(temp, "Picked up some Ore");
break;
}
updateMissionRequirements(M_COLLECT, collectable->type, collectable->value);
collectable->active = 0;
if (collectable->type != P_MINE)
{
setInfoLine(temp, FONT_WHITE);
if (collectable->type == P_SHIELD)
playSound(SFX_SHIELDUP);
else
playSound(SFX_PICKUP);
}
}
// stop people from exploiting a weapon check condition
if (player.ammo[0] == 0)
{
player.weaponType[0] = 0;
weapon[1] = weapon[0]; // reset to weapon 1 defaults
}
}
if (collectable->life < 1)
{
collectable->active = 0;
if ((collectable->type == P_CARGO) || (collectable->type == P_ESCAPEPOD) || (collectable->type == P_SLAVES))
updateMissionRequirements(M_PROTECT_PICKUP, collectable->type, 1);
}
if (collectable->active == 1)
{
prevCollectable = collectable;
engine.collectableTail = collectable;
}
else
{
if (collectable->type == P_MINE)
explodeMine(collectable);
prevCollectable->next = collectable->next;
delete collectable;
collectable = prevCollectable;
}
}
}

43
code/collectable.h Normal file
View File

@ -0,0 +1,43 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include <string.h>
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_mixer.h"
#include "defs.h"
#include "structs.h"
#include "classes.h"
extern void updateMissionRequirements(int type, int id, int value);
extern void setInfoLine(char *in, int color);
extern object *addCargo(object *owner, int cargoType);
extern void addExplosion(float x, float y, int type);
extern void playSound(int sid);
extern char checkPlayerShockDamage(float x, float y, int radius);
extern globalEngineVariables engine;
extern object player;
extern Game currentGame;
extern object weapon[MAX_WEAPONS];
extern Graphics graphics;

156
code/comms.cpp Normal file
View File

@ -0,0 +1,156 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "comms.h"
void updateCommsSurface(SDL_Surface *comms)
{
if (engine.commsSection == 1)
return;
char string[255];
graphics.blevelRect(comms, 0, 10, comms->w - 1, 55, 0x00, 0x22, 0x00);
graphics.blit(graphics.shape[FACE_CHRIS], 20, 15, comms);
graphics.drawString("Chris Bainfield", 80, 15, FONT_WHITE, comms);
sprintf(string, "Current Location: %s", systemPlanet[currentGame.stationedPlanet].name);
graphics.drawString(string, 80, 35, FONT_WHITE, comms);
}
void createCommsSurface(SDL_Surface *comms)
{
engine.commsSection = 0;
graphics.blevelRect(comms, 0, 0, comms->w - 1, comms->h - 1, 0x00, 0x00, 0x25);
graphics.drawString("+++ RECIEVED MESSAGES +++", 115, 80, FONT_GREEN, comms);
int yOffset;
for (int i = 0 ; i < 10 ; i++)
{
if ((systemPlanet[i].messageSlot != -1) && (systemPlanet[i].missionCompleted == 0))
{
yOffset = systemPlanet[i].messageSlot * 60;
graphics.blevelRect(comms, 0, 105 + yOffset, comms->w - 1, 55, 0x00, 0x00, 0x77);
graphics.blit(graphics.shape[systemPlanet[i].faceImage], 20, 110 + yOffset, comms);
graphics.drawString(systemPlanet[i].from, 80, 110 + yOffset, FONT_WHITE, comms);
graphics.drawString(systemPlanet[i].subject, 80, 130 + yOffset, FONT_CYAN, comms);
graphics.drawString("INCOMPLETE", 350, 110 + yOffset, FONT_RED, comms);
}
}
updateCommsSurface(comms);
}
void createMissionDetailSurface(SDL_Surface *comms, int missionSlot)
{
char name[50];
char string[2000];
int lines = 0;
int y = 50;
int newY = y;
int col = FONT_WHITE;
int mission = -1;
int faceNumber = -1;
FILE *fp;
for (int i = 0 ; i < 10 ; i++)
{
if ((systemPlanet[i].messageSlot == missionSlot) && (systemPlanet[i].missionCompleted == 0))
{
//printf("Slot %d - Mission %d - Completed %d\n", missionSlot, systemPlanet[i].messageMission, systemPlanet[i].missionCompleted);
mission = systemPlanet[i].messageMission;
}
}
if (mission == -1)
return;
graphics.blevelRect(comms, 0, 0, comms->w - 1, comms->h - 1, 0x00, 0x00, 0x25);
strcpy(string, "");
sprintf(string, "data/brief%d.txt", mission);
#if USEPACK
int dataLocation = locateDataInPak(string, 1);
fp = fopen(PACKLOCATION, "rb");
fseek(fp, dataLocation, SEEK_SET);
#else
fp = fopen(string, "rb");
#endif
fscanf(fp, "%[^\n]%*c", name);
sprintf(string, "+++ Communication with %s +++", name);
graphics.drawString(string, -1, 20, FONT_GREEN, comms);
fscanf(fp, "%d%*c", &lines);
for (int i = 0 ; i < lines ; i++)
{
fscanf(fp, "%[^\n]%*c", string);
faceNumber = getFace(string);
if (faceNumber > -1)
{
graphics.blit(graphics.shape[faceNumber], 10, y, comms);
col = FONT_WHITE;
}
else
{
newY = graphics.drawString(string, 80, y, col, 1, comms) + 25;
if (newY < y + 60)
newY += (60 - (newY - y));
y = newY;
}
}
fclose(fp);
graphics.blevelRect(comms, 5, comms->h - 28, 180, 20, 0x25, 0x00, 0x00);
graphics.drawString("RETURN TO MESSAGES", 15, comms->h - 25, FONT_WHITE, 1, comms);
engine.commsSection = 1;
}
void doComms(SDL_Surface *comms)
{
if ((engine.keyState[SDLK_LCTRL]) || (engine.keyState[SDLK_RCTRL]))
{
if (engine.commsSection == 0)
{
for (int i = 0 ; i < 4 ; i++)
{
if (Collision::collision(engine.cursor_x + 13, engine.cursor_y + 13, 6, 6, 170, 180 + (i * 60), 430, 50))
{
createMissionDetailSurface(comms, i);
engine.keyState[SDLK_LCTRL] = engine.keyState[SDLK_RCTRL] = 0;
}
}
}
else
{
if (Collision::collision(engine.cursor_x + 13, engine.cursor_y + 13, 6, 6, 170, 440, 160, 20))
{
createCommsSurface(comms);
engine.keyState[SDLK_LCTRL] = engine.keyState[SDLK_RCTRL] = 0;
}
}
}
}

38
code/comms.h Normal file
View File

@ -0,0 +1,38 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include <string.h>
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_mixer.h"
#include "defs.h"
#include "structs.h"
#include "classes.h"
extern int locateDataInPak(char *file, signed char required);
extern int getFace(char *face);
extern globalEngineVariables engine;
extern Game currentGame;
extern Graphics graphics;
extern Planet systemPlanet[10];

94
code/debris.cpp Normal file
View File

@ -0,0 +1,94 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "debris.h"
void addDebris(int x, int y, int amount)
{
if ((rand() % 2) == 0)
playSound(SFX_DEBRIS);
else
playSound(SFX_DEBRIS2);
object *debris;
amount = Math::rrand(3, rand() % amount);
Math::limitInt(&amount, 3, 8);
for (int i = 0 ; i < amount ; i++)
{
debris = new object;
debris->next = NULL;
debris->x = x;
debris->y = y;
debris->thinktime = Math::rrand(60, 180);
debris->dx = Math::rrand(-500, 500);
debris->dy = Math::rrand(-500, 500);
if (debris->dx != 0)
debris->dx /= 100;
if (debris->dy != 0)
debris->dy /= 100;
engine.debrisTail->next = debris;
engine.debrisTail = debris;
}
}
void doDebris()
{
object *prevDebris = engine.debrisHead;
object *debris = engine.debrisHead;
engine.debrisTail = engine.debrisHead;
while (debris->next != NULL)
{
debris = debris->next;
if (debris->thinktime > 0)
{
debris->thinktime--;
debris->x += engine.ssx;
debris->y += engine.ssy;
debris->x += debris->dx;
debris->y += debris->dy;
addExplosion(debris->x + Math::rrand(-10, 10), debris->y + Math::rrand(-10, 10), E_BIG_EXPLOSION);
}
if (debris->thinktime < 1)
{
prevDebris->next = debris->next;
delete debris;
debris = prevDebris;
}
else
{
prevDebris = debris;
engine.debrisTail = debris;
}
}
}

36
code/debris.h Normal file
View File

@ -0,0 +1,36 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include <string.h>
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_mixer.h"
#include "defs.h"
#include "structs.h"
#include "classes.h"
extern void addExplosion(float x, float y, int type);
extern void playSound(int sid);
extern globalEngineVariables engine;
extern Graphics graphics;

315
code/defs.h Normal file
View File

@ -0,0 +1,315 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))
// ALL
#define NONE 0
//AI Types
enum {
AI_NORMAL = 1,
AI_DEFENSIVE,
AI_OFFENSIVE,
AI_EVASIVE,
AI_WANDER
};
// Object Flags
#define FL_WEAPCO 1
#define FL_FRIEND 2
#define FL_IMMORTAL 4
#define FL_NOMOVE 8
#define FL_NOFIRE 16
#define FL_FIRERAY 32
#define FL_DAMAGEOWNER 64
#define FL_LEAVESECTOR 128
#define FL_ESCAPED 256
#define FL_DROPMINES 512
#define FL_AIMS 1024
#define FL_DISABLED 2048
#define FL_CANNOTDIE 4096 // This will only apply to Kline before the final mission
#define FL_RUNSAWAY 8192
#define FL_ALWAYSFACE 16384 // Kline doesn't turn his back on you! ;)
#define FL_CIRCLES 32768 // Kline can circle around
#define FL_CONTINUOUS_FIRE 65536 // Go absolutely nutts(!)
#define FL_DEPLOYDRONES 131072 // Deploys small drone - Used by Boss 2
#define FL_CANCLOAK 262144
#define FL_ISCLOAKED 524288
#define FL_ACTIVATE 1048576
#define FL_HASMINIMUMSPEED 2097152
#define FL_FIRELASER 4194304
// These are for Alien *indexes* NOT classdefs!!
enum {
WC_BOSS = 14,
WC_KLINE,
FR_PHOEBE,
FR_URSULA,
FR_SID
};
// Droppables
enum {
P_ANYTHING = 1,
P_WEAPONS,
P_CASH,
P_ROCKET,
P_SHIELD,
P_CARGO,
P_PLASMA_AMMO,
P_PLASMA_RATE,
P_PLASMA_SHOT,
P_PLASMA_DAMAGE,
P_MINE, // mines detonate when you "pick them up!"
P_PHOEBE, // only used as an attachment(!)
P_SLAVES,
P_ESCAPEPOD,
P_ORE,
P_SUPER
};
// Jobs
enum {
WT_PLASMA = 1,
WT_ROCKET,
WT_ENERGYRAY,
WT_LASER,
WT_MICROROCKET,
WT_CHARGER,
WT_DIRECTIONAL,
WT_SPREAD
};
// Explosions
#define E_SMALL_EXPLOSION 4
#define E_BIG_EXPLOSION 8
#define E_SMOKE 12
#define E_TINY_EXPLOSION 16
#define E_ELECTRICAL 20
// Weapons
enum {
W_NONE = -1,
W_PLAYER_WEAPON,
W_PLAYER_WEAPON2,
W_SINGLE_SHOT,
W_DOUBLE_SHOT,
W_TRIPLE_SHOT,
W_ROCKETS,
W_DOUBLE_ROCKETS,
W_MICRO_ROCKETS,
W_ENERGYRAY,
W_LASER,
W_CHARGER,
W_HOMING_MISSILE,
W_DOUBLE_HOMING_MISSILES,
W_MICRO_HOMING_MISSILES,
W_AIMED_SHOT,
W_SPREADSHOT,
W_IONCANNON,
W_DIRSHOCKMISSILE
};
// Weapon flags
#define WF_STRAIGHT 1
#define WF_THIN_SPREAD 2
#define WF_WIDE_SPREAD 4
#define WF_SCATTER 8
#define WF_VARIABLE_SPEED 16
#define WF_HOMING 32
#define WF_SHOCKWAVE 64
#define WF_WEAPCO 128
#define WF_FRIEND 256
#define WF_AIMED 512
#define WF_DISABLE 1024
#define WF_TIMEDEXPLOSION 2048
// Missions
enum {
M_DESTROY_ALL_TARGETS = 1,
M_DESTROY_TARGET_TYPE,
M_COLLECT,
M_PROTECT_PICKUP,
M_PROTECT_TARGET,
M_DISABLE_TARGET,
M_ESCAPE_TARGET
};
enum {
OB_JUST_FAILED = -2,
OB_FAILED,
OB_INCOMPLETE,
OB_COMPLETED,
OB_JUST_COMPLETED,
OB_CONDITION,
OB_HIDDEN
};
// Class Defs - Some of these are just place holders
enum {
CD_DUALFIGHTER, // 0
CD_MISSILEBOAT,
CD_PROTOFIGHTER,
CD_FRIEND,
CD_FRIGATE,
CD_FRIGATE_WING1,
CD_FRIGATE_WING2,
CD_TRANSPORTSHIP,
CD_CARGOSHIP,
CD_MINER,
CD_KLINE, // 10
CD_AIMFIGHTER,
CD_SLAVETRANSPORT,
CD_GOODTRANSPORT,
CD_SID,
CD_MINEBOSS,
CD_BOSS2_WING1,
CD_BOSS2_WING2,
CD_BOSS2_WING3,
CD_BOSS2_WING4,
CD_DRONE, // 20
CD_CLOAKFIGHTER,
CD_EVILURSULA,
CD_KRASS,
CD_EXEC,
CD_ASTEROID,
CD_ASTEROID2,
CD_ESCORT,
CD_MOBILE_RAY,
CD_REBELCARRIER,
CD_PLUTOBOSS, // 30
CD_BARRIER,
CD_NEPTUNEBOSS,
CD_MOBILESHIELD,
CD_PIRATE,
CD_FIREFLY,
CD_URANUSBOSS,
CD_URANUSBOSSWING1,
CD_URANUSBOSSWING2,
// Some special ones
CD_ANY = 100,
CD_BOSS,
CD_PHOEBE,
CD_URSULA
};
// Font Colors
enum {
FONT_WHITE,
FONT_RED,
FONT_YELLOW,
FONT_GREEN,
FONT_CYAN,
FONT_OUTLINE // a dark blue color
};
// Sounds
enum {
SFX_EXPLOSION,
SFX_HIT,
SFX_DEATH,
SFX_MISSILE,
SFX_PLASMA,
SFX_CLOCK,
SFX_FLY,
SFX_ENERGYRAY,
SFX_PICKUP,
SFX_SHIELDUP,
SFX_CLOAK,
SFX_DEBRIS,
SFX_DEBRIS2,
SFX_LASER,
SFX_PLASMA2,
SFX_PLASMA3
};
enum {
SECTION_TITLE,
SECTION_INTERMISSION,
SECTION_GAME
};
enum {
FACE_CHRIS = 90,
FACE_SID,
FACE_KRASS,
FACE_KLINE,
FACE_PHOEBE,
FACE_URSULA,
FACE_CREW
};
#define MAX_WEAPONS 20
#define MAX_SHAPES 100
#define MAX_SHIPSHAPES 120
#define MAX_SOUNDS 17
#define MAX_ALIENS 25
#define MAX_TEXTSHAPES 70
#define MAX_FONTSHAPES 6
#define MAX_SHOPSHAPES 6
#define MAX_DEFALIENS 40
#define MAX_MISSIONS 28
#define MAX_CARGO 20
#define MAX_SHOPITEMS 17
#define SHIP_HIT_INDEX 60
#define USEPACK 1
#ifndef PACKLOCATION
#define PACKLOCATION "starfighter.pak"
#endif
#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
enum {
PAK_IMG,
PAK_WAV,
PAK_MOD,
PAK_FONT,
PAK_S3M
};
const char systemNames[][15] = {"Spirit", "Eyananth", "Mordor", "Sol"};
const char faces[][12] = {
"FACE_CHRIS", "FACE_SID", "FACE_KRASS",
"FACE_KLINE", "FACE_PHOEBE", "FACE_URSULA",
"FACE_CREW"};
const char systemBackground[][20] = {
"gfx/spirit.jpg", "gfx/eyananth.jpg",
"gfx/mordor.jpg", "gfx/sol.jpg"};

87
code/events.cpp Normal file
View File

@ -0,0 +1,87 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "events.h"
/*
Checked during the main game loop. When the game is paused
it goes into a constant loop checking this routine. If escape is
pressed, the game automatically ends and goes back to the title screen
*/
signed char checkPauseRequest()
{
getPlayerInput();
if (engine.keyState[SDLK_ESCAPE])
{
engine.paused = 0;
engine.done = 1;
player.shield = 0;
return 1;
}
if (engine.keyState[SDLK_p])
{
engine.paused = 0;
engine.keyState[SDLK_p] = 0;
}
return 0;
}
void compareLastKeyInputs()
{
if (strstr(lastKeyEvents, "humansdoitbetter") != NULL)
{engine.cheat = 1; memset(lastKeyEvents, ' ', 25);}
if (strstr(lastKeyEvents, "credits") != NULL)
{engine.cheatCredits = 1; memset(lastKeyEvents, ' ', 25);}
}
void addKeyEvent(char *keyName)
{
if (strlen(keyName) > 1)
return;
int index = -1;
for (int i = 0 ; i < 25 ; i++)
{
if (lastKeyEvents[i] == ' ')
{
index = i;
break;
}
}
if (index == -1)
{
for (int i = 0 ; i < 25 ; i++)
{
lastKeyEvents[i] = lastKeyEvents[i + 1];
}
index = 24;
}
lastKeyEvents[index] = keyName[0];
compareLastKeyInputs();
}

37
code/events.h Normal file
View File

@ -0,0 +1,37 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include <string.h>
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_mixer.h"
#include "structs.h"
extern void getPlayerInput();
extern globalEngineVariables engine;
extern object player;
extern Game currentGame;
extern devVariables dev;
char lastKeyEvents[] = " ";

111
code/explosions.cpp Normal file
View File

@ -0,0 +1,111 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "explosions.h"
/*
Create a new explosion based on supplied parameters.
The "type" will actually be used as an explosion frame check.
All explosion types have 4 images. The "thinktime" will be used
to change frames on a 21, 14, 7 basis.
*/
void addExplosion(float x, float y, int type)
{
object *explosion = new object;
explosion->next = NULL;
explosion->active = 1;
explosion->x = x;
explosion->y = y;
explosion->thinktime = 28;
explosion->face = type;
explosion->image[0] = graphics.shape[type];
engine.explosionTail->next = explosion;
engine.explosionTail = explosion;
}
/*
* This very simply just adds a tiny explosion at the coordinate specified.
* It creates a small engine like effect.
*/
void addEngine(object *craft)
{
if (rand() % 2 == 0)
return;
float x = craft->x + (craft->engineX * craft->face);
float y = craft->y + craft->engineY;
y += Math::rrand(-3, 3);
addExplosion(x, y, E_TINY_EXPLOSION);
}
/*
Loops through active explosions and decrements their think time.
If their thinktime is divisable by 5, then the frame is changed to
the next one up (for example 0->1->2-3). When their think time is 0,
the explosion is killed off.
*/
void doExplosions()
{
object *prevExplosion = engine.explosionHead;
object *explosion = engine.explosionHead;
engine.explosionTail = engine.explosionHead;
while (explosion->next != NULL)
{
explosion = explosion->next;
if (explosion->active == 1)
{
explosion->thinktime--;
explosion->x += engine.ssx;
explosion->y += engine.ssy;
if (isOnScreen((int)explosion->x, (int)explosion->y, explosion->image[0]->w, explosion->image[0]->h))
graphics.blit(explosion->image[0], (int)explosion->x, (int)explosion->y);
if (explosion->thinktime < 1)
{
explosion->active = 0;
}
else if (explosion->thinktime % 7 == 0)
{
explosion->face++;
explosion->image[0] = graphics.shape[explosion->face];
}
}
if (explosion->active == 1)
{
prevExplosion = explosion;
engine.explosionTail = explosion;
}
else
{
prevExplosion->next = explosion->next;
delete explosion;
explosion = prevExplosion;
}
}
}

37
code/explosions.h Normal file
View File

@ -0,0 +1,37 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include <string.h>
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_mixer.h"
#include "defs.h"
#include "structs.h"
#include "classes.h"
extern int isOnScreen(int x, int y, int w, int h);
extern globalEngineVariables engine;
extern devVariables dev;
extern object enemy[MAX_ALIENS];
extern Graphics graphics;

344
code/game.cpp Normal file
View File

@ -0,0 +1,344 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "game.h"
void newGame()
{
currentGame.system = 0;
currentGame.area = 0;
currentGame.sfxVolume = 0;
currentGame.musicVolume = 0;
if (!engine.useAudio)
{
currentGame.useSound = 0;
currentGame.useMusic = 0;
}
currentGame.autoSaveSlot = -1;
currentGame.cash = 0;
currentGame.cashEarned = 0;
currentGame.shots = 0;
currentGame.hits = 0;
currentGame.accuracy = 0;
currentGame.totalKills = currentGame.wingMate1Kills = currentGame.wingMate2Kills = 0;
currentGame.totalOtherKills = 0;
currentGame.hasWingMate1 = currentGame.hasWingMate2 = 0;
currentGame.wingMate1Ejects = currentGame.wingMate2Ejects = 0;
currentGame.secondaryMissions = currentGame.secondaryMissionsCompleted = 0;
currentGame.shieldPickups = currentGame.rocketPickups = currentGame.cellPickups = 0;
currentGame.powerups = currentGame.minesKilled = currentGame.cargoPickups = 0;
currentGame.slavesRescued = 0;
currentGame.experimentalShield = 1000;
currentGame.timeTaken = 0;
currentGame.stationedPlanet = -1;
currentGame.destinationPlanet = -1;
for (int i = 0 ; i < 10 ; i++)
currentGame.missionCompleted[i] = 0;
currentGame.distanceCovered = 0;
currentGame.maxPlasmaRate = 13;
currentGame.maxPlasmaOutput = 2;
currentGame.maxPlasmaDamage = 2;
currentGame.maxPlasmaAmmo = 100;
currentGame.maxRocketAmmo = 10;
currentGame.shieldUnits = 1;
player.maxShield = 25;
player.shield = 25;
player.ammo[0] = 0;
player.ammo[1] = 5;
player.weaponType[0] = W_PLAYER_WEAPON;
player.weaponType[1] = W_ROCKETS;
initWeapons();
initMissions();
initPlanetMissions(currentGame.system);
}
int mainGameLoop()
{
Uint32 then, now, frames;
resetLists();
setMission(currentGame.area);
missionBriefScreen();
initCargo();
initPlayer();
initAliens();
clearInfoLines();
loadScriptEvents();
engine.ssx = 0;
engine.ssy = 0;
engine.done = 0;
frames = 0;
engine.counter = (SDL_GetTicks() + 1000);
engine.counter2 = (SDL_GetTicks() + 1000);
engine.missionCompleteTimer = 0;
engine.musicVolume = 100;
int rtn = 0;
unsigned long frameLimit = SDL_GetTicks();
int allowableAliens = 999999999;
for (int i = 0 ; i < 3 ; i++)
{
if ((currentMission.primaryType[i] == M_DESTROY_TARGET_TYPE) && (currentMission.target1[i] == CD_ANY))
allowableAliens = currentMission.targetValue1[i];
if (currentMission.primaryType[i] == M_DESTROY_ALL_TARGETS)
allowableAliens = 999999999;
}
for (int i = 0 ; i < MAX_ALIENS ; i++)
{
if ((enemy[i].active) && (enemy[i].flags & FL_WEAPCO))
{
allowableAliens--;
}
}
then = SDL_GetTicks();
graphics.drawBackGround();
graphics.flushBuffer();
// Default to no aliens dead...
engine.allAliensDead = 0;
engine.keyState[SDLK_LCTRL] = engine.keyState[SDLK_RCTRL] = engine.keyState[SDLK_SPACE] = 0;
flushInput();
while (engine.done != 1)
{
++frames;
graphics.updateScreen();
if ((allMissionsCompleted()) && (engine.missionCompleteTimer == 0))
{
engine.missionCompleteTimer = SDL_GetTicks() + 4000;
}
if ((missionFailed()) && (engine.missionCompleteTimer == 0))
{
if (currentGame.area != 5)
engine.missionCompleteTimer = SDL_GetTicks() + 4000;
}
if (engine.missionCompleteTimer != 0)
{
engine.gameSection = SECTION_INTERMISSION;
if (player.shield > 0)
{
if (SDL_GetTicks() >= engine.missionCompleteTimer)
{
if ((!missionFailed()) && (currentGame.area != 26))
{
leaveSector();
if ((engine.done == 2) && (currentGame.area != 10) && (currentGame.area != 15))
{
if ((enemy[FR_PHOEBE].shield > 0) && (currentGame.area != 25))
{
enemy[FR_PHOEBE].x = player.x - 40;
enemy[FR_PHOEBE].y = player.y - 35;
enemy[FR_PHOEBE].face = 0;
}
if ((enemy[FR_URSULA].shield > 0) && (currentGame.area != 25))
{
enemy[FR_URSULA].x = player.x - 40;
enemy[FR_URSULA].y = player.y + 45;
enemy[FR_URSULA].face = 0;
}
if ((currentGame.area == 9) || (currentGame.area == 17))
{
enemy[FR_SID].x = player.x - 100;
enemy[FR_SID].y = player.y;
enemy[FR_SID].face = 0;
}
}
}
else if ((currentGame.area == 26) && (engine.musicVolume > 0))
{
Math::limitFloat(&(engine.musicVolume -= 0.2), 0, 100);
Mix_VolumeMusic((int)engine.musicVolume);
}
else
{
engine.done = 1;
}
}
else
{
getPlayerInput();
}
}
else
{
Math::limitFloat(&(engine.musicVolume -= 0.2), 0, 100);
Mix_VolumeMusic((int)engine.musicVolume);
if (SDL_GetTicks() >= engine.missionCompleteTimer)
{
engine.done = 1;
}
}
}
else
{
getPlayerInput();
}
graphics.unBuffer();
doStarfield();
doCollectables();
doBullets();
doAliens();
doPlayer();
doCargo();
doDebris();
doExplosions();
doInfo();
Math::wrapChar(&(--engine.eventTimer), 0, 60);
while (engine.paused)
{
engine.done = checkPauseRequest();
then = SDL_GetTicks();
frames = 0;
graphics.updateScreen();
}
if ((currentGame.area == 24) && (engine.addAliens > -1))
{
if ((rand() % 10) == 0)
addCollectable(Math::rrand(800, 100), player.y, P_MINE, 25, 180 + rand() % 60);
}
if (engine.addAliens > -1)
{
Math::wrapInt(&(--engine.addAliens), 0, currentMission.addAliens);
if ((engine.addAliens == 0) && (allowableAliens > 0))
{
allowableAliens -= addAlien();
}
}
if ((player.shield <= 0) && (engine.missionCompleteTimer == 0))
engine.missionCompleteTimer = SDL_GetTicks() + 7000;
// specific to Boss 1
if ((currentGame.area == 5) && (enemy[WC_BOSS].flags & FL_ESCAPED))
{
playSound(SFX_DEATH);
graphics.clearScreen(graphics.white);
graphics.updateScreen();
for (int i = 0 ; i < 300 ; i++)
{
SDL_Delay(10);
if ((rand() % 25) == 0)
playSound(SFX_EXPLOSION);
}
SDL_Delay(1000);
break;
}
// (Attempt to) Limit us to 60 frame a second
while (SDL_GetTicks() < (frameLimit + 16))
{
// Do nothing. If we were to insert an SDL_Delay(1) in here
// then we would actually lose around 10 frames per second!!
}
frameLimit = SDL_GetTicks();
}
graphics.flushBuffer();
now = SDL_GetTicks();
if ( now > then )
{
//printf("Mission %d: %2.2f frames per second\n", currentGame.area, ((double)frames*1000)/(now-then));
}
if ((player.shield > 0) && (!missionFailed()))
{
if (currentGame.area < 26)
missionFinishedScreen();
switch (currentGame.area)
{
case 5:
doCutscene(1);
doCutscene(2);
break;
case 7:
doCutscene(3);
break;
case 11:
doCutscene(4);
break;
case 13:
doCutscene(5);
break;
case 18:
doCutscene(6);
break;
case 26:
doCredits();
break;
}
if (currentGame.area < 26)
{
updateSystemStatus();
if (currentGame.autoSaveSlot > -1)
saveGame(currentGame.autoSaveSlot + 1);
}
rtn = 1;
if (currentGame.area == 26)
rtn = 0;
}
else
{
gameover();
rtn = 0;
}
return rtn;
}

75
code/game.h Normal file
View File

@ -0,0 +1,75 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include <string.h>
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_mixer.h"
#include "defs.h"
#include "structs.h"
#include "classes.h"
extern void resetLists();
extern void setMission(int mission);
extern void missionBriefScreen();
extern void initPlayer();
extern void initAliens();
extern signed char allMissionsCompleted();
extern void getPlayerInput();
extern void leaveSector();
extern void doStarfield();
extern void doCollectables();
extern void doCargo();
extern void doBullets();
extern void doAliens();
extern void doPlayer();
extern void doExplosions();
extern void doDebris();
extern void doInfo();
extern signed char allMissionsCompleted();
extern signed char checkPauseRequest();
extern signed char addAlien();
extern void missionFinishedScreen();
extern void gameover();
extern void clearInfoLines();
extern signed char missionFailed();
extern void playSound(int sid);
extern void loadScriptEvents();
extern void doCutscene(int scene);
extern void addCollectable(float x, float y, int type, int value, int life);
extern void doCredits();
extern void updateSystemStatus();
extern void saveGame(int slot);
extern void flushInput();
extern void initWeapons();
extern void initMissions();
extern void initCargo();
extern void initPlanetMissions(signed char system);
extern globalEngineVariables engine;
extern object player;
extern object enemy[MAX_ALIENS];
extern mission currentMission;
extern Game currentGame;
extern Graphics graphics;

75
code/globals.cpp Normal file
View File

@ -0,0 +1,75 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "globals.h"
void defineGlobals()
{
engine.musicVolume = 100;
engine.useAudio = 2;
engine.maxAliens = 9;
engine.ssx = 0;
engine.ssy = 0;
engine.bulletHead = new object;
engine.bulletHead->next = NULL;
engine.bulletTail = engine.bulletHead;
engine.explosionHead = new object;
engine.explosionHead->next = NULL;
engine.explosionTail = engine.explosionHead;
engine.collectableHead = new collectables;
engine.collectableHead->next = NULL;
engine.collectableTail = engine.collectableHead;
engine.debrisHead = new object;
engine.debrisHead->next = NULL;
engine.debrisTail = engine.debrisHead;
engine.commsSection = 0;
for (int i = 0 ; i < 350 ; i++)
engine.keyState[i] = 0;
engine.eventTimer = 0;
engine.counter2 = 0;
engine.timeTaken = 0;
engine.timeMission = 0;
engine.counter = 0;
engine.seconds = 0;
engine.minutes = 0;
engine.paused = 0;
engine.gameSection = SECTION_TITLE;
engine.targetArrow = -1;
engine.targetArrowTimer = 0;
engine.cheat = 0;
engine.cheatShield = 0;
engine.cheatAmmo = 0;
engine.cheatCash = 0;
// All Development Stuff...
dev.moveAliens = 1;
dev.fireAliens = 1;
}

33
code/globals.h Normal file
View File

@ -0,0 +1,33 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_mixer.h"
#include "defs.h"
#include "structs.h"
extern globalEngineVariables engine;
extern devVariables dev;

103
code/graphics.cpp Normal file
View File

@ -0,0 +1,103 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "graphics.h"
SDL_Surface *loadImage(char *filename)
{
SDL_Surface *image, *newImage;
#if USEPACK
unpack(filename, PAK_IMG);
image = IMG_Load_RW(engine.sdlrw, 1);
#else
image = IMG_Load(filename);
#endif
if (image == NULL) {
printf("Couldn't load %s: %s\n", filename, SDL_GetError());
showErrorAndExit(0, filename);
}
newImage = SDL_DisplayFormat(image);
if ( newImage ) {
SDL_FreeSurface(image);
} else {
// This happens when we are loading the window icon image
newImage = image;
}
return graphics.setTransparent(newImage);
}
/*
Simply draws the stars in their positions on screen and moves
them around. They are wrapped around using the wrapFloat()
function, as defined above, and putpixel as defined in graphics.cpp
*/
void doStarfield()
{
/* Lock the screen for direct access to the pixels */
if (SDL_MUSTLOCK(graphics.screen))
{
if (SDL_LockSurface(graphics.screen) < 0 )
{
showErrorAndExit(2, "");
}
}
int color = 0;
SDL_Rect r;
for (int i = 0 ; i < 200 ; i++)
{
if (star[i].speed == 3)
color = graphics.white;
else if (star[i].speed == 2)
color = graphics.lightGrey;
else if (star[i].speed == 1)
color = graphics.darkGrey;
Math::wrapFloat(&(star[i].x += (engine.ssx * star[i].speed)), 0, 799);
Math::wrapFloat(&(star[i].y += (engine.ssy * star[i].speed)), 0, 599);
graphics.putpixel(graphics.screen, (int)star[i].x, (int)star[i].y, color);
r.x = (int)star[i].x;
r.y = (int)star[i].y;
r.w = 1;
r.h = 1;
graphics.addBuffer(r.x, r.y, r.w, r.h);
}
if (SDL_MUSTLOCK(graphics.screen))
{
SDL_UnlockSurface(graphics.screen);
}
}
int isOnScreen(int x, int y, int w, int h)
{
if ((x + w > 0) && (x < 800) && (y + h > 0) && (y < 600))
return 1;
return 0;
}

37
code/graphics.h Normal file
View File

@ -0,0 +1,37 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include <string.h>
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_mixer.h"
#include "defs.h"
#include "structs.h"
#include "classes.h"
extern void unpack(char *file, signed char fileType);
extern void showErrorAndExit(int errorId, char *name);
extern Star star[200];
extern globalEngineVariables engine;
extern Graphics graphics;

271
code/init.cpp Normal file
View File

@ -0,0 +1,271 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "init.h"
/*
Initalises a whole load of variables
*/
void initVars()
{
srand(time(NULL));
for (int i = 0 ; i < 200 ; i++)
{
star[i].x = rand() % 800;
star[i].y = rand() % 600;
star[i].speed = 1 + (rand() % 3);
}
// These are good values for sound and music
if (engine.useAudio)
{
Mix_Volume(-1, 25);
Mix_VolumeMusic((int)engine.musicVolume);
}
}
/*
Something went wrong. This stops the game, present the error message and
prompts the user to press space or ctrl to exit the game. This is unlikely to
be seen by people unless something really stoopid happens!
*/
void showErrorAndExit(int errorId, char *name)
{
graphics.clearScreen(graphics.black);
if (errorId != 2)
{
graphics.drawString("A file error has occurred", -1, 200, FONT_RED);
}
else
{
printf("Couldn't create or write to directory '%s'\n", name);
exit(1);
}
char string[255];
switch(errorId)
{
case 0:
strcpy(string, "");
sprintf(string, "%s was not found in the Starfighter data package", name);
graphics.drawString(string, -1, 250, FONT_WHITE);
graphics.drawString("Please try again. If this error persists, contact Parallel Realities", -1, 275, FONT_WHITE);
graphics.drawString("or reinstall the game", -1, 300, FONT_WHITE);
break;
case 1:
graphics.drawString("Project: Starfighter encountered an error whilst", -1, 250, FONT_WHITE);
graphics.drawString("attempting to load game data. Please try running", -1, 275, FONT_WHITE);
graphics.drawString("the game again. If the errors persist, reinstall the game", -1, 300, FONT_WHITE);
break;
case 2:
graphics.drawString("Project: Starfighter encountered a critical error", -1, 250, FONT_WHITE);
graphics.drawString("while attempting to perform a required program function.", -1, 275, FONT_WHITE);
graphics.drawString("Please contact Parallel Realities with details", -1, 300, FONT_WHITE);
break;
}
graphics.drawString("Project: Starfighter will now exit", -1, 450, FONT_WHITE);
graphics.drawString("Press Space to continue", -1, 475, FONT_WHITE);
engine.keyState[SDLK_SPACE] = 0;
while (!engine.keyState[SDLK_SPACE])
{
getPlayerInput();
graphics.updateScreen();
}
exit(1);
}
/*
This bit is just for Linux users. It attempts to get the user's
home directory, then creates the .parallelrealities and .parallelrealities/starfighter
directories so that saves and temporary data files can be written there. Good, eh? :)
*/
#if LINUX
void setupUserHomeDirectory()
{
char *userHome;
char *name = getlogin();
passwd *pass;
if (name != NULL)
pass = getpwnam(name);
else
pass = getpwuid(geteuid());
if (pass == NULL)
{
printf("Couldn't determine the user home directory. Exitting.\n");
exit(1);
}
userHome = pass->pw_dir;
char dir[PATH_MAX];
strcpy(dir, "");
sprintf(dir, "%s/.parallelrealities", userHome);
if ((mkdir(dir, S_IRWXU|S_IRWXG|S_IROTH|S_IXOTH) != 0) && (errno != EEXIST))
showErrorAndExit(2, dir);
sprintf(dir, "%s/.parallelrealities/starfighter", userHome);
if ((mkdir(dir, S_IRWXU|S_IRWXG|S_IROTH|S_IXOTH) != 0) && (errno != EEXIST))
showErrorAndExit(2, dir);
sprintf(engine.userHomeDirectory, "%s/.parallelrealities/starfighter/", userHome);
}
#endif
/*
Chugg chugg chugg.... brrr... chugg chugg chugg...brrrrrr... chugg ch..
BRRRRRRRRRRRRRRRRRMMMMMMMMMMMMMMMMMMM!! Well, hopefully anyway! ;)
*/
void initSystem()
{
strcpy(engine.userHomeDirectory, "");
#if LINUX
setupUserHomeDirectory();
#endif
/* Initialize the SDL library */
if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO) < 0) {
printf("Couldn't initialize SDL: %s\n", SDL_GetError());
exit(1);
}
currentGame.useSound = 1;
currentGame.useMusic = 1;
currentGame.fullScreen = 0;
char filename[PATH_MAX];
int fullScreen = 0, useSound = 1, useMusic = 1;
FILE *fp;
sprintf(filename, "%sconf", engine.userHomeDirectory);
fp = fopen(filename, "rb");
if (fp != NULL)
{
fscanf(fp, "%d %d %d", &fullScreen, &useSound, &useMusic);
fclose(fp);
}
currentGame.fullScreen = fullScreen;
currentGame.useSound = useSound;
currentGame.useMusic = useMusic;
SDL_WM_SetCaption("Project: Starfighter", "starfighter");
SDL_WM_SetIcon(loadImage("gfx/alienDevice.png"), NULL);
if (currentGame.fullScreen)
graphics.screen = SDL_SetVideoMode(800, 600, 16, SDL_HWPALETTE|SDL_FULLSCREEN);
else
graphics.screen = SDL_SetVideoMode(800, 600, 0, SDL_HWPALETTE);
if (graphics.screen == NULL) {
printf("Couldn't set 800x600x16 video mode: %s\n", SDL_GetError());
exit(1);
}
if (engine.useAudio)
{
if (Mix_OpenAudio(22050, AUDIO_S16, engine.useAudio, 1024) < 0)
{
printf("Warning: Couldn't set 22050 Hz 16-bit audio - Reason: %s\n", Mix_GetError());
printf("Sound and Music will be disabled\n");
engine.useAudio = 0;
}
}
SDL_ShowCursor(SDL_DISABLE);
SDL_EventState(SDL_MOUSEMOTION, SDL_DISABLE);
}
/*
Removes [hopefully] all the resources that has been
loaded and created during the game. This is called by
atexit();
*/
void cleanUp()
{
printf("Cleaning Up...\n");
printf("Freeing Graphics\n");
graphics.freeGraphics();
printf("Freeing Background\n");
SDL_FreeSurface(graphics.background);
printf("Freeing Sounds\n");
freeSound();
printf("Resetting Lists\n");
resetLists();
delete(engine.bulletHead);
delete(engine.explosionHead);
delete(engine.collectableHead);
delete(graphics.bufferHead);
printf("Freeing Font\n");
for (int i = 0 ; i < MAX_FONTSHAPES ; i++)
{
if (graphics.fontShape[i] != NULL)
SDL_FreeSurface(graphics.fontShape[i]);
}
printf("Removing Mod\n");
char filename[PATH_MAX];
strcpy(filename, "");
sprintf(filename, "%smusic.mod", engine.userHomeDirectory);
remove(filename);
sprintf(filename, "%smusic.s3m", engine.userHomeDirectory);
remove(filename);
if (engine.useAudio)
{
printf("Closing Audio\n");
Mix_CloseAudio();
}
// Save the config using current settings
FILE *fp;
sprintf(filename, "%sconf", engine.userHomeDirectory);
fp = fopen(filename, "wb");
if (fp != NULL)
{
fprintf(fp, "%d %d %d\n", currentGame.fullScreen, currentGame.useSound, currentGame.useMusic);
fclose(fp);
}
else
{
printf("Error saving config\n");
}
SDL_Quit();
printf("Done Cleaning Up...\nThank You for playing Starfighter\n");
}

49
code/init.h Normal file
View File

@ -0,0 +1,49 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include <string.h>
#include <time.h>
#if LINUX
#include <sys/stat.h>
#include <pwd.h>
#include <unistd.h>
#include <errno.h>
#endif
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_mixer.h"
#include "defs.h"
#include "structs.h"
#include "classes.h"
extern void freeSound();
extern void resetLists();
extern void getPlayerInput();
extern void drawString(char *in, int x, int y, int fontColor);
extern SDL_Surface *loadImage(char *filename);
extern globalEngineVariables engine;
extern Game currentGame;
extern Graphics graphics;
extern Star star[200];

869
code/intermission.cpp Normal file
View File

@ -0,0 +1,869 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "intermission.h"
/*
Drives the cursor. Is used by some other screens too
*/
void doCursor()
{
getPlayerInput();
Math::limitInt(&engine.cursor_x, 10, 790);
Math::limitInt(&engine.cursor_y, 10, 590);
graphics.blit(graphics.shape[0], engine.cursor_x, engine.cursor_y);
}
/*
Sets the player's current status information lines. These are the lines
that are scrolled up the screen when the player clicks on Current Status
These are set only once.
*/
void setStatusLines()
{
char string[50];
sprintf(string, "System : %s", systemNames[currentGame.system]);
graphics.textSurface(0, string, 0, 0, FONT_WHITE);
signed char total = 0;
signed char completed = 0;
for (int i = 0 ; i < 10 ; i++)
{
if (systemPlanet[i].missionNumber > -1)
{
switch(systemPlanet[i].missionCompleted)
{
case 0:
total++;
break;
case 1:
total++;
completed++;
break;
}
}
}
for (int i = 0 ; i < 30 ; i++)
graphics.textSurface(i, "", 0, 0, FONT_WHITE);
sprintf(string, "Missions Completed : %d/%d", completed, total);
graphics.textSurface(1, string, 0, 0, FONT_WHITE);
sprintf(string, "Shots Fired : %d", currentGame.shots);
graphics.textSurface(2, string, 0, 0, FONT_WHITE);
sprintf(string, "Hits Scored : %d", currentGame.hits);
graphics.textSurface(3, string, 0, 0, FONT_WHITE);
sprintf(string, "Accuracy : %d%%", currentGame.accuracy);
graphics.textSurface(4, string, 0, 0, FONT_WHITE);
sprintf(string, "Enemies Killed by Others : %d", currentGame.totalOtherKills);
graphics.textSurface(5, string, 0, 0, FONT_WHITE);
sprintf(string, "Total Cash Earned : %d", currentGame.cashEarned);
graphics.textSurface(6, string, 0, 0, FONT_WHITE);
graphics.textSurface(7, "*** Chris ***", 0, 0, FONT_WHITE);
sprintf(string, "Enemies Killed : %d", currentGame.totalKills);
graphics.textSurface(8, string, 0, 0, FONT_WHITE);
sprintf(string, "Shield Restores Picked Up : %d", currentGame.shieldPickups);
graphics.textSurface(9, string, 0, 0, FONT_WHITE);
sprintf(string, "Plasma Cells Picked Up : %d", currentGame.cellPickups);
graphics.textSurface(10, string, 0, 0, FONT_WHITE);
sprintf(string, "Rockets Picked Up : %d", currentGame.rocketPickups);
graphics.textSurface(11, string, 0, 0, FONT_WHITE);
sprintf(string, "Powerups Picked Up : %d", currentGame.rocketPickups);
graphics.textSurface(12, string, 0, 0, FONT_WHITE);
sprintf(string, "Mines Destroyed : %d", currentGame.minesKilled);
graphics.textSurface(13, string, 0, 0, FONT_WHITE);
sprintf(string, "Slaves Rescued : %d", currentGame.slavesRescued);
graphics.textSurface(14, string, 0, 0, FONT_WHITE);
sprintf(string, "Cargo Picked Up : %d", currentGame.cargoPickups);
graphics.textSurface(15, string, 0, 0, FONT_WHITE);
if (currentGame.hasWingMate1)
{
graphics.textSurface(16, "*** Phoebe ***", 0, 0, FONT_WHITE);
sprintf(string, "Enemies Killed : %d", currentGame.wingMate1Kills);
graphics.textSurface(17, string, 0, 0, FONT_WHITE);
sprintf(string, "Ejections : %d", currentGame.wingMate1Ejects);
graphics.textSurface(18, string, 0, 0, FONT_WHITE);
}
if (currentGame.hasWingMate2)
{
graphics.textSurface(19, "*** Ursula ***", 0, 0, FONT_WHITE);
sprintf(string, "Enemies Killed : %d", currentGame.wingMate2Kills);
graphics.textSurface(20, string, 0, 0, FONT_WHITE);
sprintf(string, "Ejections : %d", currentGame.wingMate2Ejects);
graphics.textSurface(21, string, 0, 0, FONT_WHITE);
}
signed char percentage = 0;
if ((currentGame.secondaryMissions > 0) && (currentGame.secondaryMissionsCompleted > 0))
percentage = (currentGame.secondaryMissionsCompleted / currentGame.secondaryMissions) * 100;
sprintf(string, "Seconday Missions Completed : %d / %d (%d%%)", currentGame.secondaryMissionsCompleted, currentGame.secondaryMissions, percentage);
graphics.textSurface(24, string, 0, 0, FONT_WHITE);
int timeTaken = currentGame.timeTaken;
signed char clock = 0;
while (timeTaken > 3599)
{
clock++;
timeTaken -= 3600;
}
sprintf(string, "Total Time : %.2d", clock);
clock = 0;
while (timeTaken > 59)
{
clock++;
timeTaken -= 60;
}
sprintf(string, "%s:%.2d:%.2d", string, clock, timeTaken);
graphics.textSurface(26, string, -1, 0, FONT_WHITE);
graphics.textSurface(27, "Current Status", -1, 0, FONT_WHITE);
graphics.textShape[0].y = 400;
graphics.textShape[0].x = 150;
for (int i = 1 ; i < 25 ; i++)
{
graphics.textShape[i].y = graphics.textShape[i - 1].y + 20;
if ((i == 7) || (i == 16) || (i == 19))
graphics.textShape[i].y += 25;
graphics.textShape[i].x = 150;
}
graphics.textShape[26].y = 404;
graphics.textShape[27].y = 83;
}
/*
Sets the names and stats of the planets within the current system.
This will later be placed into a data file.
*/
void setSystemPlanets()
{
FILE *fp;
char string[100];
strcpy(string, "");
switch (currentGame.system)
{
case 0:
strcpy(string, "data/planets_spirit.dat");
break;
case 1:
strcpy(string, "data/planets_eyananth.dat");
break;
case 2:
strcpy(string, "data/planets_mordor.dat");
break;
case 3:
strcpy(string, "data/planets_sol.dat");
break;
}
#if USEPACK
int dataLocation = locateDataInPak(string, 1);
fp = fopen(PACKLOCATION, "rb");
fseek(fp, dataLocation, SEEK_SET);
#else
fp = fopen(string, "rb");
#endif
int distance;
char name[50];
int image;
for (int i = 0 ; i < 10 ; i++)
{
fscanf(fp, "%d %s %d", &distance, name, &image);
systemPlanet[i].y = distance;
strcpy(systemPlanet[i].name, name);
systemPlanet[i].image = graphics.shape[image];
}
int messageMission;
int messageSlot;
char face[50];
char from[100];
char subject[100];
for (int i = 0 ; i < 10 ; i++)
{
fscanf(fp, "%d %d %s%*c", &messageMission, &messageSlot, face);
fscanf(fp, "%[^\n]%*c", from);
fscanf(fp, "%[^\n]%*c", subject);
systemPlanet[i].messageMission = messageMission;
systemPlanet[i].messageSlot = messageSlot;
systemPlanet[i].faceImage = getFace(face);
strcpy(systemPlanet[i].from, from);
strcpy(systemPlanet[i].subject, subject);
}
fclose(fp);
}
/*
Spins the planets around the sun, spaced according to their Y value
as defined in setSystemPlanets(). Moving the cursor over the planet
will show their name and their current status
*/
signed char showSystem(float x, float y)
{
SDL_Rect r;
signed char planet = 0;
int planetSpace = systemPlanet[planet].y;
signed char rtn = 0;
// Blit the sun
graphics.blit(graphics.shape[30], 370, 220);
for (int i = 50 ; i < 300 ; i+= planetSpace)
{
x *= 0.75;
y *= 0.75;
graphics.circle(400, 250, i, graphics.screen, graphics.darkGrey);
r.x = int(400 + (sin(x) * i));
r.y = int(250 + (cos(y) * i));
r.w = 10;
r.h = 10;
r.x -= (systemPlanet[planet].image->w / 2);
r.y -= (systemPlanet[planet].image->h / 2);
graphics.blit(systemPlanet[planet].image, r.x, r.y);
if (Collision::collision(engine.cursor_x + 13, engine.cursor_y + 13, 6, 6, r.x, r.y, systemPlanet[planet].image->w, systemPlanet[planet].image->h))
{
graphics.drawString(systemPlanet[planet].name, -1, 545, FONT_WHITE);
if ((engine.keyState[SDLK_LCTRL]) || (engine.keyState[SDLK_RCTRL]))
{
if (currentGame.system == 0)
{
currentGame.stationedPlanet = planet;
currentGame.destinationPlanet = planet;
currentGame.area = systemPlanet[currentGame.stationedPlanet].missionNumber;
strcpy(currentGame.stationedName, systemPlanet[currentGame.stationedPlanet].name);
}
else
{
currentGame.destinationPlanet = planet;
strcpy(currentGame.destinationName, systemPlanet[currentGame.destinationPlanet].name);
}
rtn = 1;
engine.keyState[SDLK_LCTRL] = engine.keyState[SDLK_RCTRL] = 0;
}
}
planet++;
if (systemPlanet[planet].y == -1)
break;
planetSpace = systemPlanet[planet].y;
}
return rtn;
}
/*
Scrolls the player's current information up the screen. When
the specified status line reaches a certain Y value, the entire
list is reset and the information lines begin again from the bottom
(in other words, they loop around).
*/
void showStatus(SDL_Surface *infoSurface)
{
graphics.blit(infoSurface, 100, 80);
for (int i = 0 ; i < 22 ; i++)
{
graphics.textShape[i].y -= 0.25;
if ((graphics.textShape[i].y > 80) && (graphics.textShape[i].y < 400))
graphics.blitText(i);
}
if (graphics.textShape[21].y < 65)
{
graphics.textShape[0].y = 400;
for (int i = 1 ; i < 25 ; i++)
{
graphics.textShape[i].y = graphics.textShape[i - 1].y + 20;
if ((i == 7) || (i == 16) || (i == 19))
graphics.textShape[i].y += 25;
}
}
graphics.blevelRect(100, 80, 600, 20, 0x00, 0x00, 0x99);
graphics.blevelRect(100, 400, 600, 20, 0x00, 0x00, 0x99);
graphics.blitText(26);
graphics.blitText(27);
}
void createOptions(SDL_Surface *optionsSurface)
{
SDL_FillRect(optionsSurface, NULL, graphics.black);
graphics.blevelRect(optionsSurface, 0, 0, optionsSurface->w - 2, optionsSurface->h - 2, 0x00, 0x00, 0x44);
graphics.drawString("++ OPTIONS ++", 105, 8, FONT_WHITE, optionsSurface);
graphics.blevelRect(optionsSurface, 190, 45, 50, 22, 0x00, 0x00, 0x00);
graphics.blevelRect(optionsSurface, 250, 45, 50, 22, 0x00, 0x00, 0x00);
graphics.blevelRect(optionsSurface, 20, 45, 150, 22, 0x00, 0x00, 0x00);
if (currentGame.useSound)
graphics.blevelRect(optionsSurface, 190, 45, 50, 22, 0xff, 0x00, 0x00);
else
graphics.blevelRect(optionsSurface, 250, 45, 50, 22, 0xff, 0x00, 0x00);
graphics.drawString("ON", 207, 50, FONT_WHITE, optionsSurface);
graphics.drawString("OFF", 263, 50, FONT_WHITE, optionsSurface);
graphics.drawString("SOUND", 30, 50, FONT_WHITE, optionsSurface);
graphics.blevelRect(optionsSurface, 190, 95, 50, 22, 0x00, 0x00, 0x00);
graphics.blevelRect(optionsSurface, 250, 95, 50, 22, 0x00, 0x00, 0x00);
graphics.blevelRect(optionsSurface, 20, 95, 150, 22, 0x00, 0x00, 0x00);
if (currentGame.useMusic)
graphics.blevelRect(optionsSurface, 190, 95, 50, 22, 0xff, 0x00, 0x00);
else
graphics.blevelRect(optionsSurface, 250, 95, 50, 22, 0xff, 0x00, 0x00);
graphics.drawString("ON", 207, 100, FONT_WHITE, optionsSurface);
graphics.drawString("OFF", 263, 100, FONT_WHITE, optionsSurface);
graphics.drawString("MUSIC", 30, 100, FONT_WHITE, optionsSurface);
graphics.blevelRect(optionsSurface, 190, 145, 50, 22, 0x00, 0x00, 0x00);
graphics.blevelRect(optionsSurface, 250, 145, 50, 22, 0x00, 0x00, 0x00);
graphics.blevelRect(optionsSurface, 20, 145, 150, 22, 0x00, 0x00, 0x00);
if (currentGame.fullScreen)
graphics.blevelRect(optionsSurface, 190, 145, 50, 22, 0xff, 0x00, 0x00);
else
graphics.blevelRect(optionsSurface, 250, 145, 50, 22, 0xff, 0x00, 0x00);
graphics.drawString("ON", 207, 150, FONT_WHITE, optionsSurface);
graphics.drawString("OFF", 263, 150, FONT_WHITE, optionsSurface);
graphics.drawString("FULLSCREEN", 30, 150, FONT_WHITE, optionsSurface);
graphics.blevelRect(optionsSurface, 20, 195, 150, 22, 0x00, 0x00, 0x00);
graphics.blevelRect(optionsSurface, 190, 195, 110, 22, 0x00, 0x00, 0x00);
if (currentGame.autoSaveSlot == -1)
{
graphics.drawString("NONE", 225, 200, FONT_WHITE, optionsSurface);
}
else
{
char string[] = "Slot %d";
sprintf(string, "Slot %d", currentGame.autoSaveSlot + 1);
graphics.blevelRect(optionsSurface, 190, 195, 110, 22, 0xff, 0x00, 0x00);
graphics.drawString(string, 225, 200, FONT_WHITE, optionsSurface);
}
graphics.drawString("AUTOSAVE SLOT", 30, 200, FONT_WHITE, optionsSurface);
}
void showOptions(SDL_Surface *optionsSurface)
{
if ((engine.keyState[SDLK_LCTRL]) || (engine.keyState[SDLK_RCTRL]))
{
if (Collision::collision(engine.cursor_x + 13, engine.cursor_y + 13, 6, 6, 417, 172, 45, 22))
currentGame.useSound = 1;
if (Collision::collision(engine.cursor_x + 13, engine.cursor_y + 13, 6, 6, 478, 172, 45, 22))
currentGame.useSound = 0;
if (Collision::collision(engine.cursor_x + 13, engine.cursor_y + 13, 6, 6, 417, 222, 45, 22))
{
currentGame.useMusic = 1;
if (engine.useAudio)
{
if (Mix_PausedMusic() == 1)
Mix_ResumeMusic();
else
Mix_PlayMusic(engine.music, -1);
}
}
if (Collision::collision(engine.cursor_x + 13, engine.cursor_y + 13, 6, 6, 478, 222, 45, 22))
{
currentGame.useMusic = 0;
if (engine.useAudio)
Mix_PauseMusic();
}
if (Collision::collision(engine.cursor_x + 13, engine.cursor_y + 13, 6, 6, 417, 272, 45, 22))
{
if (!currentGame.fullScreen)
{
#if LINUX
SDL_WM_ToggleFullScreen(graphics.screen);
#else
graphics.screen = SDL_SetVideoMode(800, 600, 16, SDL_HWSURFACE|SDL_HWPALETTE|SDL_FULLSCREEN);
graphics.drawBackground();
flushBuffer();
#endif
currentGame.fullScreen = 1;
}
}
if (Collision::collision(engine.cursor_x + 13, engine.cursor_y + 13, 6, 6, 478, 272, 45, 22))
{
if (currentGame.fullScreen)
{
#if LINUX
SDL_WM_ToggleFullScreen(graphics.screen);
#else
graphics.screen = SDL_SetVideoMode(800, 600, 0, SDL_HWSURFACE|SDL_HWPALETTE);
graphics.drawBackground();
flushBuffer();
#endif
currentGame.fullScreen = 0;
}
}
if (Collision::collision(engine.cursor_x + 13, engine.cursor_y + 13, 6, 6, 417, 322, 100, 22))
{
Math::wrapChar(&(++currentGame.autoSaveSlot), -1, 4);
engine.keyState[SDLK_LCTRL] = engine.keyState[SDLK_RCTRL] = 0;
}
createOptions(optionsSurface);
}
}
/*
Oddly named function that controls the entire intermission
screen. This simply draws a background, stars, gridlines and the icons
at the bottom of the screen. Will call (and continue to call) the specified
functions when the player has selected an icon.
*/
int galaxyMap()
{
graphics.freeGraphics();
checkForBossMission(); // double check just to make sure!
// Tell the game we are not in a mission so
// do not perform certain keyboard actions
engine.gameSection = SECTION_INTERMISSION;
graphics.clearScreen(graphics.black);
graphics.updateScreen();
graphics.clearScreen(graphics.black);
initSaveSlots();
SDL_Delay(1000);
loadMusic("music/3DParadise.mod");
loadBackground((char *)systemBackground[currentGame.system]);
char string[25];
engine.cursor_x = engine.cursor_y = 500;
graphics.shape[0] = loadImage("gfx/cursor.bmp");
// Icons 1 - 29
for (int i = 0 ; i < 26 ; i++)
{
sprintf(string, "gfx/icon%d.bmp", (i + 1));
graphics.shape[i + 1] = loadImage(string);
}
graphics.shape[27] = loadImage("gfx/buyIcon.bmp");
graphics.shape[28] = loadImage("gfx/sellIcon.bmp");
graphics.shape[29] = loadImage("gfx/firefly1.png");
// Planets 30 - 39
graphics.shape[30] = loadImage("gfx/planet_sun.gif");
graphics.shape[31] = loadImage("gfx/planet_green.gif");
graphics.shape[32] = loadImage("gfx/planet_blue.gif");
graphics.shape[33] = loadImage("gfx/planet_red.gif");
graphics.shape[34] = loadImage("gfx/planet_orange.gif");
// Faces (as defines)
graphics.shape[FACE_CHRIS] = loadImage("gfx/face_chris.png");
graphics.shape[FACE_SID] = loadImage("gfx/face_sid.png");
graphics.shape[FACE_KRASS] = loadImage("gfx/face_krass.png");
graphics.shape[FACE_PHOEBE] = loadImage("gfx/face_phoebe.png");
graphics.shape[FACE_URSULA] = loadImage("gfx/face_ursula.png");
graphics.shape[FACE_KLINE] = loadImage("gfx/face_kline.png");
engine.done = 0;
engine.keyState[SDLK_LCTRL] = engine.keyState[SDLK_RCTRL] = 0;
engine.ssx = engine.ssy = 0;
SDL_Rect r;
SDL_Rect destRect;
int distance = 0;
int interceptionChance = 0;
setStatusLines();
initShop();
setSystemPlanets();
SDL_Surface *statsSurface = graphics.alphaRect(600, 330, 0x00, 0x00, 0x99);
SDL_Surface *savesSurface = graphics.createSurface(350, 300);
SDL_Surface *optionsSurface = graphics.createSurface(320, 240);
SDL_Surface *commsSurface = graphics.createSurface(450, 400);
createSavesSurface(savesSurface, -1);
createOptions(optionsSurface);
createCommsSurface(commsSurface);
signed char section = 1;
float sinX = 300;
float cosY = 300;
signed char movePlanets = 1;
signed char saveSlot = -1;
if (currentGame.system > 0)
interceptionChance = (300 / currentGame.system);
// There is no chance of being interceptted after the final attack on Earth
if ((currentGame.system == 3) && (systemPlanet[2].missionCompleted))
interceptionChance = 0;
int rtn = 0;
if ((engine.useAudio) && (currentGame.useMusic))
Mix_PlayMusic(engine.music, -1);
textObject iconInfo[12];
iconInfo[0].image = graphics.textSurface("Start Next Mission", FONT_WHITE);
iconInfo[1].image = graphics.textSurface("View System Map", FONT_WHITE);
iconInfo[2].image = graphics.textSurface("Current Status", FONT_WHITE);
iconInfo[3].image = graphics.textSurface("Save Game", FONT_WHITE);
iconInfo[4].image = graphics.textSurface("Upgrade FIREFLY", FONT_WHITE);
iconInfo[5].image = graphics.textSurface("Comms", FONT_WHITE);
iconInfo[6].image = graphics.textSurface("Options", FONT_WHITE);
iconInfo[7].image = graphics.textSurface("Exit to Title Screen", FONT_WHITE);
sprintf(string, "System : %s", systemNames[currentGame.system]);
iconInfo[8].image = graphics.textSurface(string, FONT_WHITE);
sprintf(string, "Stationed At: %s", systemPlanet[currentGame.stationedPlanet].name);
iconInfo[9].image = graphics.textSurface(string, FONT_WHITE);
strcpy(string, "Destination: None");
if (currentGame.destinationPlanet > -1)
sprintf(string, "Destination: %s", systemPlanet[currentGame.destinationPlanet].name);
iconInfo[10].image = graphics.textSurface(string, FONT_WHITE);
for (int i = 0 ; i < 9 ; i++)
iconInfo[i].x = (800 - iconInfo[i].image->w) / 2;
iconInfo[11].image = graphics.textSurface("Go to Destination Planet", FONT_WHITE);
signed char redrawBackGround = 1;
player.maxShield = (25 * currentGame.shieldUnits);
if (currentGame.distanceCovered > 0)
section = 0;
else
player.shield = player.maxShield;
unsigned long frameLimit = SDL_GetTicks();
flushInput();
engine.keyState[SDLK_LCTRL] = engine.keyState[SDLK_RCTRL] = engine.keyState[SDLK_SPACE] = 0;
engine.done = 0;
while (!engine.done)
{
graphics.updateScreen();
if (redrawBackGround)
{
graphics.drawBackGround();
redrawBackGround = 0;
}
else
{
graphics.unBuffer();
}
doStarfield();
r.x = 0;
r.y = 0;
r.h = 600;
r.w = 1;
for (int i = 40 ; i < 800 ; i+= 40)
{
r.x = i;
SDL_FillRect(graphics.screen, &r, graphics.darkerBlue);
}
r.x = 0;
r.y = 0;
r.h = 1;
r.w = 800;
for (int i = 40 ; i < 600 ; i+= 40)
{
r.y = i;
SDL_FillRect(graphics.screen, &r, graphics.darkerBlue);
}
if (rand() % 1000 < 2)
{
engine.ssx = Math::rrand(100, 100);
engine.ssy = Math::rrand(100, 100);
engine.ssx /= 100;
engine.ssy /= 100;
}
graphics.blit(iconInfo[8].image, (int)iconInfo[8].x, 15);
switch(section)
{
case 0:
if (currentGame.stationedPlanet == currentGame.destinationPlanet)
{
currentGame.area = systemPlanet[currentGame.stationedPlanet].missionNumber;
rtn = 2;
engine.done = 1;
}
else
{
distance = abs(currentGame.stationedPlanet - currentGame.destinationPlanet);
distance = (5 / distance);
if (distance < 1)
distance = 1;
SDL_FreeSurface(iconInfo[9].image);
iconInfo[9].image = graphics.textSurface(systemPlanet[currentGame.stationedPlanet].name, FONT_WHITE);
SDL_FreeSurface(iconInfo[10].image);
iconInfo[10].image = graphics.textSurface(systemPlanet[currentGame.destinationPlanet].name, FONT_WHITE);
section = 8;
destRect.x = 180;
destRect.y = 450;
destRect.w = 1;
if (currentGame.distanceCovered > 0)
destRect.w = currentGame.distanceCovered;
destRect.h = 20;
}
break;
case 1:
if (engine.keyState[SDLK_SPACE])
{
movePlanets = !movePlanets;
engine.keyState[SDLK_SPACE] = 0;
}
if (movePlanets)
{
sinX += 0.01;
cosY += 0.01;
}
if (showSystem(sinX, cosY))
{
if (currentGame.system == 0)
{
sprintf(string, "Stationed At: %s", systemPlanet[currentGame.stationedPlanet].name);
SDL_FreeSurface(iconInfo[9].image);
iconInfo[9].image = graphics.textSurface(string, FONT_WHITE);
updateCommsSurface(commsSurface);
}
else
{
sprintf(string, "Destination: %s", systemPlanet[currentGame.destinationPlanet].name);
SDL_FreeSurface(iconInfo[10].image);
iconInfo[10].image = graphics.textSurface(string, FONT_WHITE);
}
}
graphics.blit(iconInfo[9].image, 90, 450);
if ((currentGame.system > 0) && (currentGame.stationedPlanet != currentGame.destinationPlanet))
graphics.blit(iconInfo[10].image, 550, 450);
break;
case 2:
showStatus(statsSurface);
break;
case 3:
graphics.blit(savesSurface, 200, 100);
saveSlot = showSaveSlots(savesSurface, saveSlot);
break;
case 4:
showShop();
break;
case 5:
graphics.blit(commsSurface, 170, 70);
doComms(commsSurface);
break;
case 6:
graphics.blit(optionsSurface, 230, 130);
showOptions(optionsSurface);
break;
case 7:
rtn = 0;
engine.done = 1;
break;
case 8:
showSystem(sinX, cosY);
graphics.blit(systemPlanet[currentGame.stationedPlanet].image, 150, 450);
graphics.blit(iconInfo[9].image, 135, 480);
graphics.blit(systemPlanet[currentGame.destinationPlanet].image, 650, 450);
graphics.blit(iconInfo[10].image, 635, 480);
destRect.w += distance;
SDL_FillRect(graphics.screen, &destRect, graphics.red);
if (destRect.w >= 450)
{
currentGame.stationedPlanet = currentGame.destinationPlanet;
currentGame.distanceCovered = 0;
player.shield = player.maxShield;
sprintf(string, "Stationed At: %s", systemPlanet[currentGame.stationedPlanet].name);
strcpy(currentGame.stationedName, systemPlanet[currentGame.stationedPlanet].name);
SDL_FreeSurface(iconInfo[9].image);
iconInfo[9].image = graphics.textSurface(string, FONT_WHITE);
updateCommsSurface(commsSurface);
section = 1;
redrawBackGround = 1;
}
if (interceptionChance > 0)
{
if ((rand() % interceptionChance) == 0)
{
currentGame.area = MAX_MISSIONS - 1;
rtn = 2;
engine.done = 1;
currentGame.distanceCovered = destRect.w;
}
}
break;
}
graphics.addBuffer(300, 545, 200, 15);
if (section != 8)
{
for (int i = 0 ; i < 8 ; i++)
{
// if the mission has been completed, there is no "Start Next Mission" icon
if (i == 0)
{
if ((currentGame.stationedPlanet == currentGame.destinationPlanet) && (systemPlanet[currentGame.stationedPlanet].missionCompleted != 0))
continue;
else if (currentGame.stationedPlanet == currentGame.destinationPlanet)
graphics.blit(graphics.shape[1], 80 + (i * 90), 500);
else if (currentGame.stationedPlanet != currentGame.destinationPlanet)
graphics.blit(graphics.shape[26], 80 + (i * 90), 500);
}
else
{
graphics.blit(graphics.shape[i + 1], 80 + (i * 90), 500);
}
if (Collision::collision(engine.cursor_x + 13, engine.cursor_y + 13, 6, 6, 80 + (i * 90), 500, 32, 32))
{
if (i != 0)
{
graphics.blit(iconInfo[i].image, (int)iconInfo[i].x, 545);
}
else
{
if (currentGame.stationedPlanet == currentGame.destinationPlanet)
graphics.blit(iconInfo[0].image, (int)iconInfo[i].x, 545);
else
graphics.blit(iconInfo[11].image, (int)iconInfo[i].x, 545);
}
if ((engine.keyState[SDLK_LCTRL]) || (engine.keyState[SDLK_RCTRL]))
{
redrawBackGround = 1;
section = i;
engine.keyState[SDLK_LCTRL] = engine.keyState[SDLK_RCTRL] = 0;
}
}
}
}
engine.keyState[SDLK_LCTRL] = engine.keyState[SDLK_RCTRL] = engine.keyState[SDLK_SPACE] = 0;
doCursor();
// Limit us to 60 frame a second
while (SDL_GetTicks() < (frameLimit + 16)){}
frameLimit = SDL_GetTicks();
}
Mix_HaltMusic();
SDL_FreeSurface(statsSurface);
SDL_FreeSurface(savesSurface);
SDL_FreeSurface(optionsSurface);
SDL_FreeSurface(commsSurface);
for (int i = 0 ; i < 12 ; i++)
SDL_FreeSurface(iconInfo[i].image);
player.maxShield = (25 * currentGame.shieldUnits);
if (currentGame.distanceCovered == 0)
player.shield = player.maxShield;
return rtn;
}

56
code/intermission.h Normal file
View File

@ -0,0 +1,56 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_mixer.h"
#include "defs.h"
#include "structs.h"
#include "classes.h"
extern SDL_Surface *loadImage(char *filename);
extern void doStarfield();
extern void getPlayerInput();
extern void showShop();
extern void initShop();
extern int initSaveSlots();
extern int showSaveSlots(SDL_Surface *savesSurface, signed char saveSlot);
extern void saveGame(int slot);
extern void loadMusic(char *filename);
extern void loadBackground(char *filename);
extern void createCommsSurface(SDL_Surface *comms);
extern void updateCommsSurface(SDL_Surface *comms);
extern void createSavesSurface(SDL_Surface *savesSurface, signed char clickedSlot);
extern void checkForBossMission();
extern void doComms(SDL_Surface *comms);
extern int locateDataInPak(char *file, signed char required);
extern int getFace(char *face);
extern void flushInput();
extern globalEngineVariables engine;
extern object player;
extern Game currentGame;
extern Graphics graphics;
extern Planet systemPlanet[10];

253
code/loadSave.cpp Normal file
View File

@ -0,0 +1,253 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "loadSave.h"
/*
Reads in each save game that it finds and gives it an appropriate
description using the area variable contained in the game binary
data. It returns the slot number (1 - 10) of the most recently
used file. On the title screen, this is used to determine whether
a player can "Continue Current Game" and "Load Saved Game".
*/
int initSaveSlots()
{
char fileName[PATH_MAX];
int imagePos = 350;
Game tempGame;
struct stat fileInfo;
int modTime = 0;
int continueSaveIndex = 0;
FILE *fp;
//READ SAVE GAME DATA
for (int i = 0 ; i < 5 ; i++)
{
sprintf(fileName, "%ssave%.2d.dat", engine.userHomeDirectory, (i + 1));
fp = fopen(fileName, "rb");
if (fp == NULL)
{
sprintf(saveSlot[i], "%.2d - Empty", (i + 1));
if (engine.gameSection == SECTION_TITLE)
graphics.textSurface(13 + i, saveSlot[i], -1, imagePos, FONT_WHITE);
}
else
{
if (fread(&tempGame, sizeof(Game), 1, fp) != 1)
{
sprintf(saveSlot[i], "%.2d - Corrupt Game Data", (i + 1));
}
else
{
sprintf(saveSlot[i], "%.2d - %s, %s", (i + 1), systemNames[tempGame.system], tempGame.stationedName);
if (engine.gameSection == SECTION_TITLE)
graphics.textSurface(13 + i, saveSlot[i], -1, imagePos, FONT_WHITE);
}
if (stat(fileName, &fileInfo) != -1)
{
if (fileInfo.st_mtime > modTime)
{modTime = fileInfo.st_mtime; continueSaveIndex = (i + 1);}
}
fclose(fp);
}
imagePos += 20;
}
return continueSaveIndex;
}
/*
Fill in later...
*/
signed char loadGame(int slot)
{
char filename[PATH_MAX];
FILE *fp;
sprintf(filename, "%ssave%.2d.dat", engine.userHomeDirectory, slot);
fp = fopen(filename, "rb");
if (fp == NULL)
return 0;
if (fread(&currentGame, sizeof(Game), 1, fp) != 1)
{
printf("Save game error. The file was not of the expected format.\n");
fclose(fp);
return 0;
}
fclose(fp);
weapon[0] = currentGame.playerWeapon;
weapon[1] = currentGame.playerWeapon2;
player = currentGame.thePlayer;
// Re-init all the planets in this system...
initPlanetMissions(currentGame.system);
// ... and then override with completition status
for (int i = 0 ; i < 10 ; i++)
systemPlanet[i].missionCompleted = currentGame.missionCompleted[i];
return 1;
}
void saveGame(int slot)
{
if ((slot < 1) || (slot > 5))
{
printf("Error - Saves may only be 1 to 5\n");
return;
}
FILE *fp;
char fileName[PATH_MAX];
sprintf(fileName, "%ssave%.2d.dat", engine.userHomeDirectory, slot);
fp = fopen(fileName, "wb");
currentGame.playerWeapon = weapon[0];
currentGame.playerWeapon2 = weapon[1];
currentGame.thePlayer = player;
for (int i = 0 ; i < 10 ; i++)
currentGame.missionCompleted[i] = systemPlanet[i].missionCompleted;
if (fp != NULL)
{
if (fwrite(&currentGame, sizeof(Game), 1, fp) != 1)
{
printf("Error Saving Game to Slot %d\n", slot);
}
fclose(fp);
}
else
{
printf("Error Saving Game to Slot %d\n", slot);
}
// Recall to update the save slots... (lazy, yes)
initSaveSlots();
engine.keyState[SDLK_LCTRL] = engine.keyState[SDLK_RCTRL] = 0;
}
void createSavesSurface(SDL_Surface *savesSurface, signed char clickedSlot)
{
graphics.blevelRect(savesSurface, 0, 0, 348, 298, 0x00, 0x00, 0x00);
int y = 10;
for (int i = 0 ; i < 5 ; i++)
{
if (clickedSlot == i)
graphics.blevelRect(savesSurface, 5, y, 338, 25, 0x99, 0x00, 0x00);
else
graphics.blevelRect(savesSurface, 5, y, 338, 25, 0x00, 0x00, 0x99);
graphics.drawString(saveSlot[i], 70, y + 5, FONT_WHITE, savesSurface);
y += 30;
}
graphics.drawString("*** HELP ***", 120, 170, FONT_WHITE, savesSurface);
switch(clickedSlot)
{
case 0:
case 1:
case 2:
case 3:
case 4:
graphics.blevelRect(savesSurface, 5, 265, 100, 25, 0x00, 0x99, 0x00);
graphics.blevelRect(savesSurface, 125, 265, 100, 25, 0x99, 0x99, 0x00);
graphics.blevelRect(savesSurface, 243, 265, 100, 25, 0x99, 0x00, 0x00);
graphics.drawString("SAVE", 40, 270, FONT_WHITE, savesSurface);
graphics.drawString("CANCEL", 150, 270, FONT_WHITE, savesSurface);
graphics.drawString("DELETE", 270, 270, FONT_WHITE, savesSurface);
graphics.drawString("SAVE will save the game", 17, 200, FONT_WHITE, savesSurface);
graphics.drawString("CANCEL will unselect that slot", 17, 220, FONT_WHITE, savesSurface);
graphics.drawString("DELETE will remove the save", 17, 240, FONT_WHITE, savesSurface);
break;
case -1:
graphics.drawString("First click a Save game slot to use", 17, 200, FONT_WHITE, savesSurface);
break;
case -10:
graphics.drawString("Game Saved", 130, 200, FONT_WHITE, savesSurface);
break;
case -11:
graphics.drawString("Save Deleted", 130, 200, FONT_WHITE, savesSurface);
break;
}
engine.keyState[SDLK_LCTRL] = engine.keyState[SDLK_RCTRL] = 0;
}
/*
Displays the save slot available. For use with an interface that
has the cursor enabled. It returns the index number of the slot clicked
so that the function invoking it can perform a load or save on that slot.
*/
int showSaveSlots(SDL_Surface *savesSurface, signed char saveSlot)
{
SDL_Rect r;
r.x = 201;
r.y = 115;
r.w = 348;
r.h = 25;
int clickedSlot = -1;
if ((engine.keyState[SDLK_LCTRL]) || (engine.keyState[SDLK_RCTRL]))
{
for (int i = 0 ; i < 5 ; i++)
{
if (Collision::collision(engine.cursor_x + 13, engine.cursor_y + 13, 6, 6, r.x, r.y, r.w, r.h))
{
clickedSlot = i;
createSavesSurface(savesSurface, i);
}
r.y += 30;
}
if (Collision::collision(engine.cursor_x + 13, engine.cursor_y + 13, 6, 6, 215, 365, 100, 25))
{
saveGame(saveSlot + 1);
createSavesSurface(savesSurface, -10);
}
if (Collision::collision(engine.cursor_x + 13, engine.cursor_y + 13, 6, 6, 335, 365, 100, 25))
createSavesSurface(savesSurface, -1);
if (Collision::collision(engine.cursor_x + 13, engine.cursor_y + 13, 6, 6, 453, 365, 100, 25))
{
char filename[PATH_MAX];
sprintf(filename, "%ssave%.2d.dat", engine.userHomeDirectory, (saveSlot + 1));
remove(filename);
initSaveSlots();
createSavesSurface(savesSurface, -11);
}
}
if (clickedSlot > -1)
saveSlot = clickedSlot;
return saveSlot;
}

44
code/loadSave.h Normal file
View File

@ -0,0 +1,44 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_mixer.h"
#include "defs.h"
#include "structs.h"
#include "classes.h"
char saveSlot[10][25];
extern void getPlayerInput();
extern void initPlanetMissions(signed char system);
extern globalEngineVariables engine;
extern object player;
extern object weapon[MAX_WEAPONS];
extern Game currentGame;
extern Graphics graphics;
extern Planet systemPlanet[10];

232
code/messages.cpp Normal file
View File

@ -0,0 +1,232 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "messages.h"
void setKillMessages()
{
strcpy(killMessage[0], "Chalk another one up for me!");
strcpy(killMessage[1], "That'll teach you!");
strcpy(killMessage[2], "One more for me!");
strcpy(killMessage[3], "Target destroyed!");
strcpy(killMessage[4], "You aint so tough!");
strcpy(killMessage[5], "Kicked your ass!");
strcpy(killMessage[6], "That takes me up to %d");
strcpy(killMessage[7], "Hey %s, you asleep over there?!");
strcpy(killMessage[8], "I'm catching up with you, %s!");
strcpy(killMessage[9], "Number One, Baby!");
}
void setPlayerDeadMessages()
{
strcpy(deathMessage[0], "Oh my God... No!");
strcpy(deathMessage[1], "NOOOOOOOOOOOOOOOOOOOOOOOOOOO!!!!");
strcpy(deathMessage[2], "Please tell me that didn't just happen...");
strcpy(deathMessage[3], "Chris, Answer Me!!");
strcpy(deathMessage[4], "What the hell happened?!");
strcpy(deathMessage[5], "Chriiiiiiiiiiiiiiiiiiiiiiiiiiis!!!!");
}
void setMissFireMessages()
{
strcpy(missFireMessage[0], "I am NOT your enemy!");
strcpy(missFireMessage[1], "Hey! Watch it!");
strcpy(missFireMessage[2], "What are you doing?! Shoot THEM!");
strcpy(missFireMessage[3], "OW!!! I hope that was an accident!");
strcpy(missFireMessage[4], "Open your eyes!!");
}
void setHitPlayerMessages()
{
strcpy(playerHitMessage[0], "Oops! Sorry!");
strcpy(playerHitMessage[1], "Get out of the way!");
strcpy(playerHitMessage[2], "Don't fly into my missiles!");
}
void setAllyMessages()
{
setKillMessages();
setPlayerDeadMessages();
setMissFireMessages();
setHitPlayerMessages();
}
void getKillMessage(object *ally)
{
char in[50], name[30], otherName[30];
int kills, difference;
signed char firstPlace = 0;
int faceToUse = FACE_PHOEBE;
if (ally == &enemy[FR_PHOEBE])
{
strcpy(name, "Phoebe");
strcpy(otherName, "Ursula");
kills = currentGame.wingMate1Kills;
difference = currentGame.wingMate1Kills - currentGame.wingMate2Kills;
if ((currentGame.wingMate1Kills > currentGame.wingMate2Kills) && (currentGame.wingMate1Kills > currentGame.totalKills))
firstPlace = 1;
faceToUse = FACE_PHOEBE;
}
else
{
strcpy(name, "Ursula");
strcpy(otherName, "Phoebe");
kills = currentGame.wingMate2Kills;
difference = currentGame.wingMate2Kills - currentGame.wingMate1Kills;
if ((currentGame.wingMate2Kills > currentGame.wingMate1Kills) && (currentGame.wingMate2Kills > currentGame.totalKills))
firstPlace = 1;
faceToUse = FACE_URSULA;
}
int r = rand() % 10;
if (currentGame.hasWingMate2 == 0)
r = rand() % 7;
switch(r)
{
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
sprintf(in, killMessage[rand() % 6]);
break;
case 6:
case 7:
sprintf(in, killMessage[6], kills);
break;
case 8:
if (difference > 0)
{
sprintf(in, killMessage[7], otherName);
}
else
{
sprintf(in, killMessage[8], otherName);
}
break;
case 9:
if (firstPlace == 1)
{
sprintf(in, killMessage[9]);
}
else
{
sprintf(in, killMessage[rand() % 6]);
}
break;
}
setRadioMessage(faceToUse, in, 0);
}
char *getKlineInsult()
{
static char insult[][40] = {
"Pathetic", "How very disappointing...", "Heroic. And stupid", "Fool", "And now you're nothing but a DEAD hero"
};
if (currentGame.area != 26)
return (insult[rand() % 3]);
else
return (insult[3 + (rand() % 2)]);
}
void getPlayerDeathMessage()
{
if (enemy[WC_KLINE].active)
{
setRadioMessage(FACE_KLINE, getKlineInsult(), 1);
return;
}
if ((enemy[WC_BOSS].active) && (enemy[WC_BOSS].classDef == CD_KRASS))
{
setRadioMessage(FACE_KRASS, "That was the easiest $90,000,000 I've ever earned! Bwwah!! Ha!! Ha!! Ha!!", 1);
return;
}
char name[30], in[50];
int faceToUse = FACE_PHOEBE;
strcpy(name, "Phoebe");
faceToUse = FACE_PHOEBE;
if (currentGame.hasWingMate2)
{
if ((rand() % 2) == 0)
{
strcpy(name, "Ursula");
faceToUse = FACE_URSULA;
}
}
sprintf(in, deathMessage[rand() % 6]);
setRadioMessage(faceToUse, in, 1);
}
void getMissFireMessage(object *ally)
{
char name[30], in[50];
int faceToUse = FACE_PHOEBE;
if (ally == &enemy[FR_PHOEBE])
{
strcpy(name, "Phoebe");
faceToUse = FACE_PHOEBE;
}
else
{
strcpy(name, "Ursula");
faceToUse = FACE_URSULA;
}
sprintf(in, missFireMessage[rand() % 5]);
setRadioMessage(faceToUse, in, 0);
}
void getPlayerHitMessage(object *ally)
{
char name[30], in[50];
int faceToUse = FACE_PHOEBE;
if (ally == &enemy[FR_PHOEBE])
{
strcpy(name, "Phoebe");
faceToUse = FACE_PHOEBE;
}
else
{
strcpy(name, "Ursula");
faceToUse = FACE_URSULA;
}
sprintf(in, playerHitMessage[rand() % 3]);
setRadioMessage(faceToUse, in, 0);
}

40
code/messages.h Normal file
View File

@ -0,0 +1,40 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include <string.h>
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_mixer.h"
#include "defs.h"
#include "structs.h"
extern void setRadioMessage(signed char face, char *in, int priority);
char killMessage[10][50];
char deathMessage[6][50];
char missFireMessage[5][50];
char playerHitMessage[3][50];
extern object enemy[MAX_ALIENS];
extern Game currentGame;

473
code/misc.cpp Normal file
View File

@ -0,0 +1,473 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "misc.h"
void clearInfoLines()
{
for (int i = 0 ; i < 4 ; i++)
{
graphics.textShape[i].life = 0;
}
}
// from a to b
void copyInfoLine(int a, int b)
{
graphics.textSurface(b, graphics.textShape[a].text, -1, 0, graphics.textShape[a].fontColor);
graphics.textShape[b].life = graphics.textShape[a].life;
}
/*
Sets one of the three information lines on the screen. The accepts the
string and colors. It will set the information to the first free infoline
it finds (top to bottom). If it doesn't find any free ones, it will push
all the other info lines down one and add itself to the top.
*/
void setInfoLine(char *in, int color)
{
int index = -1;
for (int i = 0 ; i < 3 ; i++)
{
if ((graphics.textShape[i].life == 0) && (index == -1))
{
index = i;
}
}
// Bump down
if (index == -1)
{
index = 2;
copyInfoLine(1, 0);
copyInfoLine(2, 1);
}
graphics.textSurface(index, in, -1, 0, color);
graphics.textShape[index].life = 240;
}
/*
Sets a radio message that appears at the top of the screen. Used for
script events, etc. We send a message priority too, since we don't want
Phoebe or Ursula's banter to interrupt an important message
*/
void setRadioMessage(signed char face, char *in, int priority)
{
if ((graphics.textShape[3].life > 0) && (priority == 0))
return;
graphics.textSurface(3, in, -1, 50, FONT_WHITE);
graphics.textShape[3].life = 240;
SDL_Surface *faceShape = NULL;
if (face > -1)
faceShape = graphics.shape[face];
graphics.createMessageBox(faceShape, in, 1);
}
void doTargetArrow()
{
if ((engine.targetArrowTimer == 0) || (enemy[engine.targetIndex].shield < 1))
return;
if (enemy[engine.targetIndex].flags & FL_ISCLOAKED)
return;
if (graphics.textShape[3].life > 0)
return;
engine.targetArrow = -1;
if (engine.targetArrowTimer > 0)
engine.targetArrowTimer--;
int distX = (int)(enemy[engine.targetIndex].x - player.x);
int distY = (int)(enemy[engine.targetIndex].y - player.y);
if (distY < -300)
engine.targetArrow = 36;
if (distY > 300)
engine.targetArrow = 40;
if (distX < -400)
engine.targetArrow = 42;
if (distX > 400)
engine.targetArrow = 38;
if ((distY < -300) && (distX > 400))
engine.targetArrow = 37;
if ((distY > 300) && (distX > 400))
engine.targetArrow = 39;
if ((distY > 300) && (distX < -400))
engine.targetArrow = 41;
if ((distY < -300) && (distX < -400))
engine.targetArrow = 43;
if (engine.targetArrow != -1)
{
graphics.blit(graphics.shape[engine.targetArrow], 380, 50);
graphics.blit(graphics.shape[44], 365, 70);
}
}
/*
Fill in later...
*/
void doInfo()
{
int shieldColor = 0;
SDL_Rect bar;
signed char fontColor;
char text[25];
graphics.addBuffer(0, 20, 800, 25);
graphics.addBuffer(0, 545, 800, 25);
if (engine.minutes > -1)
{
if ((engine.minutes == 0) && (engine.seconds <= 29))
fontColor = FONT_RED;
else if ((engine.minutes == 0) && (engine.seconds > 29))
fontColor = FONT_YELLOW;
else
fontColor = FONT_WHITE;
graphics.blitText(10); // time remaining
sprintf(text, "%.2d:%.2d", engine.minutes, engine.seconds);
graphics.drawString(text, 410, 21, fontColor);
}
if (currentGame.area != MAX_MISSIONS - 1)
{
graphics.blitText(9); // mission objectives
sprintf(text, "%d", (currentMission.remainingObjectives1 + currentMission.remainingObjectives2));
graphics.drawString(text, 745, 21, FONT_WHITE);
}
graphics.blitText(8); // cash
sprintf(text, "%.6d", currentGame.cash);
graphics.drawString(text, 90, 21, FONT_WHITE);
doTargetArrow();
fontColor = FONT_WHITE;
if (player.ammo[0] > 0)
{
if (player.ammo[0] <= 25) fontColor = FONT_YELLOW;
if (player.ammo[0] <= 10) fontColor = FONT_RED;
}
graphics.blitText(5); // plasma ammo
sprintf(text, "%.3d", player.ammo[0]);
graphics.drawString(text, 320, 551, fontColor);
graphics.blitText(6);
if ((player.weaponType[1] != W_CHARGER) && (player.weaponType[1] != W_LASER))
{
if (player.ammo[1] == 1)
fontColor = FONT_RED;
else
fontColor = FONT_WHITE;
sprintf(text, "%.3d", player.ammo[1]); // rocket ammo
graphics.drawString(text, 465, 551, fontColor);
}
if (((player.weaponType[1] == W_CHARGER) || (player.weaponType[1] == W_LASER)) && (player.ammo[1] > 0))
{
int c = graphics.white;
if (player.ammo[1] > 100)
c = graphics.red;
bar.x = 450;
bar.y = 550;
bar.h = 12;
for (int i = 0 ; i < (player.ammo[1] / 5) ; i++)
{
bar.w = 1;
SDL_FillRect(graphics.screen, &bar, c);
bar.x += 2;
}
}
if ((!allMissionsCompleted()) && (SDL_GetTicks() >= engine.counter2))
{
engine.timeTaken++;
engine.counter2 = SDL_GetTicks() + 1000;
if (engine.missionCompleteTimer == 0)
checkScriptEvents();
}
if ((engine.timeMission) && (!engine.cheatTime) && (player.shield > 0))
{
if (SDL_GetTicks() >= engine.counter)
{
if ((engine.seconds > 1) && (engine.seconds <= 11) && (engine.minutes == 0))
{
playSound(SFX_CLOCK);
}
if (engine.seconds > 0)
{
engine.seconds--;
engine.counter = (SDL_GetTicks() + 1000);
}
else if ((engine.seconds == 0) && (engine.minutes > 0))
{
engine.minutes--;
engine.seconds = 59;
engine.counter = (SDL_GetTicks() + 1000);
for (int i = 0 ; i < 3 ; i++)
{
if (currentMission.timeLimit1[i] > -1)
currentMission.timeLimit1[i]--;
if (currentMission.timeLimit2[i] > -1)
currentMission.timeLimit2[i]--;
}
checkTimer();
checkScriptEvents();
}
if ((engine.seconds == 0) && (engine.minutes == 0))
{
for (int i = 0 ; i < 3 ; i++)
{
if (currentMission.timeLimit1[i] > -1)
currentMission.timeLimit1[i]--;
if (currentMission.timeLimit2[i] > -1)
currentMission.timeLimit2[i]--;
}
checkTimer();
checkScriptEvents();
//engine.counter = 0;
engine.counter = (SDL_GetTicks() + 1000);
}
}
}
for (int i = 0 ; i < 3 ; i++)
{
if (graphics.textShape[i].life > 0)
{
graphics.textShape[i].y = (525 - (i * 20));
graphics.blitText(i);
graphics.textShape[i].life--;
if (graphics.textShape[i].life == 0)
{
copyInfoLine(i + 1, i);
copyInfoLine(i + 2, i + 1);
graphics.textShape[2].life = 0;
}
}
}
// Show the radio message if there is one
if (graphics.textShape[3].life > 0)
{
graphics.blit(graphics.messageBox, (800 - graphics.messageBox->w) / 2, 50);
graphics.textShape[3].life--;
}
// Do the target's remaining shield (if required)
if (currentGame.area != 10)
{
if ((engine.targetIndex > -1) && (enemy[engine.targetIndex].shield > 0) && (engine.targetIndex > 9))
{
graphics.blitText(7);
bar.w = 1;
bar.h = 12;
bar.x = 620;
bar.y = 550;
for (float i = 0 ; i < (engine.targetShield * enemy[engine.targetIndex].shield) ; i++)
{
if (i > 50)
shieldColor = graphics.green;
else if ((i >= 25) && (i <= 50))
shieldColor = graphics.yellow;
else
shieldColor = graphics.red;
SDL_FillRect(graphics.screen, &bar, shieldColor);
bar.x += 2;
}
}
}
graphics.blitText(11);
bar.w = 25;
bar.h = 12;
bar.x = 80;
bar.y = 571;
SDL_FillRect(graphics.screen, &bar, graphics.green);
for (int i = 1 ; i < currentGame.maxPlasmaDamage ; i++)
{
bar.x += 30;
if (weapon[1].damage >= (i + 1))
SDL_FillRect(graphics.screen, &bar, graphics.green);
else
SDL_FillRect(graphics.screen, &bar, graphics.darkGreen);
}
graphics.blitText(12);
bar.w = 25;
bar.h = 12;
bar.x = 315;
bar.y = 571;
SDL_FillRect(graphics.screen, &bar, graphics.yellow);
for (int i = 1 ; i < currentGame.maxPlasmaDamage ; i++)
{
bar.x += 30;
if (weapon[1].ammo[0] >= (i + 1))
SDL_FillRect(graphics.screen, &bar, graphics.yellow);
else
SDL_FillRect(graphics.screen, &bar, graphics.darkYellow);
}
graphics.blitText(13);
bar.w = 25;
bar.h = 12;
bar.x = 550;
bar.y = 571;
for (int i = 15 ; i > (currentGame.maxPlasmaRate - 1) ; i -= 2)
{
if (weapon[1].reload[0] <= i)
SDL_FillRect(graphics.screen, &bar, graphics.blue);
else
SDL_FillRect(graphics.screen, &bar, graphics.darkerBlue);
bar.x += 30;
}
graphics.blitText(4);
if (player.shield < 1)
return;
if ((!engine.keyState[SDLK_SPACE]) && (player.weaponType[1] == W_LASER) && (engine.eventTimer % 8 == 1))
Math::limitChar(&(--player.ammo[1]), 1, 255);
if ((engine.eventTimer < 30) && (player.shield <= engine.lowShield))
return;
signed char blockSize = 1;
bar.w = blockSize;
bar.h = 12;
bar.x = 95;
bar.y = 550;
for (int i = 0 ; i < player.shield ; i += blockSize)
{
if (i >= engine.averageShield)
shieldColor = graphics.green;
else if ((i >= engine.lowShield) && (i < engine.averageShield))
shieldColor = graphics.yellow;
else
shieldColor = graphics.red;
SDL_FillRect(graphics.screen, &bar, shieldColor);
bar.x += blockSize;
if (player.maxShield < 75)
bar.x++;
}
}
int getFace(char *face)
{
for (int i = 0 ; i < 7 ; i++)
{
if (strcmp(faces[i], face) == 0)
return 90 + i;
}
return -1;
}
void resetLists()
{
object *ob, *ob2;
collectables *c1, *c2;
bRect *r1, *r2;
ob = engine.bulletHead->next;
while(ob != NULL)
{
ob2 = ob;
ob = ob->next;
delete ob2;
}
engine.bulletHead->next = NULL;
engine.bulletTail = engine.bulletHead;
ob = engine.explosionHead->next;
while(ob != NULL)
{
ob2 = ob;
ob = ob->next;
delete ob2;
}
engine.explosionHead->next = NULL;
engine.explosionTail = engine.explosionHead;
c1 = engine.collectableHead->next;
while (c1 != NULL)
{
c2 = c1;
c1 = c1->next;
delete c2;
}
engine.collectableHead->next = NULL;
engine.collectableTail = engine.collectableHead;
r1 = graphics.bufferHead->next;
while (r1 != NULL)
{
r2 = r1;
r1 = r1->next;
delete r2;
}
graphics.bufferHead->next = NULL;
graphics.bufferTail = graphics.bufferHead;
ob = engine.debrisHead->next;
while(ob != NULL)
{
ob2 = ob;
ob = ob->next;
delete ob2;
}
engine.debrisHead->next = NULL;
engine.debrisTail = engine.debrisHead;
}

44
code/misc.h Normal file
View File

@ -0,0 +1,44 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include <string.h>
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_mixer.h"
#include "defs.h"
#include "structs.h"
#include "classes.h"
extern signed char allMissionsCompleted();
extern void playSound(int sid);
extern void checkTimer();
extern void checkScriptEvents();
extern globalEngineVariables engine;
extern devVariables dev;
extern object player;
extern object enemy[MAX_ALIENS];
extern object weapon[MAX_WEAPONS];
extern mission currentMission;
extern Game currentGame;
extern Graphics graphics;

1460
code/missions.cpp Normal file

File diff suppressed because it is too large Load Diff

52
code/missions.h Normal file
View File

@ -0,0 +1,52 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include <string.h>
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_mixer.h"
#include "defs.h"
#include "structs.h"
#include "classes.h"
extern SDL_Surface *loadImage(char *file_name);
extern void playRandomTrack();
extern void getPlayerInput();
extern void setInfoLine(char *in, int color);
extern void loadGameGraphics();
extern void killAllAliens();
extern int locateDataInPak(char *file, signed char required);
extern void setRadioMessage(signed char face, char *in, int priority);
extern void syncScriptEvents();
extern void loadMusic(char *filename);
extern void setTarget(int index);
extern void flushInput();
extern globalEngineVariables engine;
extern object player;
extern object enemy[MAX_ALIENS];
extern mission currentMission;
extern Game currentGame;
extern Graphics graphics;
extern Planet systemPlanet[10];
extern mission missions[MAX_MISSIONS];

429
code/player.cpp Normal file
View File

@ -0,0 +1,429 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "player.h"
/*
Initialises the player for a new game.
*/
void initPlayer()
{
player.active = 1;
player.x = 200;
player.y = 200;
player.speed = 2;
player.maxShield = (25 * currentGame.shieldUnits);
player.systemPower = player.maxShield;
player.face = 0;
player.image[0] = graphics.shipShape[0];
player.image[1] = graphics.shipShape[1];
player.engineX = player.image[0]->w;
player.engineY = (player.image[0]->h / 2);
player.owner = &player;
player.flags = FL_FRIEND;
player.weaponType[0] = W_PLAYER_WEAPON;
if (player.ammo[0] > 0)
{
player.weaponType[0] = W_PLAYER_WEAPON2;
}
else
{
player.weaponType[0] = W_PLAYER_WEAPON;
weapon[1] = weapon[0]; // reset to weapon 1 defaults
}
player.hit = 0;
engine.lowShield = (player.maxShield / 3);
engine.averageShield = engine.lowShield + engine.lowShield;
if (player.weaponType[1] == W_CHARGER)
player.ammo[1] = 0;
if (player.weaponType[1] == W_LASER)
player.ammo[1] = 1;
}
void doPlayer()
{
// This causes the motion to slow
engine.ssx *= 0.99;
engine.ssy *= 0.99;
int shapeToUse;
if (player.shield > -100)
{
if (player.shield > 0)
{
if ((engine.keyState[SDLK_LCTRL]) || (engine.keyState[SDLK_RCTRL]))
fireBullet(&player, 0);
if ((engine.keyState[SDLK_SPACE]) && (player.weaponType[1] != W_NONE))
{
if ((player.weaponType[1] != W_CHARGER) && (player.weaponType[1] != W_LASER) && (player.ammo[1] > 0))
{
fireBullet(&player, 1);
}
if (player.weaponType[1] == W_LASER)
{
if (player.ammo[1] < 100)
{
fireBullet(&player, 1);
player.ammo[1] += 2;
if (player.ammo[1] >= 100)
{
player.ammo[1] = 200;
setInfoLine("Laser Overheat!!", FONT_WHITE);
}
}
}
}
if (player.weaponType[1] == W_CHARGER)
{
if (engine.keyState[SDLK_SPACE])
{
Math::limitChar(&(++player.ammo[1]), 0, 200);
}
else
{
if (player.ammo[1] > 0)
fireBullet(&player, 1);
player.ammo[1] = 0;
}
}
if ((engine.keyState[SDLK_LSHIFT]) || (engine.keyState[SDLK_RSHIFT]))
{
if (player.ammo[0] < 1)
{
if (weapon[0].ammo[0] == 3)
{
if (weapon[0].flags & WF_THIN_SPREAD)
{
weapon[0].flags -= WF_THIN_SPREAD;
weapon[0].flags += WF_STRAIGHT;
setInfoLine("Weapon set to Concentrate", FONT_WHITE);
}
else
{
weapon[0].flags -= WF_STRAIGHT;
weapon[0].flags += WF_THIN_SPREAD;
setInfoLine("Weapon set to Spread", FONT_WHITE);
}
}
}
else
{
if (weapon[1].ammo[0] == 3)
{
if (weapon[1].flags & WF_THIN_SPREAD)
{
weapon[1].flags -= WF_THIN_SPREAD;
weapon[1].flags += WF_STRAIGHT;
setInfoLine("Weapon set to Concentrate", FONT_WHITE);
}
else
{
weapon[1].flags -= WF_STRAIGHT;
weapon[1].flags += WF_THIN_SPREAD;
setInfoLine("Weapon set to Spread", FONT_WHITE);
}
}
else if (weapon[1].ammo[0] == 4)
{
if (weapon[1].flags & WF_THIN_SPREAD)
{
weapon[1].flags -= WF_THIN_SPREAD;
weapon[1].flags += WF_STRAIGHT;
setInfoLine("Weapon set to Concentrate", FONT_WHITE);
}
else
{
weapon[1].flags -= WF_STRAIGHT;
weapon[1].flags += WF_THIN_SPREAD;
setInfoLine("Weapon set to Spread", FONT_WHITE);
}
}
else if (weapon[1].ammo[0] == 5)
{
if (weapon[1].flags & WF_WIDE_SPREAD)
{
if (weapon[1].flags & WF_THIN_SPREAD)
weapon[1].flags -= WF_THIN_SPREAD;
weapon[1].flags -= WF_WIDE_SPREAD;
weapon[1].flags += WF_STRAIGHT;
setInfoLine("Weapon set to Concentrate", FONT_WHITE);
}
else
{
if (weapon[1].flags & WF_THIN_SPREAD)
weapon[1].flags -= WF_THIN_SPREAD;
weapon[1].flags -= WF_STRAIGHT;
weapon[1].flags += WF_WIDE_SPREAD;
setInfoLine("Weapon set to Spread", FONT_WHITE);
}
}
}
engine.keyState[SDLK_LSHIFT] = engine.keyState[SDLK_RSHIFT] = 0;
}
Math::limitChar(&--player.reload[0], 0, 999);
Math::limitChar(&--player.reload[1], 0, 999);
if (engine.keyState[SDLK_UP])
{
player.y -= player.speed;
engine.ssy += 0.1;
}
if (engine.keyState[SDLK_DOWN])
{
player.y += player.speed;
engine.ssy -= 0.1;
}
if (engine.keyState[SDLK_LEFT])
{
player.x -= player.speed;
engine.ssx += 0.1;
player.face = 1;
}
if (engine.keyState[SDLK_RIGHT])
{
player.x += player.speed;
engine.ssx -= 0.1;
player.face = 0;
}
if (engine.keyState[SDLK_ESCAPE])
{
if ((engine.done == 0) && (engine.gameSection == SECTION_GAME) && (currentMission.remainingObjectives1 == 0))
{
playSound(SFX_FLY);
engine.done = 2;
engine.missionCompleteTimer = (SDL_GetTicks() - 1);
}
}
if (engine.keyState[SDLK_p])
{
engine.paused = 1;
engine.keyState[SDLK_p] = 0;
}
if ((engine.keyState[SDLK_t]) && (currentGame.area != 10))
{
if (engine.targetArrowTimer == -1)
engine.targetArrowTimer = 0;
else
engine.targetArrowTimer = -1;
engine.keyState[SDLK_t] = 0;
}
if ((engine.missionCompleteTimer == 0) && (engine.targetArrowTimer == -1))
{
if ((enemy[engine.targetIndex].shield < 1) && (currentGame.area != 10))
{
engine.targetIndex = rand() % MAX_ALIENS;
if (enemy[engine.targetIndex].flags & FL_FRIEND)
engine.targetIndex = 0;
else
setTarget(engine.targetIndex);
}
}
if (((currentGame.area == 18) && (enemy[WC_BOSS].shield > 0)) || (currentGame.area == 24))
player.face = 0;
if (engine.done == 0)
{
Math::limitFloat(&player.x, 100, 700);
Math::limitFloat(&player.y, 100, 500);
}
if (player.shield > engine.lowShield)
addEngine(&player);
shapeToUse = player.face;
if (player.hit)
shapeToUse += SHIP_HIT_INDEX;
Math::limitChar(&--player.hit, 0, 100);
graphics.blit(graphics.shipShape[shapeToUse], (int)player.x, (int)player.y);
if ((player.shield <= engine.lowShield) && (rand() % 5 < 1))
addExplosion(player.x + Math::rrand(-10, 10), player.y + Math::rrand(-10, 20), E_SMOKE);
}
else
{
player.active = 0;
player.shield--;
if (player.shield == -1)
{
if ((currentGame.hasWingMate1) || (enemy[WC_KLINE].active))
getPlayerDeathMessage();
// Make it look like the ships are all still moving...
if (currentGame.area == 18)
{
for (int i = 0 ; i < MAX_ALIENS ; i++)
enemy[i].flags += FL_LEAVESECTOR;
}
playSound(SFX_DEATH);
playSound(SFX_EXPLOSION);
}
engine.keyState[SDLK_UP] = engine.keyState[SDLK_DOWN] = engine.keyState[SDLK_LEFT] = engine.keyState[SDLK_RIGHT] = 0;
if ((rand() % 3) == 0)
addExplosion(player.x + Math::rrand(-10, 10), player.y + Math::rrand(-10, 10), E_BIG_EXPLOSION);
if (player.shield == -99)
addDebris((int)player.x, (int)player.y, player.maxShield);
}
}
Math::limitFloat(&engine.ssx, -3, 3);
Math::limitFloat(&engine.ssy, -3, 3);
// Specific for the mission were you have to chase the Executive Transport
if ((currentGame.area == 18) && (enemy[WC_BOSS].shield > 0) && (player.shield > 0))
{
engine.ssx = -6;
engine.ssy = 0;
}
if (currentGame.area == 24)
{
engine.ssx = -6;
engine.ssy = 0;
}
player.dx = engine.ssx;
player.dy = engine.ssy;
}
void flushInput()
{
for (int i = 0 ; i < 350 ; i++)
engine.keyState[i] = 0;
while (SDL_PollEvent(&engine.event)){}
}
void getPlayerInput()
{
if (engine.gameSection == SECTION_INTERMISSION)
{
// Get the current mouse position
int x, y;
SDL_GetMouseState(&x, &y);
engine.cursor_x = x;
engine.cursor_y = y;
}
if (SDL_PollEvent(&engine.event))
{
switch (engine.event.type)
{
case SDL_QUIT:
exit(0);
break;
case SDL_MOUSEBUTTONDOWN:
if (engine.gameSection == SECTION_INTERMISSION)
{
if (engine.event.button.button == SDL_BUTTON_LEFT) engine.keyState[SDLK_LCTRL] = 1;
if (engine.event.button.button == SDL_BUTTON_RIGHT) engine.keyState[SDLK_SPACE] = 1;
}
break;
case SDL_KEYDOWN:
if (engine.gameSection == SECTION_TITLE)
addKeyEvent(SDL_GetKeyName(engine.event.key.keysym.sym));
engine.keyState[engine.event.key.keysym.sym] = 1;
if (engine.gameSection != SECTION_GAME)
engine.paused = 0;
break;
case SDL_KEYUP:
if (engine.event.key.keysym.sym != SDLK_p)
engine.keyState[engine.event.key.keysym.sym] = 0;
break;
default:
break;
}
}
}
void leaveSector()
{
engine.keyState[SDLK_UP] = engine.keyState[SDLK_DOWN] = engine.keyState[SDLK_LEFT] = engine.keyState[SDLK_RIGHT] = 0;
engine.keyState[SDLK_LCTRL] = engine.keyState[SDLK_RCTRL] = engine.keyState[SDLK_SPACE] = 0;
if (engine.done == 0)
engine.done = 3;
if (engine.done == 3)
{
player.face = 0;
if (player.x > -100)
{
player.x += engine.ssx;
engine.ssx -= 1;
if (player.y > 300)
player.y--;
if (player.y < 300)
player.y++;
}
if (player.x <= -100)
{
engine.done = 2;
playSound(SFX_FLY);
}
}
if (engine.done == 2)
{
player.face = 0;
player.x += 12;
engine.ssx -= 0.2;
if (player.x > 1600)
engine.done = 1;
}
}

50
code/player.h Normal file
View File

@ -0,0 +1,50 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include <string.h>
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_mixer.h"
#include "defs.h"
#include "structs.h"
#include "classes.h"
extern void fireBullet(object *attacker, int weaponType);
extern void addExplosion(float x, float y, int type);
extern void playSound(int sid);
extern void addEngine(object *craft);
extern void addKeyEvent(char *keyName);
extern void addDebris(int x, int y, int amount);
extern void setRadioMessage(signed char face, char *in, int priority);
extern void setInfoLine(char *in, int color);
extern void getPlayerDeathMessage();
extern void playSound(int sid);
extern void setTarget(int index);
extern globalEngineVariables engine;
extern object player;
extern mission currentMission;
extern Game currentGame;
extern object weapon[MAX_WEAPONS];
extern object enemy[MAX_ALIENS];
extern Graphics graphics;

221
code/resources.cpp Normal file
View File

@ -0,0 +1,221 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "resources.h"
void loadBackground(char *filename)
{
if (graphics.background != NULL)
{
SDL_FreeSurface(graphics.background);
graphics.background = NULL;
}
graphics.background = loadImage(filename);
SDL_SetColorKey(graphics.background, 0, 0);
}
void loadGameGraphics()
{
int index;
char string[75];
graphics.freeGraphics();
graphics.shipShape[0] = loadImage("gfx/firefly1.png");
graphics.shipShape[1] = loadImage("gfx/firefly2.png");
strcpy(string, "");
switch(currentGame.system)
{
case 0:
strcpy(string, "data/resources_spirit.dat");
break;
case 1:
strcpy(string, "data/resources_eyananth.dat");
break;
case 2:
strcpy(string, "data/resources_mordor.dat");
break;
case 3:
strcpy(string, "data/resources_sol.dat");
break;
}
FILE *fp;
#if USEPACK
int dataLocation = locateDataInPak(string, 1);
fp = fopen(PACKLOCATION, "rb");
fseek(fp, dataLocation, SEEK_SET);
#else
fp = fopen(string, "rb");
#endif
if (fp == NULL)
exit(1);
fscanf(fp, "%d %s", &index, string);
while (index != -1)
{
graphics.shipShape[index] = loadImage(string);
fscanf(fp, "%d %s", &index, string);
}
fclose(fp);
/*
Overlay a red alpha surface onto
*/
SDL_Surface *hitRect;
for (int i = SHIP_HIT_INDEX ; i < MAX_SHIPSHAPES ; i++)
{
if (graphics.shipShape[i - SHIP_HIT_INDEX] == NULL)
continue;
graphics.shipShape[i] = graphics.createSurface(graphics.shipShape[i - SHIP_HIT_INDEX]->w, graphics.shipShape[i- SHIP_HIT_INDEX]->h);
graphics.blit(graphics.shipShape[i - SHIP_HIT_INDEX], 0, 0, graphics.shipShape[i]);
hitRect = graphics.alphaRect(graphics.shipShape[i]->w, graphics.shipShape[i]->h, 255, 0, 0);
graphics.blit(hitRect, 0, 0, graphics.shipShape[i]);
SDL_SetColorKey(graphics.shipShape[i], (SDL_SRCCOLORKEY|SDL_RLEACCEL), SDL_MapRGB(graphics.shipShape[i]->format, 127, 0, 0));
SDL_FreeSurface(hitRect);
}
strcpy(string, "data/resources_all.dat");
#if USEPACK
dataLocation = locateDataInPak(string, 1);
fp = fopen(PACKLOCATION, "rb");
fseek(fp, dataLocation, SEEK_SET);
#else
fp = fopen(string, "rb");
#endif
fscanf(fp, "%d %s", &index, string);
while (index != -1)
{
graphics.shape[index] = loadImage(string);
fscanf(fp, "%d %s", &index, string);
}
fclose(fp);
loadBackground((char *)systemBackground[currentGame.system]);
setAlienShapes();
setWeaponShapes();
}
void loadSound()
{
sound[SFX_EXPLOSION] = loadSound("sound/explode.wav");
sound[SFX_HIT] = loadSound("sound/explode2.wav");
sound[SFX_DEATH] = loadSound("sound/maledeath.wav");
sound[SFX_MISSILE] = loadSound("sound/missile.wav");
sound[SFX_PLASMA] = loadSound("sound/plasma.wav");
sound[SFX_CLOCK] = loadSound("sound/clock.wav");
sound[SFX_FLY] = loadSound("sound/flyby.wav");
sound[SFX_ENERGYRAY] = loadSound("sound/beamLaser.wav");
sound[SFX_PICKUP] = loadSound("sound/item.wav");
sound[SFX_SHIELDUP] = loadSound("sound/shield.wav");
sound[SFX_CLOAK] = loadSound("sound/cloak.wav");
sound[SFX_DEBRIS] = loadSound("sound/explode3.wav");
sound[SFX_DEBRIS2] = loadSound("sound/explode4.wav");
sound[SFX_LASER] = loadSound("sound/laser.wav");
sound[SFX_PLASMA2] = loadSound("sound/plasma2.wav");
sound[SFX_PLASMA3] = loadSound("sound/plasma3.wav");
}
void freeSound()
{
for (int i = 0 ; i < MAX_SOUNDS ; i++)
{
if (sound[i] != NULL)
Mix_FreeChunk(sound[i]);
}
if (engine.music != NULL)
Mix_FreeMusic(engine.music);
}
void setFontColor(SDL_Surface *image, int red, int green, int blue)
{
SDL_Color colors[256];
colors[0].r = 0;
colors[0].g = 0;
colors[0].b = 0;
for (int i = 1 ; i < 256 ; i++)
{
colors[i].r = red;
colors[i].g = green;
colors[i].b = blue;
}
SDL_SetPalette(image, SDL_LOGPAL|SDL_PHYSPAL, colors, 0, 256);
}
/*
Custom loading to alter the font color before doing
all other things
*/
void loadFont()
{
SDL_Surface *image, *newImage;
for (int i = 0 ; i < MAX_FONTSHAPES ; i++)
{
#if USEPACK
unpack("gfx/smallFont.bmp", PAK_FONT);
image = IMG_Load_RW(engine.sdlrw, 1);
#else
image = IMG_Load("gfx/smallFont.bmp");
#endif
if (image == NULL) {
printf("Couldn't load game font! (%s) Exitting.\n", SDL_GetError());
exit(1);
}
switch(i)
{
case 1:
setFontColor(image, 255, 0, 0);
break;
case 2:
setFontColor(image, 255, 255, 0);
break;
case 3:
setFontColor(image, 0, 255, 0);
break;
case 4:
setFontColor(image, 0, 255, 255);
break;
case 5:
setFontColor(image, 0, 0, 10);
break;
}
newImage = SDL_DisplayFormat(image);
graphics.fontShape[i] = graphics.setTransparent(newImage);
SDL_FreeSurface(image);
}
}

45
code/resources.h Normal file
View File

@ -0,0 +1,45 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include <string.h>
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_mixer.h"
#include "defs.h"
#include "structs.h"
#include "classes.h"
extern void unpack(char *file, signed char fileType);
extern SDL_Surface *loadImage(char *filename);
extern Mix_Chunk *loadSound(char *filename);
extern int locateDataInPak(char *file, signed char required);
extern void setAlienShapes();
extern void setWeaponShapes();
extern void loadGameGraphics();
extern globalEngineVariables engine;
extern object weapon[MAX_WEAPONS];
extern Mix_Chunk *sound[MAX_SOUNDS];
extern object enemy[MAX_ALIENS];
extern Graphics graphics;
extern Game currentGame;

312
code/script.cpp Normal file
View File

@ -0,0 +1,312 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "script.h"
void setKlineGreeting()
{
char greet[][50] = {
"How nice to see you again, Bainfield!",
"It all ends here, rebel!",
"I hope you won't disappoint me this time...",
"Do you really think you can defeat us?!"
};
gameEvent[0].time = 2;
gameEvent[0].face = FACE_KLINE;
strcpy(gameEvent[0].message, greet[rand() % 4]);
gameEvent[0].entity = -1;
gameEvent[0].flag = 0;
}
void loadScriptEvents()
{
for (int i = 0 ; i < 10 ; i++)
{
gameEvent[i].time = 0;
strcpy(gameEvent[i].message, "");
gameEvent[i].entity = -1;
gameEvent[i].flag = 0;
}
if ((currentGame.area == 27) && (enemy[WC_KLINE].classDef == CD_KLINE))
setKlineGreeting();
char filename[255];
strcpy(filename, "");
sprintf(filename, "data/script%d.txt", currentGame.area);
FILE *fp;
int i = 0;
int time, entity, flags;
char face[255], message[255];
#if USEPACK
int dataLocation = locateDataInPak(filename, 0);
if (dataLocation == -1)
return;
fp = fopen(PACKLOCATION, "rb");
fseek(fp, dataLocation, SEEK_SET);
#else
fp = fopen(filename, "rb");
if (fp == NULL)
return;
#endif
fscanf(fp, "%d ", &time);
while (time != 0)
{
fscanf(fp, "%s %d %d ", face, &entity, &flags);
fscanf(fp, "%[^\n]%*c", message);
gameEvent[i].time = time;
gameEvent[i].face = getFace(face);
gameEvent[i].entity = entity;
gameEvent[i].flag = flags;
strcpy(gameEvent[i].message, message);
i++;
fscanf(fp, "%d ", &time);
}
fclose(fp);
}
void checkScriptEvents()
{
for (int i = 0 ; i < 10 ; i++)
{
if (engine.timeTaken == gameEvent[i].time)
{
if (strcmp(gameEvent[i].message, "@none@") != 0)
{
setRadioMessage(gameEvent[i].face, gameEvent[i].message, 1);
}
if (gameEvent[i].entity > -1)
{
if (gameEvent[i].flag != -FL_ACTIVATE)
{
enemy[gameEvent[i].entity].flags += gameEvent[i].flag;
}
else
{
enemy[gameEvent[i].entity].active = 1;
enemy[gameEvent[i].entity].x = Math::rrand((int)player.x + 400, (int)player.x + 800);
enemy[gameEvent[i].entity].y = Math::rrand((int)player.y - 400, (int)player.y + 800);
}
}
gameEvent[i].time = 0;
}
}
}
void syncScriptEvents()
{
for (int i = 0 ; i < 10 ; i++)
{
if (gameEvent[i].time < 0)
{
gameEvent[i].time = engine.timeTaken + abs(gameEvent[i].time);
}
}
}
void setScene(int scene)
{
FILE *fp;
char string[255], face[255];
float sx, sy, x, y, speed;
int index, shape;
strcpy(string, "");
sprintf(string, "data/cutscene%d.dat", scene);
#if USEPACK
int dataLocation = locateDataInPak(string, 1);
fp = fopen(PACKLOCATION, "rb");
fseek(fp, dataLocation, SEEK_SET);
#else
fp = fopen(string, "rb");
#endif
// Load in the specified background
fscanf(fp, "%s", string);
loadBackground(string);
// Set the star speed
fscanf(fp, "%f %f", &sx, &sy);
engine.ssx = sx;
engine.ssy = sy;
// Read in the specs for each ship
for (int i = 0 ; i < 15 ; i++)
{
fscanf(fp, "%d %d %f %f %f", &index, &shape, &x, &y, &speed);
if (x < 0) x = (rand() % abs((int)x));
if (y < 0) y = (rand() % abs((int)y));
if (speed <= -1) speed = 1 + (rand() % abs((int)speed));
if (shape > -1)
{
enemy[index].image[0] = graphics.shipShape[shape];
enemy[index].x = x;
enemy[index].y = y;
enemy[index].dx = speed;
enemy[index].active = 1;
}
}
// And finally read in the messages
for (int i = 0 ; i < 10 ; i++)
{
fscanf(fp, "%s%*c", face);
fscanf(fp, "%[^\n]", string);
if (strcmp(string, "@none@") == 0)
break;
cutMessage[i].face = getFace(face);
strcpy(cutMessage[i].message, string);
}
fclose(fp);
}
void doCutscene(int scene)
{
graphics.clearScreen(graphics.black);
graphics.updateScreen();
graphics.clearScreen(graphics.black);
SDL_Delay(1000);
engine.keyState[SDLK_LCTRL] = engine.keyState[SDLK_RCTRL] = engine.keyState[SDLK_SPACE] = 0;
engine.ssx = -0.5;
engine.ssy = 0;
graphics.flushBuffer();
graphics.freeGraphics();
resetLists();
loadGameGraphics();
for (int i = 0 ; i < 15 ; i++)
{
enemy[i] = defEnemy[0];
enemy[i].face = 0;
enemy[i].active = 0;
}
for (int i = 0 ; i < 10 ; i++)
{
strcpy(cutMessage[i].message, "");
cutMessage[i].face = -1;
}
setScene(scene);
/*
Because we can fiddle with the images, we need to set the engines to
the correct places on the craft. Otherwise it will look wrong
*/
for (int i = 0 ; i < 15 ; i++)
{
enemy[i].engineX = enemy[i].image[0]->w;
enemy[i].engineY = (enemy[i].image[0]->h / 2);
}
unsigned long frameLimit = SDL_GetTicks();
signed char showMessage = 0;
signed char currentMessage = -1;
int timer = 60 * 4;
graphics.drawBackGround();
SDL_Surface *face;
flushInput();
while (true)
{
graphics.updateScreen();
graphics.unBuffer();
getPlayerInput();
doStarfield();
doExplosions();
for (int i = 0 ; i < 15 ; i++)
{
if (enemy[i].active)
{
addEngine(&enemy[i]);
enemy[i].x += enemy[i].dx;
enemy[i].x += engine.ssx;
graphics.blit(enemy[i].image[0], (int)enemy[i].x, (int)enemy[i].y);
if (enemy[i].x > 850)
{
enemy[i].x = -50;
enemy[i].y = rand() % 560;
}
}
}
timer--;
if (timer == 0)
{
showMessage = 1 - showMessage;
timer = 120;
if (showMessage)
{
timer = 60 * 7;
currentMessage++;
if (currentMessage == 10)
break;
if (strcmp(cutMessage[currentMessage].message, "") == 0)
break;
face = NULL;
if (cutMessage[currentMessage].face != -1)
face = graphics.shape[cutMessage[currentMessage].face];
graphics.createMessageBox(face, cutMessage[currentMessage].message, 0);
}
}
if ((showMessage) && (graphics.messageBox != NULL))
graphics.blit(graphics.messageBox, (800 - graphics.messageBox->w) / 2, 500);
while (SDL_GetTicks() < (frameLimit + 16)){}
frameLimit = SDL_GetTicks();
if (engine.keyState[SDLK_ESCAPE])
break;
}
graphics.flushBuffer();
graphics.freeGraphics();
graphics.clearScreen(graphics.black);
graphics.updateScreen();
}

52
code/script.h Normal file
View File

@ -0,0 +1,52 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include <string.h>
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_mixer.h"
#include "defs.h"
#include "structs.h"
#include "classes.h"
extern void doStarfield();
extern void getPlayerInput();
extern void loadGameGraphics();
extern void loadBackground(char *filename);
extern void setRadioMessage(signed char face, char *in, int priority);
extern void doExplosions();
extern void addEngine(object *craft);
extern void doExplosions();
extern void resetLists();
extern int getFace(char *face);
extern int locateDataInPak(char *file, signed char required);
extern void flushInput();
extern Game currentGame;
extern object enemy[MAX_ALIENS];
extern object player;
extern object defEnemy[MAX_DEFALIENS];
extern globalEngineVariables engine;
extern Graphics graphics;
extern event gameEvent[10];
extern cutMsg cutMessage[10];

772
code/shop.cpp Normal file
View File

@ -0,0 +1,772 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "shop.h"
void drawSecondaryWeaponSurface()
{
char description[50];
strcpy(description, "");
graphics.drawString("Secondary Weapon", 10, 3, FONT_WHITE, graphics.shopSurface[2]);
switch (player.weaponType[1])
{
case W_NONE:
strcpy(description, "Type : None");
break;
case W_ROCKETS:
strcpy(description, "Type : Rockets");
break;
case W_DOUBLE_ROCKETS:
strcpy(description, "Type : Dbl Rockets");
break;
case W_MICRO_ROCKETS:
strcpy(description, "Type : Micro Rockets");
break;
case W_LASER:
strcpy(description, "Type : Laser");
break;
case W_CHARGER:
strcpy(description, "Type : Charger");
break;
case W_HOMING_MISSILE:
strcpy(description, "Type : Homing Missile");
break;
case W_DOUBLE_HOMING_MISSILES:
strcpy(description, "Type : Dbl Homing Missiles");
break;
case W_MICRO_HOMING_MISSILES:
strcpy(description, "Type : Mcr Homing Missiles");
break;
}
graphics.drawString(description, 10, 22, FONT_WHITE, graphics.shopSurface[2]);
if ((player.weaponType[1] != W_LASER) && (player.weaponType[1] != W_CHARGER) && (player.weaponType[1] != W_NONE))
{
sprintf(description, "Capacity : %d", currentGame.maxRocketAmmo);
graphics.drawString(description, 10, 37, FONT_WHITE, graphics.shopSurface[2]);
}
}
void adjustShopPrices()
{
shopItems[0].price = (500 * currentGame.maxPlasmaOutput);
shopItems[1].price = (500 * currentGame.maxPlasmaDamage);
shopItems[2].price = (500 * (16 - currentGame.maxPlasmaRate));
shopItems[5].price = (2000 * weapon[0].ammo[0]);
shopItems[6].price = (2000 * weapon[0].damage);
shopItems[7].price = (2000 * (16 - weapon[0].reload[0]));
shopItems[8].price = (5 * currentGame.maxPlasmaAmmo);
shopItems[9].price = (25 * currentGame.maxRocketAmmo);
if (currentGame.maxPlasmaOutput == 5)
shopItems[0].price = 0;
if (currentGame.maxPlasmaDamage == 5)
shopItems[1].price = 0;
if (currentGame.maxPlasmaRate == 7)
shopItems[2].price = 0;
if (weapon[0].ammo[0] == 3)
shopItems[5].price = 0;
if (weapon[0].damage == 3)
shopItems[6].price = 0;
if (weapon[0].reload[0] == 11)
shopItems[7].price = 0;
}
void drawShop()
{
adjustShopPrices();
for (int i = 0 ; i < MAX_SHOPSHAPES ; i++)
{
if (graphics.shopSurface[i] != NULL)
{
SDL_FreeSurface(graphics.shopSurface[i]);
}
}
for (int i = 0 ; i < 3 ; i++)
graphics.shopSurface[i] = graphics.createSurface(246, 91);
for (int i = 0 ; i < 3 ; i++)
{
graphics.blevelRect(graphics.shopSurface[i], 0, 0, 245, 90, 0x00, 0x00, 0x55);
graphics.blevelRect(graphics.shopSurface[i], 0, 0, 245, 20, 0x00, 0x00, 0x99);
}
graphics.shopSurface[4] = graphics.alphaRect(601, 101, 0x00, 0x00, 0x00);
graphics.blevelRect(graphics.shopSurface[4], 0, 0, 600, 100, 0x00, 0x00, 0x33);
switch (shopSelectedItem)
{
case -1:
case -2:
case -3:
case -4:
case -5:
case -6:
break;
case 0:
case 1:
case 2:
case 8:
graphics.blevelRect(graphics.shopSurface[1], 0, 0, 245, 90, 0x55, 0x00, 0x00);
graphics.blevelRect(graphics.shopSurface[1], 0, 0, 245, 20, 0x99, 0x00, 0x00);
break;
case 3:
case 4:
graphics.blevelRect(graphics.shopSurface[4], 0, 0, 600, 100, 0x33, 0x00, 0x00);
break;
case 5:
case 6:
case 7:
graphics.blevelRect(graphics.shopSurface[0], 0, 0, 245, 90, 0x55, 0x00, 0x00);
graphics.blevelRect(graphics.shopSurface[0], 0, 0, 245, 20, 0x99, 0x00, 0x00);
break;
default:
graphics.blevelRect(graphics.shopSurface[2], 0, 0, 245, 90, 0x55, 0x00, 0x00);
graphics.blevelRect(graphics.shopSurface[2], 0, 0, 245, 20, 0x99, 0x00, 0x00);
break;
}
char description[100];
strcpy(description, "");
graphics.drawString("Primary Weapon", 10, 3, FONT_WHITE, graphics.shopSurface[0]);
sprintf(description, "Plasma Cannons : %d", weapon[0].ammo[0]);
graphics.drawString(description, 10, 22, FONT_WHITE, graphics.shopSurface[0]);
sprintf(description, "Plasma Power : Stage %d", weapon[0].damage);
graphics.drawString(description, 10, 37, FONT_WHITE, graphics.shopSurface[0]);
sprintf(description, "Cooler : Stage %d", ((15 - weapon[0].reload[0]) / 2) + 1);
graphics.drawString(description, 10, 52, FONT_WHITE, graphics.shopSurface[0]);
graphics.drawString("Powerup Weapon", 10, 3, FONT_WHITE, graphics.shopSurface[1]);
sprintf(description, "Plasma Output : Stage %d", currentGame.maxPlasmaOutput);
graphics.drawString(description, 10, 22, FONT_WHITE, graphics.shopSurface[1]);
sprintf(description, "Plasma Condensor : Stage %d", currentGame.maxPlasmaDamage);
graphics.drawString(description, 10, 37, FONT_WHITE, graphics.shopSurface[1]);
sprintf(description, "Liquid Nitrogen : Stage %d", ((15 - currentGame.maxPlasmaRate) / 2) + 1);
graphics.drawString(description, 10, 52, FONT_WHITE, graphics.shopSurface[1]);
sprintf(description, "Plasma Capacity : %d", currentGame.maxPlasmaAmmo);
graphics.drawString(description, 10, 67, FONT_WHITE, graphics.shopSurface[1]);
drawSecondaryWeaponSurface();
graphics.shopSurface[3] = graphics.createSurface(601, 121);
graphics.blevelRect(graphics.shopSurface[3], 0, 0, 600, 120, 0x00, 0x00, 0x22);
graphics.drawString("Temporary Weapons", 10, 2, FONT_WHITE, graphics.shopSurface[3]);
graphics.drawString("Ammo and Storage", 260, 2, FONT_WHITE, graphics.shopSurface[3]);
graphics.drawString("Primary Weapons", 10, 62, FONT_WHITE, graphics.shopSurface[3]);
graphics.drawString("Secondary Weapons", 260, 62, FONT_WHITE, graphics.shopSurface[3]);
signed char icons = MAX_SHOPITEMS;
if (currentGame.system == 0)
icons = 11;
else if (currentGame.system == 1)
icons = 13;
else if (currentGame.system == 2)
icons = 15;
for (int i = 0 ; i < icons ; i++)
graphics.blit(graphics.shape[shopItems[i].image], shopItems[i].x - 90, shopItems[i].y - 178, graphics.shopSurface[3]);
sprintf(description, "Shield Units : %d", currentGame.shieldUnits * 25);
graphics.drawString(description, 10, 4, FONT_WHITE, graphics.shopSurface[4]);
sprintf(description, "Cash : $%d", currentGame.cash);
graphics.drawString(description, 10, 80, FONT_WHITE, graphics.shopSurface[4]);
sprintf(description, "Plasma Cells : %.3d", player.ammo[0]);
graphics.drawString(description, 430, 4, FONT_WHITE, graphics.shopSurface[4]);
sprintf(description, "Rockets : %.3d", player.ammo[1]);
graphics.drawString(description, 475, 80, FONT_WHITE, graphics.shopSurface[4]);
graphics.shopSurface[5] = graphics.createSurface(601, 56);
graphics.blevelRect(graphics.shopSurface[5], 0, 0, 600, 35, 0x00, 0x99, 0x00);
graphics.blevelRect(graphics.shopSurface[5], 0, 20, 600, 35, 0x00, 0x33, 0x00);
graphics.drawString("Information", 5, 4, FONT_WHITE, graphics.shopSurface[5]);
switch (shopSelectedItem)
{
case -1:
break;
case -2:
graphics.drawString("You don't have enough money", 20, 30, FONT_WHITE, graphics.shopSurface[5]);
break;
case -3:
graphics.drawString("Cannot upgrade ship", 5, 22, FONT_WHITE, graphics.shopSurface[5]);
graphics.drawString("Hardware capacity has been reached", 20, 38, FONT_CYAN, graphics.shopSurface[5]);
break;
case -4:
graphics.drawString("Ammunition limit reached", 20, 30, FONT_WHITE, graphics.shopSurface[5]);
break;
case -5:
graphics.drawString("You cannot sell that item", 20, 30, FONT_WHITE, graphics.shopSurface[5]);
break;
case -6:
graphics.drawString("Nothing to sell", 20, 30, FONT_WHITE, graphics.shopSurface[5]);
break;
case -7:
graphics.drawString("Rockets cannot be bought for Laser or Charger Cannon", 5, 30, FONT_WHITE, graphics.shopSurface[5]);
break;
case -8:
graphics.drawString("You already have that weapon", 20, 30, FONT_WHITE, graphics.shopSurface[5]);
break;
case -9:
graphics.drawString("This weapon's ammo limit has been reached", 20, 30, FONT_WHITE, graphics.shopSurface[5]);
break;
default:
if (shopItems[shopSelectedItem].price != 0)
{
sprintf(description, "%s ($%d)", shopItems[shopSelectedItem].description, shopItems[shopSelectedItem].price);
}
else
{
sprintf(description, "%s (N/A)", shopItems[shopSelectedItem].description);
}
graphics.drawString(shopItems[shopSelectedItem].name, 5, 22, FONT_WHITE, graphics.shopSurface[5]);
graphics.drawString(description, 20, 38, FONT_CYAN, graphics.shopSurface[5]);
break;
}
}
#if USEPACK
void loadShop()
{
char name[255], description[255];
int price, image, x, y;
FILE *fp;
#if USEPACK
int dataLocation = locateDataInPak("data/shop.dat", 1);
fp = fopen(PACKLOCATION, "rb");
fseek(fp, dataLocation, SEEK_SET);
#else
fp = fopen("data/shop.dat", "rb");
#endif
for (int i = 0 ; i < MAX_SHOPITEMS ; i++)
{
fscanf(fp, "%[^\n]%*c", name);
fscanf(fp, "%[^\n]%*c", description);
fscanf(fp, "%d", &price);
fscanf(fp, "%d", &image);
fscanf(fp, "%d", &x);
fscanf(fp, "%d%*c", &y);
strcpy(shopItems[i].name, name);
strcpy(shopItems[i].description, description);
shopItems[i].price = price;
shopItems[i].image = image;
shopItems[i].x = x;
shopItems[i].y = y;
}
fclose(fp);
shopSelectedItem = -1;
player.image[0] = graphics.shape[0];
player.x = 380;
player.y = 95;
drawShop();
}
void initShop(){loadShop();}
#else
void saveShop()
{
FILE *fp;
fp = fopen("data/shop.dat", "wb");
if (fp == NULL)
{
printf("Unable to write Shop Data File\n");
exit(1);
}
for (int i = 0 ; i < MAX_SHOPITEMS ; i++)
{
fprintf(fp, "%s\n", shopItems[i].name);
fprintf(fp, "%s\n", shopItems[i].description);
fprintf(fp, "%d ", shopItems[i].price);
fprintf(fp, "%d ", shopItems[i].image);
fprintf(fp, "%d ", shopItems[i].x);
fprintf(fp, "%d\n", shopItems[i].y);
}
// Put an extra line for the PAK file "just in case"
fprintf(fp, "\n");
fclose(fp);
}
/*
Throw into a data file in final build
*/
void initShop()
{
/* ----------- Temporary Items ----------- */
shopItems[0].price = 1000;
strcpy(shopItems[0].name, "Plasma channel splitter");
strcpy(shopItems[0].description, "Improves poweredup plasma output");
shopItems[0].image = 9;
shopItems[1].price = 1000;
strcpy(shopItems[1].name, "Plasma capacity condensor");
strcpy(shopItems[1].description, "Increases poweredup plasma damage");
shopItems[1].image = 10;
shopItems[2].price = 1000;
strcpy(shopItems[2].name, "Liquid nitrogen capsules");
strcpy(shopItems[2].description, "Increases plasma firing rate");
shopItems[2].image = 11;
shopItems[3].price = 50;
strcpy(shopItems[3].name, "10 Plasma cells");
strcpy(shopItems[3].description, "Plasma ammunition");
shopItems[3].image = 12;
shopItems[4].price = 50;
strcpy(shopItems[4].name, "Rocket Ammo");
strcpy(shopItems[4].description, "High velocity dumb fire rocket");
shopItems[4].image = 13;
/* ----------- Permanent Items ----------- */
shopItems[5].price = 2000;
strcpy(shopItems[5].name, "Additional Plasma Cannon");
strcpy(shopItems[5].description, "Adds an extra plasma cannon to the Firefly");
shopItems[5].image = 14;
shopItems[6].price = 2000;
strcpy(shopItems[6].name, "Plasma Power Booster");
strcpy(shopItems[6].description, "Increases power of plasma shots");
shopItems[6].image = 15;
shopItems[7].price = 2000;
strcpy(shopItems[7].name, "Plasma Cooling Booster");
strcpy(shopItems[7].description, "Permanently increases firing rate");
shopItems[7].image = 16;
/* ----------- Ammo Items -------------- */
shopItems[8].price = 250;
strcpy(shopItems[8].name, "Plasma compressor");
strcpy(shopItems[8].description, "Increases plasma ammo capacity");
shopItems[8].image = 17;
shopItems[9].price = 250;
strcpy(shopItems[9].name, "Rocket Pod");
strcpy(shopItems[9].description, "Allows for an additional 5 rockets to be carried");
shopItems[9].image = 18;
/* ---------- Weaponary --------------- */
shopItems[10].price = 2000;
strcpy(shopItems[10].name, "Dual Rocket Launcher");
strcpy(shopItems[10].description, "Allows for two rockets to be fired at once");
shopItems[10].image = 19;
shopItems[11].price = 2500;
strcpy(shopItems[11].name, "Micro Rocket Launcher");
strcpy(shopItems[11].description, "Launches several less powerful rockets at once");
shopItems[11].image = 20;
shopItems[12].price = 5000;
strcpy(shopItems[12].name, "Laser Cannon");
strcpy(shopItems[12].description, "Laser Cannon");
shopItems[12].image = 21;
shopItems[13].price = 7500;
strcpy(shopItems[13].name, "Homing Missile Launcher");
strcpy(shopItems[13].description, "Fires homing missile");
shopItems[13].image = 22;
shopItems[14].price = 10000;
strcpy(shopItems[14].name, "Charge Cannon");
strcpy(shopItems[14].description, "A charge up cannon");
shopItems[14].image = 23;
shopItems[15].price = 20000;
strcpy(shopItems[15].name, "Dual Homing Missile Launcher");
strcpy(shopItems[15].description, "Fires two homing missiles");
shopItems[15].image = 24;
shopItems[16].price = 25000;
strcpy(shopItems[16].name, "Homing Micro Missile Launcher");
strcpy(shopItems[16].description, "Fires several small homing missiles");
shopItems[16].image = 25;
for (int i = 0 ; i < 3 ; i++)
{
shopItems[i].x = 100 + (i * 50);
shopItems[i].y = 200;
}
shopItems[3].x = 350;
shopItems[3].y = 200;
shopItems[4].x = 400;
shopItems[4].y = 200;
for (int i = 0 ; i < 3 ; i++)
{
shopItems[i + 5].x = 100 + (i * 50);
shopItems[i + 5].y = 260;
}
for (int i = 0 ; i < 2 ; i++)
{
shopItems[i + 8].x = 450 + (i * 50);
shopItems[i + 8].y = 200;
}
for (int i = 0 ; i < 8 ; i++)
{
shopItems[i + 10].x = 350 + (i * 50);
shopItems[i + 10].y = 260;
}
shopSelectedItem = -1;
player.image[0] = graphics.shape[0];
player.x = 380;
player.y = 95;
saveShop();
drawShop();
}
#endif
void buy(int i)
{
if ((currentGame.cash < shopItems[i].price) && (!engine.cheatCash))
{
shopSelectedItem = -2;
drawShop();
return;
}
switch(i)
{
case 0:
if (currentGame.maxPlasmaOutput == 5)
{shopSelectedItem = -3; return;}
currentGame.maxPlasmaOutput++;
break;
case 1:
if (currentGame.maxPlasmaDamage == 5)
{shopSelectedItem = -3; return;}
currentGame.maxPlasmaDamage++;
break;
case 2:
if (currentGame.maxPlasmaRate == 7)
{shopSelectedItem = -3; return;}
currentGame.maxPlasmaRate -= 2;
break;
case 3:
if (player.ammo[0] == currentGame.maxPlasmaAmmo)
{shopSelectedItem = -4; return;}
Math::limitChar(&(player.ammo[0] += 10), 0, currentGame.maxPlasmaAmmo);
break;
case 4:
if ((player.weaponType[1] == W_CHARGER) || (player.weaponType[1] == W_LASER))
{shopSelectedItem = -7; return;}
if (player.ammo[1] == currentGame.maxRocketAmmo)
{shopSelectedItem = -4; return;}
if ((player.weaponType[1] == W_HOMING_MISSILE) && (player.ammo[1] == 20))
{shopSelectedItem = -9; return;}
if ((player.weaponType[1] == W_DOUBLE_HOMING_MISSILES) && (player.ammo[1] == 10))
{shopSelectedItem = -9; return;}
if ((player.weaponType[1] == W_MICRO_HOMING_MISSILES) && (player.ammo[1] == 10))
{shopSelectedItem = -9; return;}
player.ammo[1]++;
break;
case 5:
if (weapon[0].ammo[0] == 3)
{shopSelectedItem = -3; return;}
weapon[0].ammo[0]++;
if (currentGame.maxPlasmaOutput < weapon[0].ammo[0])
currentGame.maxPlasmaOutput = weapon[0].ammo[0];
break;
case 6:
if (weapon[0].damage == 3)
{shopSelectedItem = -3; return;}
weapon[0].damage++;
if (currentGame.maxPlasmaDamage < weapon[0].damage)
currentGame.maxPlasmaDamage = weapon[0].damage;
break;
case 7:
if (weapon[0].reload[0] == 11)
{shopSelectedItem = -3; return;}
weapon[0].reload[0] -= 2;
if (currentGame.maxPlasmaRate > weapon[0].reload[0])
currentGame.maxPlasmaRate = weapon[0].reload[0];
break;
case 8:
if (currentGame.maxPlasmaAmmo == 250)
{shopSelectedItem = -3; return;}
Math::limitChar(&(currentGame.maxPlasmaAmmo += 10), 0, 250);
break;
case 9:
if ((player.weaponType[1] == W_CHARGER) || (player.weaponType[1] == W_LASER))
{shopSelectedItem = -7; return;}
if (currentGame.maxRocketAmmo == 50)
{shopSelectedItem = -3; return;}
currentGame.maxRocketAmmo += 5;
break;
case 10:
if (player.weaponType[1] == W_DOUBLE_ROCKETS)
{shopSelectedItem = -8; return;}
player.weaponType[1] = W_DOUBLE_ROCKETS;
shopSelectedItem = -1;
break;
case 11:
if (player.weaponType[1] == W_MICRO_ROCKETS)
{shopSelectedItem = -8; return;}
player.weaponType[1] = W_MICRO_ROCKETS;
shopSelectedItem = -1;
break;
case 12:
if (player.weaponType[1] == W_LASER)
{shopSelectedItem = -8; return;}
player.weaponType[1] = W_LASER;
player.ammo[1] = 0;
shopSelectedItem = -1;
break;
case 13:
if (player.weaponType[1] == W_HOMING_MISSILE)
{shopSelectedItem = -8; return;}
player.weaponType[1] = W_HOMING_MISSILE;
Math::limitChar(&player.ammo[1], 0, 20);
shopSelectedItem = -1;
break;
case 14:
if (player.weaponType[1] == W_CHARGER)
{shopSelectedItem = -8; return;}
player.weaponType[1] = W_CHARGER;
player.ammo[1] = 0;
shopSelectedItem = -1;
break;
case 15:
if (player.weaponType[1] == W_DOUBLE_HOMING_MISSILES)
{shopSelectedItem = -8; return;}
player.weaponType[1] = W_DOUBLE_HOMING_MISSILES;
Math::limitChar(&player.ammo[1], 0, 10);
shopSelectedItem = -1;
break;
case 16:
if (player.weaponType[1] == W_MICRO_HOMING_MISSILES)
{shopSelectedItem = -8; return;}
player.weaponType[1] = W_MICRO_HOMING_MISSILES;
Math::limitChar(&player.ammo[1], 0, 10);
shopSelectedItem = -1;
break;
}
if (!engine.cheatCash)
currentGame.cash -= shopItems[i].price;
}
void sell(int i)
{
switch (i)
{
case 0:
if (currentGame.maxPlasmaOutput == 2)
{shopSelectedItem = -5; return;}
currentGame.maxPlasmaOutput--;
break;
case 1:
if (currentGame.maxPlasmaDamage == 2)
{shopSelectedItem = -5; return;}
currentGame.maxPlasmaDamage--;
break;
case 2:
if (currentGame.maxPlasmaRate == 13)
{shopSelectedItem = -5; return;}
currentGame.maxPlasmaRate += 2;
break;
case 3:
if (player.ammo[0] == 0)
{shopSelectedItem = -6; return;}
if (player.ammo[0] > 9)
Math::limitChar(&(player.ammo[0] -= 10), 0, currentGame.maxPlasmaAmmo);
else
player.ammo[0] = 0;
break;
case 4:
if (player.ammo[1] == 0)
{shopSelectedItem = -6; return;}
player.ammo[1]--;
break;
case 5:
if (weapon[0].ammo[0] == 1)
{shopSelectedItem = -5; return;}
weapon[0].ammo[0]--;
break;
case 6:
if (weapon[0].damage == 1)
{shopSelectedItem = -5; return;}
weapon[0].damage--;
break;
case 7:
if (weapon[0].reload[0] == 15)
{shopSelectedItem = -5; return;}
weapon[0].reload[0] += 2;
break;
case 8:
if (currentGame.maxPlasmaAmmo == 100)
{shopSelectedItem = -1; return;}
currentGame.maxPlasmaAmmo -= 10;
Math::limitChar(&player.ammo[0], 0, currentGame.maxPlasmaAmmo);
break;
case 9:
if (currentGame.maxRocketAmmo == 0)
{shopSelectedItem = -1; return;}
currentGame.maxRocketAmmo -= 5;
Math::limitChar(&player.ammo[1], 0, currentGame.maxRocketAmmo);
break;
case 10:
if (player.weaponType[1] != W_DOUBLE_ROCKETS)
{shopSelectedItem = -1; return;}
player.weaponType[1] = W_NONE;
shopSelectedItem = -1;
break;
case 11:
if (player.weaponType[1] != W_MICRO_ROCKETS)
{shopSelectedItem = -1; return;}
player.weaponType[1] = W_NONE;
shopSelectedItem = -1;
break;
case 12:
if (player.weaponType[1] != W_LASER)
{shopSelectedItem = -1; return;}
player.weaponType[1] = W_NONE;
player.ammo[1] = 0;
shopSelectedItem = -1;
break;
case 13:
if (player.weaponType[1] != W_HOMING_MISSILE)
{shopSelectedItem = -1; return;}
player.weaponType[1] = W_NONE;
shopSelectedItem = -1;
break;
case 14:
if (player.weaponType[1] != W_CHARGER)
{shopSelectedItem = -1; return;}
player.weaponType[1] = W_NONE;
player.ammo[1] = 0;
shopSelectedItem = -1;
break;
case 15:
if (player.weaponType[1] != W_DOUBLE_HOMING_MISSILES)
{shopSelectedItem = -1; return;}
player.weaponType[1] = W_NONE;
shopSelectedItem = -1;
break;
case 16:
if (player.weaponType[1] != W_MICRO_HOMING_MISSILES)
{shopSelectedItem = -1; return;}
player.weaponType[1] = W_NONE;
shopSelectedItem = -1;
break;
}
currentGame.cash += (shopItems[i].price / 2);
}
void showShop()
{
graphics.blit(graphics.shopSurface[0], 20, 395);
graphics.blit(graphics.shopSurface[1], 275, 395);
graphics.blit(graphics.shopSurface[2], 530, 395);
graphics.blit(graphics.shopSurface[3], 100, 180);
graphics.blit(graphics.shopSurface[4], 100, 50);
graphics.blit(graphics.shopSurface[5], 100, 320);
if (shopSelectedItem > -1)
{
graphics.blit(graphics.shape[27], 60, 350);
graphics.blit(graphics.shape[28], 710, 350);
}
graphics.blit(graphics.shape[29], (int)player.x, (int)player.y);
signed char icons = MAX_SHOPITEMS;
if (currentGame.system == 0)
icons = 11;
else if (currentGame.system == 1)
icons = 13;
else if (currentGame.system == 2)
icons = 15;
if ((engine.keyState[SDLK_LCTRL]) || (engine.keyState[SDLK_RCTRL]))
{
for (int i = 0 ; i < icons ; i++)
{
if (Collision::collision(engine.cursor_x + 13, engine.cursor_y + 13, 6, 6, shopItems[i].x, shopItems[i].y, 32, 25))
{
shopSelectedItem = i;
engine.keyState[SDLK_LCTRL] = engine.keyState[SDLK_RCTRL] = 0;
drawShop();
}
}
if (shopSelectedItem > -1)
{
if (Collision::collision(engine.cursor_x + 13, engine.cursor_y + 13, 6, 6, 60, 350, 24, 16))
{
buy(shopSelectedItem);
engine.keyState[SDLK_LCTRL] = engine.keyState[SDLK_RCTRL] = 0;
drawShop();
}
if (Collision::collision(engine.cursor_x + 13, engine.cursor_y + 13, 6, 6, 700, 350, 24, 16))
{
sell(shopSelectedItem);
engine.keyState[SDLK_LCTRL] = engine.keyState[SDLK_RCTRL] = 0;
drawShop();
}
}
}
}

43
code/shop.h Normal file
View File

@ -0,0 +1,43 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include <string.h>
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_mixer.h"
#include "defs.h"
#include "structs.h"
#include "classes.h"
extern int locateDataInPak(char *file, signed char required);
extern object player;
extern globalEngineVariables engine;
extern object weapon[MAX_WEAPONS];
extern Game currentGame;
extern Graphics graphics;
extern devVariables dev;
extern ShopItem shopItems[MAX_SHOPITEMS];
signed char shopSelectedItem;

306
code/structs.h Normal file
View File

@ -0,0 +1,306 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
typedef struct object {
signed char active;
signed char classDef; // Used by aliens to determine what they are
signed char AIType; // Type of articifial intelligence
signed char id; // The "job" of the object
object *target; // index target in enemy array
signed char reload[2];
int systemPower; // computer systems for craft
int shield; // current shield
int maxShield; // max shield (for recharging)
int deathCounter; // how long to explode for
signed char speed;
unsigned char damage; // Contact damage for bullets
int score; // How much a kill of this is worth
unsigned char ammo[2]; // Ammo for 2nd weapon. Max of 100 (except laser)
signed char face; // Either 0 or 1
object *owner; // Who owns this object
int chance[2]; // Chance of using the weapons (out of 1000)
SDL_Surface *image[2]; // For facing left and right
unsigned char imageIndex[2]; // used for loading
signed char hit; // used to make a craft "flash" if it is struck by a shot
int engineX; // The place for the engine on the other side of the craft
int engineY; // The middle of the engine on the craft
int thinktime; // When the object will next react
signed char weaponType[2]; // Weapon types
signed char collectChance; // Chance of dropping the object
signed char collectType; // What the object is carrying
unsigned char collectValue; // What it is worth
int flags; // Various flags for an object
float x, y, dx, dy;
object *next;
} object;
typedef struct mission {
char primaryObjective[3][50]; // Description
signed char primaryType[3]; // The type of mission this is
signed char target1[3]; // index of target in enemy array
int targetValue1[3]; // Number of things to collect (slaves, cash, etc)
signed char timeLimit1[3]; // In minutes
int completed1[3];
char secondaryObjective[3][50]; // Description
signed char secondaryType[3]; // The type of mission this is
signed char target2[3]; // index of target in enemy array
int targetValue2[3]; // Number of things to collect (slaves, cash, etc)
signed char timeLimit2[3]; // In minutes
int completed2[3];
signed char remainingObjectives1;
signed char remainingObjectives2;
int addAliens; // How often to add new enemies
};
typedef struct Star {
float x, y, dx, dy;
signed char speed; // How fast the star moves
};
typedef struct collectables {
signed char active;
float x, y, dx, dy;
SDL_Surface *image;
signed char type; // What kind of collectable is it?
unsigned char value; // How much is it worth?
int life; // How long it will stay around for
collectables *next;
};
typedef struct textObject {
SDL_Surface *image;
unsigned char life;
float x, y;
signed char fontColor;
char text[255];
};
typedef struct Game {
object thePlayer;
object playerWeapon;
object playerWeapon2;
unsigned char system;
unsigned char area;
unsigned char musicVolume;
unsigned char sfxVolume;
signed char fullScreen;
signed char useMusic;
signed char useSound;
signed char autoSaveSlot;
unsigned int cash;
unsigned int cashEarned;
unsigned int shots;
unsigned int hits;
unsigned char accuracy;
unsigned char hasWingMate1, hasWingMate2;
unsigned int totalKills, wingMate1Kills, wingMate2Kills;
unsigned char wingMate1Ejects, wingMate2Ejects;
unsigned int totalOtherKills;
unsigned char secondaryMissions, secondaryMissionsCompleted;
unsigned int shieldPickups, rocketPickups, cellPickups, powerups, minesKilled, cargoPickups;
// slaves for Eyananth
unsigned int slavesRescued;
// remaining shield for experimental fighter
unsigned int experimentalShield;
unsigned int timeTaken; // In seconds
unsigned char missionCompleted[10];
signed char stationedPlanet;
signed char destinationPlanet;
char stationedName[20];
char destinationName[20];
int distanceCovered;
unsigned char maxPlasmaRate;
unsigned char maxPlasmaDamage;
unsigned char maxPlasmaOutput;
unsigned char maxPlasmaAmmo;
unsigned char maxRocketAmmo;
unsigned char shieldUnits;
};
typedef struct ShopItem {
int x, y;
unsigned int price;
char name[50];
char description[255];
unsigned char image;
};
typedef struct bRect {
int x, y, w, h;
bRect *next;
} bRect;
typedef struct Planet {
int y;
char name[50];
SDL_Surface *image;
signed char missionNumber; // associated mission number
signed char missionCompleted; // whether it has been completed
signed char messageMission;
signed char messageSlot;
signed char faceImage;
char from[50];
char subject[100];
};
typedef struct globalEngineVariables {
SDL_Event event;
signed char done;
SDL_RWops *sdlrw;
float musicVolume;
signed char maxAliens;
float ssx;
float ssy;
Mix_Music *music;
object *bulletHead;
object *bulletTail;
object *explosionHead;
object *explosionTail;
collectables *collectableHead;
collectables *collectableTail;
object *debrisHead;
object *debrisTail;
int cursor_x, cursor_y;
signed char commsSection;
signed char eventTimer;
signed char lowShield;
signed char averageShield;
float targetShield;
signed char targetIndex;
signed char targetArrow;
int targetArrowTimer;
// Mission completion timer (allows for 4 seconds before leaving sector)
unsigned long missionCompleteTimer;
// Times the mission normally
unsigned int counter2;
int timeTaken; // In seconds
// For missions with a time limit
signed char timeMission;
unsigned int counter;
signed char seconds;
signed char minutes;
// Mission Related stuff
signed char allAliensDead;
int addAliens;
signed char paused;
signed char gameSection;
signed char useAudio;
// This really only applies to Linux users.
char userHomeDirectory[1024];
char keyState[350];
signed char cheat; // overall cheat
signed char cheatShield;
signed char cheatCash;
signed char cheatAmmo;
signed char cheatTime;
signed char cheatCredits;
};
typedef struct event {
int time;
char message[255];
signed char face;
signed char entity;
int flag;
};
typedef struct cutMsg {
int face;
char message[255];
};
typedef struct devVariables {
signed char moveAliens;
signed char fireAliens;
};

738
code/title.cpp Normal file
View File

@ -0,0 +1,738 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "version.h"
#include "title.h"
signed char showGameMenu(signed char continueSaveSlot)
{
graphics.blitText(2);
if (continueSaveSlot != 0)
{
graphics.blitText(3);
graphics.blitText(4);
}
graphics.blitText(5);
if (engine.cheat)
{
graphics.textShape[7].y = 450;
graphics.blitText(6);
}
else
{
graphics.textShape[7].y = 430;
}
graphics.blitText(7);
if (engine.cheat)
return 6;
return 5;
}
signed char showLoadMenu()
{
signed char rtn = 1;
for (int i = 13 ; i < 18 ; i++)
{
if (graphics.textShape[i].image != NULL)
{
graphics.blitText(i);
rtn++;
graphics.textShape[12].y = graphics.textShape[i].y + 40;
}
}
graphics.blitText(12);
return rtn;
}
void createOptionsMenu()
{
if (currentGame.useSound)
graphics.textSurface(8, "SOUND - ON", -1, 350, FONT_WHITE);
else
graphics.textSurface(8, "SOUND - OFF", -1, 350, FONT_WHITE);
if (currentGame.useMusic)
graphics.textSurface(9, "MUSIC - ON", -1, 370, FONT_WHITE);
else
graphics.textSurface(9, "MUSIC - OFF", -1, 370, FONT_WHITE);
if (currentGame.fullScreen)
graphics.textSurface(10, "FULLSCREEN - ON", -1, 390, FONT_WHITE);
else
graphics.textSurface(10, "FULLSCREEN - OFF", -1, 390, FONT_WHITE);
char string[50];
strcpy(string, "AUTO SAVE SLOT - NONE");
if (currentGame.autoSaveSlot > -1)
sprintf(string, "AUTO SAVE SLOT - #%d", currentGame.autoSaveSlot + 1);
graphics.textSurface(11, string, -1, 410, FONT_WHITE);
}
signed char showOptionsMenu()
{
graphics.textShape[12].y = 450;
graphics.blitText(8);
graphics.blitText(9);
graphics.blitText(10);
graphics.blitText(11);
graphics.blitText(12);
return 5;
}
void createCheatMenu()
{
if (engine.cheatShield)
graphics.textSurface(18, "UNLIMITED SHIELD - ON", -1, 350, FONT_WHITE);
else
graphics.textSurface(18, "UNLIMITED SHIELD - OFF", -1, 350, FONT_WHITE);
if (engine.cheatAmmo)
graphics.textSurface(19, "UNLIMITED AMMO - ON", -1, 370, FONT_WHITE);
else
graphics.textSurface(19, "UNLIMITED AMMO - OFF", -1, 370, FONT_WHITE);
if (engine.cheatCash)
graphics.textSurface(20, "UNLIMITED CASH - ON", -1, 390, FONT_WHITE);
else
graphics.textSurface(20, "UNLIMITED CASH - OFF", -1, 390, FONT_WHITE);
if (engine.cheatTime)
graphics.textSurface(21, "UNLIMITED TIME - ON", -1, 410, FONT_WHITE);
else
graphics.textSurface(21, "UNLIMITED TIME - OFF", -1, 410, FONT_WHITE);
}
signed char showCheatMenu()
{
graphics.textShape[12].y = 450;
graphics.blitText(18);
graphics.blitText(19);
graphics.blitText(20);
graphics.blitText(21);
graphics.blitText(12);
return 5;
}
/*
This is the main title screen, with the stars whirling past and the
"Parallel Realities, Present..." text. Nothing too special.
*/
int doTitle()
{
newGame();
engine.gameSection = SECTION_TITLE;
graphics.flushBuffer();
graphics.freeGraphics();
resetLists();
// required to stop the title screen crashing
currentGame.system = 0;
currentGame.area = 0;
loadGameGraphics();
graphics.clearScreen(graphics.black);
graphics.updateScreen();
graphics.clearScreen(graphics.black);
SDL_Delay(1000);
signed char continueSaveSlot = initSaveSlots();
loadMusic("music/Platinum.mod");
loadBackground("gfx/spirit.jpg");
SDL_Surface *prlogo, *sflogo;
prlogo = loadImage("gfx/prlogo.gif");
sflogo = loadImage("gfx/sflogo.gif");
int prx = ((800 - prlogo->w) / 2);
int pry = ((600 - prlogo->h) / 2);
int sfx = ((800 - sflogo->w) / 2);
int sfy = ((600 - sflogo->h) / 2);
graphics.textSurface(0, "PRESENTS", -1, 300, FONT_WHITE);
graphics.textSurface(1, "AN SDL GAME", -1, 300, FONT_WHITE);
graphics.textSurface(2, "START NEW GAME", -1, 350, FONT_WHITE);
graphics.textSurface(3, "LOAD GAME", -1, 370, FONT_WHITE);
graphics.textSurface(4, "CONTINUE CURRENT GAME", -1, 390, FONT_WHITE);
graphics.textSurface(5, "OPTIONS", -1, 410, FONT_WHITE);
graphics.textSurface(6, "CHEAT OPTIONS", -1, 430, FONT_WHITE);
graphics.textSurface(7, "QUIT", -1, 430, FONT_WHITE);
createOptionsMenu();
graphics.textSurface(12, "BACK TO MAIN MENU", -1, 0, FONT_WHITE);
createCheatMenu();
// Set the star motion
engine.ssx = -0.5;
engine.ssy = 0;
int then = SDL_GetTicks();
int now;
for (int i = 0 ; i < 15 ; i++)
{
enemy[i] = defEnemy[rand() % 3];
if ((rand() % 5) == 0)
enemy[i] = defEnemy[CD_TRANSPORTSHIP];
if ((rand() % 5) == 0)
enemy[i] = defEnemy[CD_MINER];
enemy[i].x = rand() % 800;
enemy[i].y = rand() % 560;
enemy[i].dx = 1 + rand() % 3;
enemy[i].face = 0;
}
int redGlow = 255;
signed char redDir = -2;
char buildVersion[25];
sprintf(buildVersion, "Version "VERSION);
SDL_Rect optionRec;
optionRec.x = 290;
optionRec.y = 345;
optionRec.h = 22;
optionRec.w = 215;
signed char selectedOption = 1;
if (continueSaveSlot > 0)
{selectedOption = 3; optionRec.y += 40;}
signed char skip = 0;
signed char listLength = 5; // menu list length
signed char menuType = 0;
graphics.drawBackGround();
unsigned long frameLimit = SDL_GetTicks();
engine.done = 0;
flushInput();
engine.keyState[SDLK_LCTRL] = engine.keyState[SDLK_RCTRL] = 0;
if ((currentGame.useMusic) && (engine.useAudio))
Mix_PlayMusic(engine.music, 1);
while (!engine.done)
{
graphics.updateScreen();
graphics.unBuffer();
now = SDL_GetTicks();
doStarfield();
doExplosions();
for (int i = 0 ; i < 15 ; i++)
{
addEngine(&enemy[i]);
enemy[i].x += enemy[i].dx;
graphics.blit(enemy[i].image[0], (int)enemy[i].x, (int)enemy[i].y);
if (enemy[i].x > 830)
{
enemy[i].x = -10;
enemy[i].y = rand() % 580;
enemy[i].dx = 1 + rand() % 3;
}
}
if ((now - then > 2000) && (now - then < 8000) && (!skip))
{
graphics.blit(prlogo, prx, pry);
}
else if ((now - then > 9000) && (now - then < 15000) && (!skip))
{
graphics.blitText(0);
}
else if ((now - then > 16000) && (now - then < 21000) && (!skip))
{
graphics.blitText(1);
}
else if ((now - then > 25500) || (skip))
{
graphics.blit(sflogo, sfx, sfy);
if ((now - then >= 27500) || (skip))
{
graphics.addBuffer(280, 345, 235, 145);
graphics.blevelRect(optionRec.x, optionRec.y, optionRec.w, optionRec.h, redGlow, 0x00, 0x00);
switch(menuType)
{
case 0:
listLength = showGameMenu(continueSaveSlot);
break;
case 1:
listLength = showLoadMenu();
break;
case 2:
listLength = showOptionsMenu();
break;
case 3:
listLength = showCheatMenu();
break;
}
redGlow += redDir;
if (redGlow <= 0) {redDir = 2; redGlow = 0;}
if (redGlow >= 255) {redDir = -2; redGlow = 255;}
if (engine.keyState[SDLK_UP])
{
engine.keyState[SDLK_UP] = 0;
Math::wrapChar(&(--selectedOption), 1, listLength);
if (menuType == 0)
if ((selectedOption == 2) || (selectedOption == 3))
if (continueSaveSlot == 0)
selectedOption = 1;
}
if (engine.keyState[SDLK_DOWN])
{
engine.keyState[SDLK_DOWN] = 0;
Math::wrapChar(&(++selectedOption), 1, listLength);
if (menuType == 0)
if ((selectedOption == 2) || (selectedOption == 3))
if (continueSaveSlot == 0)
selectedOption = 4;
}
optionRec.y = 326 + (20 * selectedOption);
if (menuType > 0)
if (selectedOption == listLength)
optionRec.y += 20;
if (!skip)
{
graphics.drawString("Copyright Parallel Realities 2003", 5, 580, FONT_WHITE, graphics.background);
graphics.drawString(buildVersion, 695, 580, FONT_WHITE, graphics.background);
graphics.addBuffer(0, 580, 800, 20);
skip = 1;
}
}
}
getPlayerInput();
// if someone has invoked the credits cheat
if (engine.cheatCredits)
{
doCredits();
engine.cheatCredits = 0;
}
if ((engine.keyState[SDLK_LCTRL]) || (engine.keyState[SDLK_RCTRL]) || (engine.keyState[SDLK_SPACE]))
{
if ((now - then <= 27500) && (!skip))
{
graphics.drawString("Copyright Parallel Realities 2003", 5, 580, FONT_WHITE, graphics.background);
graphics.drawString(buildVersion, 695, 580, FONT_WHITE, graphics.background);
graphics.addBuffer(0, 580, 800, 20);
skip = 1;
}
else
{
switch(menuType)
{
case 0:
if ((selectedOption == 1) || (selectedOption == 3))
engine.done = 1;
else if (selectedOption == 2)
{menuType = 1; selectedOption = 1;}
else if (selectedOption == 4)
{menuType = 2; selectedOption = 1;}
else if (selectedOption == 5)
{
if (engine.cheat)
{menuType = 3; selectedOption = 1;}
else
engine.done = 1;
}
else if (selectedOption == 6)
engine.done = 1;
break;
case 1:
if (selectedOption != listLength)
{engine.done = 1; continueSaveSlot = selectedOption; selectedOption = 3;}
else
{menuType = 0; selectedOption = 1;}
break;
case 2:
if ((selectedOption == 1) && (engine.useAudio))
currentGame.useSound = 1 - currentGame.useSound;
else if ((selectedOption == 2) && (engine.useAudio))
{
currentGame.useMusic = 1 - currentGame.useMusic;
if (currentGame.useMusic)
{
if (Mix_PausedMusic() == 1)
Mix_ResumeMusic();
else
Mix_PlayMusic(engine.music, 1);
}
else
{
Mix_PauseMusic();
}
}
else if (selectedOption == 3)
{
currentGame.fullScreen = 1 - currentGame.fullScreen;
#if LINUX
SDL_WM_ToggleFullScreen(graphics.screen);
#else
if (currentGame.fullScreen)
graphics.screen = SDL_SetVideoMode(800, 600, 16, SDL_HWSURFACE|SDL_HWPALETTE|SDL_FULLSCREEN);
else
graphics.screen = SDL_SetVideoMode(800, 600, 0, SDL_HWSURFACE|SDL_HWPALETTE);
graphics.drawBackground();
flushBuffer();
#endif
}
else if (selectedOption == 4)
Math::wrapChar(&(++currentGame.autoSaveSlot), -1, 4);
else if (selectedOption == listLength)
{menuType = 0; selectedOption = 1;}
createOptionsMenu();
break;
case 3:
if (selectedOption == 1)
engine.cheatShield = 1 - engine.cheatShield;
else if (selectedOption == 2)
engine.cheatAmmo = 1 - engine.cheatAmmo;
else if (selectedOption == 3)
engine.cheatCash = 1 - engine.cheatCash;
else if (selectedOption == 4)
engine.cheatTime = 1 - engine.cheatTime;
else if (selectedOption == listLength)
{menuType = 0; selectedOption = 1;}
createCheatMenu();
break;
case 4:
if (selectedOption == listLength)
{menuType = 0; selectedOption = 1;}
break;
}
}
engine.keyState[SDLK_LCTRL] = engine.keyState[SDLK_RCTRL] = engine.keyState[SDLK_SPACE] = 0;
}
while (SDL_GetTicks() < (frameLimit + 16)){}
frameLimit = SDL_GetTicks();
}
Mix_HaltMusic();
SDL_FreeSurface(prlogo);
SDL_FreeSurface(sflogo);
engine.keyState[SDLK_LCTRL] = engine.keyState[SDLK_RCTRL] = engine.keyState[SDLK_SPACE] = 0;
resetLists();
if (selectedOption == 1)
selectedOption = 2; // go straight to mission 0
if (selectedOption == 3)
{
newGame();
selectedOption = loadGame(continueSaveSlot);
}
// Send back a negative number...
if (selectedOption > 4)
{
selectedOption = -1;
exit(0);
}
return selectedOption;
}
/*
Scrolls the intro text up the screen and nothing else. The text will be placed
into a data file when the game is finished.
*/
void showStory()
{
graphics.freeGraphics();
int y = 620;
FILE *fp;
#if USEPACK
int dataLocation = locateDataInPak("data/intro.txt", 1);
fp = fopen(PACKLOCATION, "rb");
fseek(fp, dataLocation, SEEK_SET);
#else
fp = fopen("data/intro.txt", "rb");
#endif
int i = 0;
int nextPos = -1;
char string[255];
fscanf(fp, "%d ", &nextPos);
while (nextPos != -1)
{
fscanf(fp, "%[^\n]%*c", string);
y += nextPos;
graphics.textSurface(i, string, -1, y, FONT_WHITE);
i++;
fscanf(fp, "%d ", &nextPos);
}
fclose(fp);
loadBackground("gfx/startUp.jpg");
graphics.blit(graphics.background, 0, 0);
graphics.flushBuffer();
unsigned long frameLimit = SDL_GetTicks();
flushInput();
engine.keyState[SDLK_LCTRL] = engine.keyState[SDLK_RCTRL] = engine.keyState[SDLK_SPACE] = 0;
while (true)
{
graphics.updateScreen();
graphics.unBuffer();
getPlayerInput();
if ((engine.keyState[SDLK_LCTRL]) || (engine.keyState[SDLK_RCTRL]) || (engine.keyState[SDLK_SPACE]))
break;
if (graphics.textShape[8].y > 450)
{
for (int i = 0 ; i < 9 ; i++)
{
graphics.textShape[i].y -= 0.25;
graphics.blitText(i);
}
}
else
{
SDL_Delay(3000);
break;
}
while (SDL_GetTicks() < (frameLimit + 16)){}
frameLimit = SDL_GetTicks();
}
}
/*
The game over screen :(
*/
void gameover()
{
graphics.flushBuffer();
graphics.freeGraphics();
SDL_FillRect(graphics.background, NULL, graphics.black);
engine.keyState[SDLK_LCTRL] = engine.keyState[SDLK_RCTRL] = engine.keyState[SDLK_SPACE] = 0;
engine.gameSection = SECTION_INTERMISSION;
loadMusic("music/Wybierak.mod");
SDL_Surface *gameover = loadImage("gfx/gameover.png");
graphics.clearScreen(graphics.black);
graphics.updateScreen();
graphics.clearScreen(graphics.black);
SDL_Delay(1000);
if ((currentGame.useMusic) && (engine.useAudio))
{
Mix_VolumeMusic(100);
Mix_PlayMusic(engine.music, 1);
}
int x = (800 - gameover->w) / 2;
int y = (600 - gameover->h) / 2;
unsigned long frameLimit = SDL_GetTicks();
graphics.updateScreen();
flushInput();
engine.keyState[SDLK_LCTRL] = engine.keyState[SDLK_RCTRL] = engine.keyState[SDLK_SPACE] = 0;
while (true)
{
getPlayerInput();
if ((engine.keyState[SDLK_LCTRL]) || (engine.keyState[SDLK_RCTRL]) || (engine.keyState[SDLK_SPACE]))
break;
graphics.updateScreen();
graphics.unBuffer();
x = ((800 - gameover->w) / 2) - Math::rrand(-2, 2);
y = ((600 - gameover->h) / 2) - Math::rrand(-2, 2);
graphics.blit(gameover, x, y);
// Limit us to 60 frame a second
while (SDL_GetTicks() < (frameLimit + 16)){}
frameLimit = SDL_GetTicks();
}
SDL_FreeSurface(gameover);
if ((currentGame.useMusic) && (engine.useAudio))
Mix_HaltMusic();
graphics.flushBuffer();
}
void doCredits()
{
loadBackground("gfx/credits.jpg");
graphics.flushBuffer();
graphics.freeGraphics();
if ((currentGame.useMusic) && (engine.useAudio))
loadMusic("music/Solace.s3m");
FILE *fp;
int numberOfCredits = 0;
int lastCredit = 0;
int yPos = 0;
int yPos2 = 510;
char text[255];
textObject *credit;
graphics.clearScreen(graphics.black);
graphics.updateScreen();
graphics.clearScreen(graphics.black);
SDL_Delay(1000);
graphics.drawBackGround();
#if USEPACK
int dataLocation = locateDataInPak("data/credits.txt", 1);
fp = fopen(PACKLOCATION, "rb");
fseek(fp, dataLocation, SEEK_SET);
#else
fp = fopen("data/credits.txt", "rb");
#endif
for (int i = 0 ; i < 6 ; i++)
{
fscanf(fp, "%[^\n]%*c", text);
graphics.drawString(text, -1, 240 + (i * 20), FONT_WHITE);
}
fscanf(fp, "%d%*c", &numberOfCredits);
credit = (textObject*) malloc(sizeof(textObject) * numberOfCredits);
for (int i = 0 ; i < numberOfCredits ; i++)
{
fscanf(fp, "%d %[^\n]%*c", &yPos, text);
credit[i].image = graphics.textSurface(text, FONT_WHITE);
credit[i].x = (800 - credit[i].image->w) / 2;
yPos2 += yPos;
credit[i].y = yPos2;
}
fclose(fp);
if ((currentGame.useMusic) && (engine.useAudio))
{
Mix_VolumeMusic(100);
Mix_PlayMusic(engine.music, 1);
}
SDL_Delay(3000);
graphics.updateScreen();
SDL_Delay(10000);
graphics.drawBackGround();
unsigned long frameLimit = SDL_GetTicks();
engine.done = 0;
lastCredit = numberOfCredits - 1;
SDL_Rect r1 = {0, 80, 800, 20};
SDL_Rect r2 = {0, 500, 800, 20};
engine.keyState[SDLK_ESCAPE] = 0;
flushInput();
while (true)
{
graphics.updateScreen();
graphics.unBuffer();
getPlayerInput();
if (engine.keyState[SDLK_ESCAPE])
break;
for (int i = 0 ; i < numberOfCredits ; i++)
{
if ((credit[i].y > 80) && (credit[i].y < 500))
graphics.blit(credit[i].image, (int)credit[i].x, (int)credit[i].y);
if (credit[lastCredit].y > 400)
credit[i].y -= 0.3;
}
SDL_FillRect(graphics.screen, &r1, graphics.black);
SDL_FillRect(graphics.screen, &r2, graphics.black);
while (SDL_GetTicks() < (frameLimit + 16)){}
frameLimit = SDL_GetTicks();
}
for (int i = 0 ; i < numberOfCredits ; i++)
{
SDL_FreeSurface(credit[i].image);
}
free(credit);
}

54
code/title.h Normal file
View File

@ -0,0 +1,54 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include <string.h>
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_mixer.h"
#include "defs.h"
#include "structs.h"
#include "classes.h"
extern SDL_Surface *loadImage(char *filename);
extern void unpack(char *file);
extern void loadMusic(char *filename);
extern void doStarfield();
extern void doExplosions();
extern void addEngine(object *craft);
extern void getPlayerInput();
extern void resetLists();
extern signed char loadGame(int slot);
extern int initSaveSlots();
extern void newGame();
extern void loadGameGraphics();
extern void loadBackground(char *filename);
extern void doCredits();
extern int locateDataInPak(char *file, signed char required);
extern void flushInput();
extern globalEngineVariables engine;
extern devVariables dev;
extern object defEnemy[MAX_DEFALIENS];
extern object enemy[MAX_ALIENS];
extern Game currentGame;
extern Graphics graphics;

161
code/unpack.cpp Normal file
View File

@ -0,0 +1,161 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "unpack.h"
/*
Searches the pak file for the required data. When
it is found, the data is read into a character buffer.
*/
void unpack(char *file, signed char fileType)
{
unsigned char *packBuffer;
char packFilename[60];
int packFSize;
FILE *pak;
FILE *fp = NULL; // music has to be read-written-read!
char musicFilename[PATH_MAX];
strcpy(packFilename, "");
pak = fopen(PACKLOCATION, "rb");
if (pak == NULL)
{
printf("Couldn't access the Project: Starfighter data file!\n");
exit(1);
}
fseek(pak, 4, SEEK_SET);
while (true)
{
if (!fread(packFilename, 1, 56, pak))
{
fclose(pak);
if (fileType != PAK_FONT)
{
showErrorAndExit(0, file);
}
exit(1);
break;
}
fread(&packFSize, 4, 1, pak);
packFSize = SDL_SwapLE32(packFSize);
if (strcmp(packFilename, file) == 0)
{
if ((fileType == PAK_MOD) || (fileType == PAK_S3M))
{
if (fileType == PAK_MOD)
{
sprintf(musicFilename, "%smusic.mod", engine.userHomeDirectory);
fp = fopen(musicFilename, "wb");
}
else
{
sprintf(musicFilename, "%smusic.s3m", engine.userHomeDirectory);
fp = fopen(musicFilename, "wb");
}
if (fp == NULL)
showErrorAndExit(1, "");
}
packBuffer = (unsigned char*) malloc(packFSize);
fread(packBuffer, 1, packFSize, pak);
if ((fileType == PAK_MOD) || (fileType == PAK_S3M))
{
fwrite(packBuffer, 1, packFSize, fp);
fclose(fp);
}
break;
}
else
{
fseek(pak, packFSize, SEEK_CUR);
}
}
if ((fileType != PAK_MOD) && (fileType != PAK_S3M))
engine.sdlrw = SDL_RWFromMem(packBuffer, packFSize);
//printf("Extracted: %s\n", file);
fclose(pak);
}
/*
Search the data package for the required file.
When it is found, return the location.
*/
int locateDataInPak(char *file, signed char required)
{
//printf("Looking for %s...", file);
char packFilename[60];
int packFSize;
int location = 0;
FILE *pak;
strcpy(packFilename, "");
pak = fopen(PACKLOCATION, "rb");
if (pak == NULL)
{
printf("Couldn't access the Project: Starfighter data file!\n");
exit(1);
}
fseek(pak, 4, SEEK_SET);
while (true)
{
if (!fread(packFilename, 1, 56, pak))
{
fclose(pak);
if (required)
{
showErrorAndExit(0, file);
exit(1);
}
break;
}
fread(&packFSize, 4, 1, pak);
packFSize = SDL_SwapLE32(packFSize);
if (strcmp(packFilename, file) == 0)
{
location = ftell(pak);
fclose(pak);
//printf("found it!\n");
return location;
}
else
{
fseek(pak, packFSize, SEEK_CUR);
}
}
//printf("not found (skipping)\n");
return -1; // we only get this if it isn't required
}

35
code/unpack.h Normal file
View File

@ -0,0 +1,35 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_mixer.h"
#include "SDL/SDL_endian.h"
#include "defs.h"
#include "structs.h"
extern void showErrorAndExit(int errorId, char *name);
extern globalEngineVariables engine;

1
code/version.h Normal file
View File

@ -0,0 +1 @@

261
code/weapons.cpp Normal file
View File

@ -0,0 +1,261 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "weapons.h"
void setWeaponShapes()
{
for (int i = 0 ; i < MAX_WEAPONS ; i++)
{
weapon[i].image[0] = graphics.shape[weapon[i].imageIndex[0]];
weapon[i].image[1] = graphics.shape[weapon[i].imageIndex[1]];
}
}
#if USEPACK
void loadWeapons()
{
int dataLocation = locateDataInPak("data/weapons.dat", 1);
int id, ammo, damage, reload, speed, image1, image2, flags;
FILE *fp;
fp = fopen(PACKLOCATION, "rb");
fseek(fp, dataLocation, SEEK_SET);
for (int i = 0 ; i < MAX_WEAPONS ; i++)
{
fscanf(fp, "%d", &id);
fscanf(fp, "%d", &ammo);
fscanf(fp, "%d", &damage);
fscanf(fp, "%d", &reload);
fscanf(fp, "%d", &speed);
fscanf(fp, "%d", &image1);
fscanf(fp, "%d", &image2);
fscanf(fp, "%d", &flags);
weapon[i].id = id;
weapon[i].ammo[0] = ammo;
weapon[i].damage = damage;
weapon[i].reload[0] = reload;
weapon[i].speed = speed;
weapon[i].imageIndex[0] = image1;
weapon[i].imageIndex[1] = image2;
weapon[i].flags = flags;
}
fclose(fp);
}
void initWeapons() {loadWeapons();}
#else
void saveWeapons()
{
FILE *fp;
fp = fopen("data/weapons.dat", "wb");
if (fp == NULL)
{
printf("Unable to write Weapon Data File\n");
exit(1);
}
for (int i = 0 ; i < MAX_WEAPONS ; i++)
{
fprintf(fp, "%d ", weapon[i].id);
fprintf(fp, "%d ", weapon[i].ammo[0]);
fprintf(fp, "%d ", weapon[i].damage);
fprintf(fp, "%d ", weapon[i].reload[0]);
fprintf(fp, "%d ", weapon[i].speed);
fprintf(fp, "%d ", weapon[i].imageIndex[0]);
fprintf(fp, "%d ", weapon[i].imageIndex[1]);
fprintf(fp, "%d\n", weapon[i].flags);
}
// Put an extra line for the PAK file "just in case"
fprintf(fp, "\n");
fclose(fp);
}
/*
A list of predefined weaponary. Will most probably
be placed into a data file in the final build.
*/
void initWeapons()
{
// Player's weapon (this NEVER allocated to anything else)
weapon[W_PLAYER_WEAPON].id = WT_PLASMA;
weapon[W_PLAYER_WEAPON].ammo[0] = 1;
weapon[W_PLAYER_WEAPON].damage = 1;
weapon[W_PLAYER_WEAPON].reload[0] = 15;
weapon[W_PLAYER_WEAPON].speed = 10;
weapon[W_PLAYER_WEAPON].imageIndex[0] = 0;
weapon[W_PLAYER_WEAPON].imageIndex[1] = 0;
weapon[W_PLAYER_WEAPON].flags = WF_STRAIGHT;
// Nor is this one!
weapon[W_PLAYER_WEAPON2] = weapon[W_PLAYER_WEAPON];
// Single Shot
weapon[W_SINGLE_SHOT].id = WT_PLASMA;
weapon[W_SINGLE_SHOT].ammo[0] = 1;
weapon[W_SINGLE_SHOT].damage = 1;
weapon[W_SINGLE_SHOT].reload[0] = 15;
weapon[W_SINGLE_SHOT].speed = 10;
weapon[W_SINGLE_SHOT].imageIndex[0] = 0;
weapon[W_SINGLE_SHOT].imageIndex[1] = 1;
weapon[W_SINGLE_SHOT].flags = WF_STRAIGHT;
// Double Shot
weapon[W_DOUBLE_SHOT] = weapon[W_SINGLE_SHOT];
weapon[W_DOUBLE_SHOT].ammo[0] = 2;
// Triple Shot
weapon[W_TRIPLE_SHOT] = weapon[W_SINGLE_SHOT];
weapon[W_TRIPLE_SHOT].ammo[0] = 3;
// Rockets
weapon[W_ROCKETS].id = WT_ROCKET;
weapon[W_ROCKETS].ammo[0] = 1;
weapon[W_ROCKETS].damage = 15;
weapon[W_ROCKETS].reload[0] = 45;
weapon[W_ROCKETS].speed = 20;
weapon[W_ROCKETS].flags = WF_STRAIGHT;
weapon[W_ROCKETS].imageIndex[0] = 2;
weapon[W_ROCKETS].imageIndex[1] = 3;
// Double Rockets (uses ROCKETS as base)
weapon[W_DOUBLE_ROCKETS] = weapon[W_ROCKETS];
weapon[W_DOUBLE_ROCKETS].ammo[0] = 2;
weapon[W_DOUBLE_ROCKETS].reload[0] = 80;
// Micro Rockets
weapon[W_MICRO_ROCKETS].id = WT_ROCKET;
weapon[W_MICRO_ROCKETS].ammo[0] = 5;
weapon[W_MICRO_ROCKETS].damage = 3;
weapon[W_MICRO_ROCKETS].reload[0] = 30;
weapon[W_MICRO_ROCKETS].speed = 15;
weapon[W_MICRO_ROCKETS].flags = WF_STRAIGHT + WF_VARIABLE_SPEED;
weapon[W_MICRO_ROCKETS].imageIndex[0] = 2;
weapon[W_MICRO_ROCKETS].imageIndex[1] = 3;
// Energy Ray
weapon[W_ENERGYRAY].id = WT_ENERGYRAY;
weapon[W_ENERGYRAY].ammo[0] = 255;
weapon[W_ENERGYRAY].damage = 1;
weapon[W_ENERGYRAY].reload[0] = 25; // reload for energy ray is never used
weapon[W_ENERGYRAY].speed = 15;
weapon[W_ENERGYRAY].flags = WF_STRAIGHT;
// Laser
weapon[W_LASER].id = WT_LASER;
weapon[W_LASER].ammo[0] = 1;
weapon[W_LASER].damage = 3;
weapon[W_LASER].reload[0] = 1;
weapon[W_LASER].speed = 10;
weapon[W_LASER].imageIndex[0] = 1;
weapon[W_LASER].imageIndex[1] = 1;
weapon[W_LASER].flags = WF_STRAIGHT;
// Beam up weapon
weapon[W_CHARGER].id = WT_CHARGER;
weapon[W_CHARGER].ammo[0] = 1;
weapon[W_CHARGER].damage = 1;
weapon[W_CHARGER].reload[0] = 0;
weapon[W_CHARGER].speed = 12;
weapon[W_CHARGER].flags = WF_STRAIGHT;
weapon[W_CHARGER].imageIndex[0] = 33;
weapon[W_CHARGER].imageIndex[1] = 34;
// Homing missile
weapon[W_HOMING_MISSILE].id = WT_ROCKET;
weapon[W_HOMING_MISSILE].ammo[0] = 1;
weapon[W_HOMING_MISSILE].damage = 15;
weapon[W_HOMING_MISSILE].reload[0] = 35;
weapon[W_HOMING_MISSILE].speed = 10;
weapon[W_HOMING_MISSILE].flags = WF_STRAIGHT + WF_HOMING;
weapon[W_HOMING_MISSILE].imageIndex[0] = 4;
weapon[W_HOMING_MISSILE].imageIndex[1] = 4;
// Double homing missile
weapon[W_DOUBLE_HOMING_MISSILES] = weapon[W_HOMING_MISSILE];
weapon[W_DOUBLE_HOMING_MISSILES].ammo[0] = 2;
weapon[W_DOUBLE_HOMING_MISSILES].reload[0] = 65;
weapon[W_DOUBLE_HOMING_MISSILES].imageIndex[0] = 4;
weapon[W_DOUBLE_HOMING_MISSILES].imageIndex[1] = 4;
// Micro homing missiles
weapon[W_MICRO_HOMING_MISSILES].id = WT_ROCKET;
weapon[W_MICRO_HOMING_MISSILES].ammo[0] = 5;
weapon[W_MICRO_HOMING_MISSILES].damage = 12;
weapon[W_MICRO_HOMING_MISSILES].reload[0] = 65;
weapon[W_MICRO_HOMING_MISSILES].speed = 3;
weapon[W_MICRO_HOMING_MISSILES].flags = WF_STRAIGHT + WF_HOMING;
weapon[W_MICRO_HOMING_MISSILES].imageIndex[0] = 4;
weapon[W_MICRO_HOMING_MISSILES].imageIndex[1] = 4;
// Aimed plasma bolt (2x damage)
weapon[W_AIMED_SHOT].id = WT_DIRECTIONAL;
weapon[W_AIMED_SHOT].ammo[0] = 1;
weapon[W_AIMED_SHOT].damage = 2;
weapon[W_AIMED_SHOT].reload[0] = 15;
weapon[W_AIMED_SHOT].speed = 0;
weapon[W_AIMED_SHOT].flags = WF_STRAIGHT + WF_AIMED;
weapon[W_AIMED_SHOT].imageIndex[0] = 33;
weapon[W_AIMED_SHOT].imageIndex[1] = 34;
// 3 way spread weapon
weapon[W_SPREADSHOT].id = WT_SPREAD;
weapon[W_SPREADSHOT].ammo[0] = 3;
weapon[W_SPREADSHOT].damage = 1;
weapon[W_SPREADSHOT].reload[0] = 10;
weapon[W_SPREADSHOT].speed = 10;
weapon[W_SPREADSHOT].flags = WF_THIN_SPREAD;
weapon[W_SPREADSHOT].imageIndex[0] = 0;
weapon[W_SPREADSHOT].imageIndex[1] = 1;
// Sid's ion cannon like weapon
weapon[W_IONCANNON].id = WT_PLASMA;
weapon[W_IONCANNON].ammo[0] = 1;
weapon[W_IONCANNON].damage = 1;
weapon[W_IONCANNON].reload[0] = 2;
weapon[W_IONCANNON].speed = 10;
weapon[W_IONCANNON].flags = WF_STRAIGHT + WF_DISABLE + WF_AIMED;
weapon[W_IONCANNON].imageIndex[0] = 35;
weapon[W_IONCANNON].imageIndex[1] = 35;
// Directional Shock Missile - Used by Kline in final battle
weapon[W_DIRSHOCKMISSILE].id = WT_ROCKET;
weapon[W_DIRSHOCKMISSILE].ammo[0] = 5;
weapon[W_DIRSHOCKMISSILE].damage = 20;
weapon[W_DIRSHOCKMISSILE].reload[0] = 60;
weapon[W_DIRSHOCKMISSILE].speed = 0;
weapon[W_DIRSHOCKMISSILE].flags = WF_STRAIGHT + WF_AIMED + WF_TIMEDEXPLOSION;
weapon[W_DIRSHOCKMISSILE].imageIndex[0] = 4;
weapon[W_DIRSHOCKMISSILE].imageIndex[1] = 4;
saveWeapons();
}
#endif

36
code/weapons.h Normal file
View File

@ -0,0 +1,36 @@
/*
Copyright (C) 2003 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include <string.h>
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_mixer.h"
#include "defs.h"
#include "structs.h"
#include "classes.h"
extern int locateDataInPak(char *file, signed char required);
extern Graphics graphics;
extern object weapon[MAX_WEAPONS];

339
docs/LICENSE Normal file
View File

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

368
docs/index.html Executable file
View File

@ -0,0 +1,368 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<HTML>
<HEAD>
<TITLE></TITLE>
<META NAME="Generator" CONTENT="TextPad 4.0">
<META NAME="Author" CONTENT="?">
<META NAME="Keywords" CONTENT="?">
<META NAME="Description" CONTENT="?">
<STYLE>
a {color: #499FFF; text-decoration: none; font-family: helvetica;}
a:hover {color: #499FFF; text-decoration: underline}
body {color: #FFFFFF; background: #000000; font: 10pt helvetica;}
table {color: #FFFFFF; font: 10pt helvetica;}
td {color: #FFFFFF;}
</STYLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#FF0000" VLINK="#800000" ALINK="#FF00FF">
<CENTER>
<IMG SRC="sflogo.gif">
<H3>Gameplay Manual</H3>
</CENTER>
<P></P>
<TABLE BGCOLOR="#000099" WIDTH="100%"><TR><TD><B>License Agreement</B></TR></TR></TABLE>
<P>Project: Starfighter<BR>
Copyright Parallel Realities 2003<BR>
All Rights Reserved
</P>
<P>
This program is free software; you can redistribute it and/or<BR>
modify it under the terms of the GNU General Public License<BR>
as published by the Free Software Foundation; either version 2<BR>
of the License, or (at your option) any later version.<BR>
</P>
<P>
This program is distributed in the hope that it will be useful,<BR>
but WITHOUT ANY WARRANTY; without even the implied warranty of<BR>
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.<BR>
</P>
<P>
See the GNU General Public License for more details.<BR>
</P>
<P>
You should have received a copy of the GNU General Public License<BR>
along with this program; if not, write to the Free Software<BR>
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.<BR>
</P>
<TABLE BGCOLOR="#000099" WIDTH="100%"><TR><TD><B>Introduction</B></TR></TR></TABLE>
<P>
Project: Starfighter is an old school 2D shoot 'em up. In the game you take on the role of a
rebel pilot called Chris, who is attempting to overthrow a military corporation called Weapco. Weapco
has seized control of the known universe and currently rules it with an iron fist. Chris can no longer
stand back and watch as millions of people suffer and die. He steals an experimental craft known
as "Firefly" and begins his mission to fight his way to Sol, freeing key systems along the way. The
game opens with Chris attempting to escape a Weapco patrol that has intercepted him.
</P>
<P>
<TABLE BGCOLOR="#000099" WIDTH="100%"><TR><TD><B>Installation</B></TD></TR></TABLE>
<P>Binary files are provided for both Windows and Linux*.</P>
<P>Installation under Windows</P>
<P>
Unzip the archive into a suitable directory and then double click the Starfighter.exe
file to begin. Games and settings will be saved into this directory.
</P>
<P>Installation under Linux</P>
<PRE>
tar zxf starfighter.tar.gz
cd Starfighter
make
make install
</PRE>
<P>When the game is first run it will attempt to create</P>
<PRE>
~/.parallelrealities/starfighter/
</PRE>
<P>Should this fail the game will not run.</P>
<P><I>* x86 binary compiled with g++ on Mandrake 9. Source and makefile are provided for Linux users
who need to recompile</I></P>
<P>
<TABLE BGCOLOR="#000099" WIDTH="100%"><TR><TD><B>Controls</B></TD></TR></TABLE>
<P>Menus</P>
<UL>
Arrow Keys - Highlight option<BR>
Left Control / Space - Select menu option<BR>
</UL>
<P>Intermission Screen</P>
<UL>
Mouse - Move cursor<BR>
Left Mouse Button - Selected option<BR>
Right Mouse Button - Toggle planet orbit On / Off<BR>
</UL>
<P>In Game</P>
<UL>
Arrow Keys - Control Firefly<BR>
Left Ctrl - Fire primary weapon<BR>
Space - Fire secondary weapon<BR>
Shift - Toggle Primary Weapon Concentrate / Spread (see Weaponry)<BR>
T - Targetting Arrow On /Off<BR>
P - Pause / Unpause<BR>
Escape - Flee (not possible until all primary missions completed)<BR>
Escape whilst paused - Quit to title screen<BR>
</UL>
<P>Note - Keys cannot be changed</P>
<P>
<TABLE BGCOLOR="#000099" WIDTH="100%"><TR><TD><B>How to Play</B></TD></TR></TABLE>
<P>When first starting Project: Starfighter you will see the text scrolling introduction. You can
either wait for this to finish or you can skip it by pressing ctrl or space.</P>
<P>The title sequence will begin. Once the menu is shown (or you opt to skip to it by pressing
space or ctrl) you may select from the options shown</P>
<TABLE>
<TR><TD BGCOLOR="#FF0000"><CENTER> Start New Game </CENTER></TD></TR>
<TR><TD BGCOLOR="#FF0000"><CENTER> Load Game* </CENTER></TD></TR>
<TR><TD BGCOLOR="#FF0000"><CENTER> Continue Current Game* </CENTER></TD></TR>
<TR><TD BGCOLOR="#FF0000"><CENTER> Options </CENTER></TD></TR>
<TR><TD BGCOLOR="#FF0000"><CENTER> Quit </CENTER></TD></TR>
</TABLE>
<P><I>* will only be shown if there are saved games available</I></P>
<P><B>Start New Game</B><BR>
This will start a new game
</P>
<P><B>Load Game</B><BR>
This will bring up a list of currently available games to be loaded, along with the planet that
the game was saved in. This option is only shown when there is at least one saved game available.
</P>
<P><B>Continue Current Game</B><BR>
This will automatically load the most recently saved game. This option is only shown when there is
at least one saved game available.
</P>
<P><B>Options</B><BR>
This will show a list of game options. Options for sound, music and an auto save slot can be changed.
Music and Sound can be switched to either On or Off. The Auto Save Slot allows the player to select
a save slot that will automatically be updated when the player finishes a mission. This can be
switched from None to 1, 2, 3, 4 or 5. When this option is set to a number, that save slot will be
used to save a game at the end of a mission. Note that any currently existing game will be
automatically overwritten.
</P>
<P><B>Quit</B><BR>
This will quit the game. Quitting is immediate, without prompting (the game can also be quit at
anytime by clicking the close button of the window).
</P>
<P>
<TABLE BGCOLOR="#000099" WIDTH="100%"><TR><TD><B>Loading and Saving Games</B></TD></TR></TABLE>
<P>Games can be loaded from the title screen. When there are saved games available, the option "Load
Game" will be shown. Selecting this will show a list of available games to be loaded. Select a game
from the list to load, you will then be taken to the Intermission screen. To go back, selected
Back to Main Menu.</P>
<P>Games can be saved in two ways. The first way is to save a game on the Intermission screen. Move
the cursor to the Save Game icon and select it. You will see a list of five game slots that can be
used to save a game to. Click one of these and then click the "Save" button to save the game. The
second way is to use the Auto Save function. This will automatically save your game after you have
successfully completed a mission. To make use of this feature you must choose a save slot that
you wish to auto save into. This can be done on the title screen in the options section or on
the intermission screen at the options section.</P>
<P>
<TABLE BGCOLOR="#000099" WIDTH="100%"><TR><TD><B>Getting Missions</B></TD></TR></TABLE>
<P>In each System, the player can get missions by going to the Comms section of the Intermission
screen. Here allies will inform you of tasks that need to be performed and what planet these tasks
apply to. Once the player has decided which task they will perform, they must go to the corresponding
planet in the system (see Moving Around for more details). Once stationed at the planet
click "Start Mission" to proceed to the mission briefing screen. The "Start Mission" icon will not
be shown if the mission of the planet has been completed.</P>
<P>
<TABLE BGCOLOR="#000099" WIDTH="100%"><TR><TD><B>Mission Briefing</B></TD></TR></TABLE>
<P>Before the beginning of each mission you will be presented with a mission briefing screen. This
will outline the mission's primary and (if any) secondary objectives. It will also inform you of
mission restrictions, such as time limits. Once you have read this, press ctrl or space to
continue</P>
<P>
<TABLE BGCOLOR="#000099" WIDTH="100%"><TR><TD><B>Completing Missions</B></TD></TR></TABLE>
<P>Each mission in the game has one or more objectives tied to it. These objectives are either
Primary or Secondary objectives. In order to complete the mission, the player must complete all the
primary mission objectives. For example, when the game begins Chris is fleeing a WEAPCO patrol. The
primary objective for this mission is to destroy all the enemy fighters. Once this is achieved the
Firefly will leave the sector and the mission will be marked as a success.</P>
<P>One thing to note is that some missions will have both Primary and Secondary objectives. In this
case, the Firefly does not leave the sector if all primary mission objectives are complete and
secondary objectives remain. The player may then attempt to complete remaining secondary
objectives or press Escape to leave the sector. Secondary objectives are optional.</P>
<P>During the mission you will see messages appearing at the bottom of the screen. These messages
can be related to items that you pick up, as well as mission related information.<P>
<P>
<FONT COLOR="#FFFFFF">White messages</FONT> are standard for picking up items such as cash and
power ups<BR>
<FONT COLOR="#00FF00">Green messages</FONT> signify successful completion of mission objectives<BR>
<FONT COLOR="#00FFFF">Light Blue messages </FONT>give further details about Primary mission
requirements<BR>
<FONT COLOR="#FF0000">Red messages</FONT> indicate mission failures, warnings and wing mate
ejections<BR>
<FONT COLOR="#FFFF00">Yellow messages</FONT> give further details about Secondary mission requirements
<BR>
</P>
<P>
<TABLE BGCOLOR="#000099" WIDTH="100%"><TR><TD><B>The Target Arrow</B></TD></TR></TABLE>
<P>
<IMG SRC="targetArrow.png" ALIGN="LEFT">
The Target Arrow can be used to locate enemies and point you in the direction that the enemy craft
is. You can toggle the Target Arrow on or off by pressing "T" on the keyboard. This arrow is very
useful for finding enemies that are evasive (such as transports) on missions that require you to
destroy all present craft. Simply follow the arrow to find the enemy. The arrow will not be displayed
when you are within the immediate vacinity of the target. On certain missions (such as Bosses) the
arrow will initially point towards a certain target that is part of the mission objective. The
target's current remaining shield is also displayed in the bottom right hand corner of the screen.
Please note that due to the nature of the game, the target arrow cannot be cycled through enemies.
</P>
<P>
<TABLE BGCOLOR="#000099" WIDTH="100%"><TR><TD><B>Moving Around Systems</B></TD></TR></TABLE>
<P>To play a mission in Starfighter you must be stationed at the relevant planet. To get to the
planet you require, you will need to click on the planet whilst viewing it on the Show System section
of the Intermission screen. Travelling between planets can be dangerous, but luckily Spirit is a
peaceful place and there are no chances of interceptions, so travel is instantaneous.</P>
<P>Other systems are not as friendly and whilst travelling to a new destination the player runs
the risk of being intercepted by a WEAPCO patrol. After Spirit the player will select a planet
to travel to by clicking on it with the mouse. "Destination", followed by the planet's name
will appear in the bottom right hand corner of the screen. A new icon labelled "Go To Destination"
will also appear. Clicking this icon will make the player travel to the destination planet.</P>
<P>Travelling to new planets is represented at the bottom of the screen by the two planets (the
one being travelled from and the one being travelled to). A red bar will fill up as the journey
progresses. The speed the bar fills up will vary occurring to how far away the planets are from
one another. At any point during this time the planet can be intercepted (see Interceptions).
Once the red bar has filled up completely the journey will be completed and you will be
stationed that the new planet.</P>
<P>
<TABLE BGCOLOR="#000099" WIDTH="100%"><TR><TD><B>Interceptions</B></TD></TR></TABLE>
<P>Interceptions can take place whilst travelling between two planets within a system. When the
player is intercepted they will go directly into a mission-like scenario. The objective of this
interception is to clear all attacking forces. Once this is done, the player will be free to
leave.</P>
<P>Interceptions also serve other purposes - Sometimes the WEAPCO patrol may have slave
transports with them. One of the objectives of a later system is to rescue a certain amount of
slaves. This is only possible during interceptions.</P>
<P>One important thing to remember is that any damage the player receives during an interception
will NOT be repaired until they have reached the destination planet. Therefore if the player
is heavily damaged during one interception that damage will still be present if they are
attacked again. This can make interceptions very dangerous.</P>
<P>
<TABLE BGCOLOR="#000099" WIDTH="100%"><TR><TD><B>Weaponry and Upgrades</B></TD></TR></TABLE>
<P>During the course of the game you will receive money. Money is gained from destroying enemy craft
and picking up cash spheres in game (please be aware that due to the nature of the game cash is not
earned for destroying ships during Interceptions).</P>
<P>Money can be used to upgrade the Firefly and purchase additional ammunition for weapons. Items
can be purchased from a shop on the Intermission screen.</P>
<P><B>Temporary Upgrades</B>
<UL>Temporary upgrades are used to boost the Firefly's ability to be powered up. For example, at
the start of the game the Firefly can only be powered up to fire two plasma bolts are once. By
purchasing an upgrade for the Firefly, you can allow for power ups to enable you to fire a maximum
of up to five plasma bolts at once. Note that this only affects power ups and these will still be
ammunition limited. To upgrade your default weapon, you will need permanent power ups (see below).
</UL>
</P>
<P><B>Permanent Upgrades</B></P>
<UL>These power ups are more expensive than temporary upgrades, but are permanent. Whereas a temporary
upgrade requires you to make use of power ups on an ammunition limited base, permanent power ups are
not limited. This is highly useful when facing heavily shielded and tough opponents, with no means
of getting plasma ammo or transports in sight! When you power up your permanent weapon, your
powered up weapon level will also be automatically upgraded if it is less powerful than your new
current power up level.<P/>
When the Firefly's Primary Weapon has been upgraded to its maximum output (3 plasma cannons) the
player can toggle the output type by pressing Shift. The output type can either be Concentrate (the
default firing type) or Spread. Various situations can call for varying the output type.
</UL>
<P><B>Secondary Weapons</B></P>
<UL>
As well as primary weapons and temporary upgrades, the Firefly is also capable of using a
secondary weapon. At the start of the game this is a rocket launcher. Like the other weapons in the
game this can be upgraded by purchasing a new weapon from the shop. At the start of the game, a
Double Rocket Launcher and Micro Rocket Launcher are available for purchase. Secondary weapons are
used in the same way the rocket launcher is used (Space to fire). However the Laser Cannon and
Charge Cannon work differently.<P/>
Neither the Charge Cannon or the Laser Cannon are ammunition limited (unlike the other rocket based
weapons). The Charge Cannon works by the player holding down the Space bar and releasing it. A
meter at the bottom of the screen shows how much charge has been built up. The Laser Cannon works
by the player holding down the Space bar to fire a stream of laser fire. It is prone to over heating
and must be allowed to cool after usage.
</UL>
<P>Certain weapons and upgrades will not be available to you until later in the game, so remember
to save your money for them</P>
<P>
<TABLE BGCOLOR="#000099" WIDTH="100%"><TR><TD><B>Item Spheres</B></TD></TR></TABLE>
<P>When an enemy craft is destroyed they will sometimes release ammo and cash spheres. Certain
enemy craft will release power up spheres that can give your weapon a temporary boost. The following
are spheres that can be picked up during missions,</P>
<TABLE>
<TR><TD><IMG SRC="cash.gif"></TD><TD><B>Cash Sphere</B> - Provides you with an additional cash bonus</TD></TR>
<TR><TD><IMG SRC="ammo.gif"></TD><TD><B>Plasma Ammo Sphere</B> - Increases your current plasma ammo</TD></TR>
<TR><TD><IMG SRC="rocketAmmo.png"></TD><TD><B>Rocket Ammo Sphere</B> - Increases your current rocket ammo</TD></TR>
<TR><TD><IMG SRC="plasmaDamage.png"></TD><TD><B>Power Sphere</B> - Boosts your plasma power</TD></TR>
<TR><TD><IMG SRC="plasmaAmmo.png"></TD><TD><B>Output Sphere</B> - Boosts the amount of plasma shots you can fire</TD></TR>
<TR><TD><IMG SRC="plasmaRate.png"></TD><TD><B>Cooler Sphere</B> - Increases your plasma firing rate</TD></TR>
<TR><TD><IMG SRC="superCharge.png"></TD><TD><B>Super Sphere</B> - Three / Five way spread, full power and cooling (Rare)</TD></TR>
</TABLE>
</P>
<P>
<TABLE BGCOLOR="#000099" WIDTH="100%"><TR><TD><B>Cut Scenes</B></TD></TR></TABLE>
<P>During the course of the game mini cut scenes will be shown after certain missions. These scenes
serve to extend the plot of the game and provide the player with gameplay tips. If you wish to
skip a cut scene press Escape. It is advised that you only skip cut scenes if you have already seen
them.</P>
<P>
<TABLE BGCOLOR="#000099" WIDTH="100%"><TR><TD><B>Ending the Game</B></TD></TR></TABLE>
<P>The game is over when the Firefly's shield units are reduced to 0 (zero), or a Primary Mission
objective is failed. At this point, you will see the Game Over screen. To continue, press Ctrl
or Space. You will then be taken back to the title screen. In certain missions the game will end
if Sid Wilson is killed.</P>
<P>
<TABLE BGCOLOR="#000099" WIDTH="100%"><TR><TD><B>About</B></TD></TR></TABLE>
<P>Parallel Realities started off writing games on the Amiga using AMOS and then, later, Blitz Basic
2. Games written included the BOTSS Trilogy and most notably TANX Squadron. TANX Squadron was awarded
Amiga Format's contributor prize of the month in the summer of 1999. Project: Starfighter originally
started life on the Amiga but was never completed. Development began again for Linux in 2002 with this
being our first C program. The game matured quickly from the initial ideas and this is the finished
product. We do hope you enjoy playing it.</P>
<P>Project: Starfighter<BR>
Copyright Parallel Realities 2003<BR>
All Rights Reserved</P>
<P>Created using the <A HREF="http://www.libsdl.org">SDL library</A></P>
<P ALIGN="RIGHT"><A HREF="http://www.parallelrealities.co.uk">www.parallelrealities.co.uk</A></P>
</BODY>
</HTML>

37
makefile Executable file
View File

@ -0,0 +1,37 @@
CFLAGS = `sdl-config --cflags` -Wall -DLINUX
LIBS = `sdl-config --libs` -lSDL_mixer -lSDL_image
OBJS = ai.o aliens.o audio.o bullets.o cargo.o collectable.o comms.o debris.o events.o explosions.o game.o globals.o graphics.o init.o intermission.o loadSave.o messages.o misc.o missions.o player.o resources.o script.o shop.o Starfighter.o title.o unpack.o weapons.o
VERSION = 1.1
PROG = starfighter
PACK = starfighter.pak
DOCS = docs/*
BINDIR = /usr/games/
DATADIR = /usr/share/games/parallelrealities/
DOCDIR = /usr/share/doc/starfighter/
# top-level rule to create the program.
all: $(PROG)
# compiling other source files.
%.o: code/%.cpp code/%.h code/structs.h code/defs.h code/classes.h
$(CXX) $(CFLAGS) -c -O3 -DVERSION=\"$(VERSION)\" -DPACKLOCATION=\"$(DATADIR)$(PACK)\" $<
# linking the program.
$(PROG): $(OBJS)
$(CXX) $(LIBS) $(OBJS) -o $(PROG)
# cleaning everything that can be automatically recreated with "make".
clean:
$(RM) $(OBJS)
distclean:
$(RM) $(PROG)
# install
install:
mkdir -p $(DATADIR)
strip $(PROG)
install -o root -g games -m 755 $(PROG) $(BINDIR)$(PROG)
install -o root -g games -m 644 $(PACK) $(DATADIR)$(PACK)
cp $(DOCS) $(DOCDIR)