mirror of
https://github.com/dhewm/dhewm3.git
synced 2024-11-27 14:42:23 +00:00
736ec20d4d
Don't include the lazy precompiled.h everywhere, only what's required for the compilation unit. platform.h needs to be included instead to provide all essential defines and types. All includes use the relative path to the neo or the game specific root. Move all idlib related includes from idlib/Lib.h to precompiled.h. precompiled.h still exists for the MFC stuff in tools/. Add some missing header guards.
2296 lines
60 KiB
C++
2296 lines
60 KiB
C++
/*
|
|
===========================================================================
|
|
|
|
Doom 3 GPL Source Code
|
|
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
|
|
|
This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
|
|
|
|
Doom 3 Source Code 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 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Doom 3 Source Code 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 Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
|
|
|
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
|
|
|
===========================================================================
|
|
*/
|
|
|
|
#include "sys/platform.h"
|
|
#include "framework/Session_local.h"
|
|
#include "sound/sound.h"
|
|
#include "ui/DeviceContext.h"
|
|
#include "ui/Window.h"
|
|
#include "ui/UserInterfaceLocal.h"
|
|
|
|
#include "ui/GameSSDWindow.h"
|
|
|
|
#define Z_NEAR 100.0f
|
|
#define Z_FAR 4000.0f
|
|
#define ENTITY_START_DIST 3000
|
|
|
|
#define V_WIDTH 640.0f
|
|
#define V_HEIGHT 480.0f
|
|
|
|
/*
|
|
*****************************************************************************
|
|
* SSDCrossHair
|
|
****************************************************************************
|
|
*/
|
|
|
|
#define CROSSHAIR_STANDARD_MATERIAL "game/SSD/crosshair_standard"
|
|
#define CROSSHAIR_SUPER_MATERIAL "game/SSD/crosshair_super"
|
|
|
|
SSDCrossHair::SSDCrossHair() {
|
|
}
|
|
|
|
SSDCrossHair::~SSDCrossHair() {
|
|
}
|
|
|
|
void SSDCrossHair::WriteToSaveGame( idFile *savefile ) {
|
|
|
|
savefile->Write(¤tCrosshair, sizeof(currentCrosshair));
|
|
savefile->Write(&crosshairWidth, sizeof(crosshairWidth));
|
|
savefile->Write(&crosshairHeight, sizeof(crosshairHeight));
|
|
|
|
}
|
|
|
|
void SSDCrossHair::ReadFromSaveGame( idFile *savefile ) {
|
|
|
|
InitCrosshairs();
|
|
|
|
savefile->Read(¤tCrosshair, sizeof(currentCrosshair));
|
|
savefile->Read(&crosshairWidth, sizeof(crosshairWidth));
|
|
savefile->Read(&crosshairHeight, sizeof(crosshairHeight));
|
|
|
|
}
|
|
|
|
void SSDCrossHair::InitCrosshairs() {
|
|
|
|
crosshairMaterial[CROSSHAIR_STANDARD] = declManager->FindMaterial( CROSSHAIR_STANDARD_MATERIAL );
|
|
crosshairMaterial[CROSSHAIR_SUPER] = declManager->FindMaterial( CROSSHAIR_SUPER_MATERIAL );
|
|
|
|
crosshairWidth = 64;
|
|
crosshairHeight = 64;
|
|
|
|
currentCrosshair = CROSSHAIR_STANDARD;
|
|
|
|
}
|
|
|
|
void SSDCrossHair::Draw(idDeviceContext *dc, const idVec2& cursor) {
|
|
|
|
float x,y;
|
|
x = cursor.x-(crosshairWidth/2);
|
|
y = cursor.y-(crosshairHeight/2);
|
|
dc->DrawMaterial(x, y, crosshairWidth, crosshairHeight, crosshairMaterial[currentCrosshair], colorWhite, 1.0f, 1.0f);
|
|
|
|
}
|
|
|
|
/*
|
|
*****************************************************************************
|
|
* SSDEntity
|
|
****************************************************************************
|
|
*/
|
|
|
|
SSDEntity::SSDEntity() {
|
|
EntityInit();
|
|
}
|
|
|
|
SSDEntity::~SSDEntity() {
|
|
}
|
|
|
|
void SSDEntity::WriteToSaveGame( idFile *savefile ) {
|
|
|
|
savefile->Write(&type, sizeof(type));
|
|
game->WriteSaveGameString(materialName, savefile);
|
|
savefile->Write(&position, sizeof(position));
|
|
savefile->Write(&size, sizeof(size));
|
|
savefile->Write(&radius, sizeof(radius));
|
|
savefile->Write(&hitRadius, sizeof(hitRadius));
|
|
savefile->Write(&rotation, sizeof(rotation));
|
|
|
|
savefile->Write(&matColor, sizeof(matColor));
|
|
|
|
game->WriteSaveGameString(text, savefile);
|
|
savefile->Write(&textScale, sizeof(textScale));
|
|
savefile->Write(&foreColor, sizeof(foreColor));
|
|
|
|
savefile->Write(¤tTime, sizeof(currentTime));
|
|
savefile->Write(&lastUpdate, sizeof(lastUpdate));
|
|
savefile->Write(&elapsed, sizeof(elapsed));
|
|
|
|
savefile->Write(&destroyed, sizeof(destroyed));
|
|
savefile->Write(&noHit, sizeof(noHit));
|
|
savefile->Write(&noPlayerDamage, sizeof(noPlayerDamage));
|
|
|
|
savefile->Write(&inUse, sizeof(inUse));
|
|
|
|
}
|
|
|
|
void SSDEntity::ReadFromSaveGame( idFile *savefile, idGameSSDWindow* _game ) {
|
|
|
|
savefile->Read(&type, sizeof(type));
|
|
game->ReadSaveGameString(materialName, savefile);
|
|
SetMaterial(materialName);
|
|
savefile->Read(&position, sizeof(position));
|
|
savefile->Read(&size, sizeof(size));
|
|
savefile->Read(&radius, sizeof(radius));
|
|
savefile->Read(&hitRadius, sizeof(hitRadius));
|
|
savefile->Read(&rotation, sizeof(rotation));
|
|
|
|
savefile->Read(&matColor, sizeof(matColor));
|
|
|
|
game->ReadSaveGameString(text, savefile);
|
|
savefile->Read(&textScale, sizeof(textScale));
|
|
savefile->Read(&foreColor, sizeof(foreColor));
|
|
|
|
game = _game;
|
|
savefile->Read(¤tTime, sizeof(currentTime));
|
|
savefile->Read(&lastUpdate, sizeof(lastUpdate));
|
|
savefile->Read(&elapsed, sizeof(elapsed));
|
|
|
|
savefile->Read(&destroyed, sizeof(destroyed));
|
|
savefile->Read(&noHit, sizeof(noHit));
|
|
savefile->Read(&noPlayerDamage, sizeof(noPlayerDamage));
|
|
|
|
savefile->Read(&inUse, sizeof(inUse));
|
|
}
|
|
|
|
void SSDEntity::EntityInit() {
|
|
|
|
inUse = false;
|
|
|
|
|
|
type = SSD_ENTITY_BASE;
|
|
|
|
materialName = "";
|
|
material = NULL;
|
|
position.Zero();
|
|
size.Zero();
|
|
radius = 0.0f;
|
|
hitRadius = 0.0f;
|
|
rotation = 0.0f;
|
|
|
|
|
|
currentTime = 0;
|
|
lastUpdate = 0;
|
|
|
|
destroyed = false;
|
|
noHit = false;
|
|
noPlayerDamage = false;
|
|
|
|
matColor.Set(1, 1, 1, 1);
|
|
|
|
text = "";
|
|
textScale = 1.0f;
|
|
foreColor.Set(1, 1, 1, 1);
|
|
}
|
|
|
|
void SSDEntity::SetGame(idGameSSDWindow* _game) {
|
|
game = _game;
|
|
}
|
|
|
|
void SSDEntity::SetMaterial(const char* name) {
|
|
materialName = name;
|
|
material = declManager->FindMaterial( name );
|
|
material->SetSort( SS_GUI );
|
|
}
|
|
|
|
void SSDEntity::SetPosition(const idVec3& _position) {
|
|
position = _position;
|
|
}
|
|
|
|
void SSDEntity::SetSize(const idVec2& _size) {
|
|
size = _size;
|
|
}
|
|
|
|
void SSDEntity::SetRadius(float _radius, float _hitFactor) {
|
|
radius = _radius;
|
|
hitRadius = _radius*_hitFactor;
|
|
}
|
|
|
|
void SSDEntity::SetRotation(float _rotation) {
|
|
rotation = _rotation;
|
|
}
|
|
|
|
void SSDEntity::Update() {
|
|
|
|
currentTime = game->ssdTime;
|
|
|
|
//Is this the first update
|
|
if(lastUpdate == 0) {
|
|
lastUpdate = currentTime;
|
|
return;
|
|
}
|
|
|
|
elapsed = currentTime - lastUpdate;
|
|
|
|
EntityUpdate();
|
|
|
|
lastUpdate = currentTime;
|
|
}
|
|
|
|
bool SSDEntity::HitTest(const idVec2& pt) {
|
|
|
|
if(noHit) {
|
|
return false;
|
|
}
|
|
|
|
idVec3 screenPos = WorldToScreen(position);
|
|
|
|
|
|
//Scale the radius based on the distance from the player
|
|
float scale = 1.0f -((screenPos.z-Z_NEAR)/(Z_FAR-Z_NEAR));
|
|
float scaledRad = scale*hitRadius;
|
|
|
|
//So we can compare against the square of the length between two points
|
|
float scaleRadSqr = scaledRad*scaledRad;
|
|
|
|
idVec2 diff = screenPos.ToVec2()-pt;
|
|
float dist = idMath::Fabs(diff.LengthSqr());
|
|
|
|
if(dist < scaleRadSqr) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void SSDEntity::Draw(idDeviceContext *dc) {
|
|
|
|
|
|
idVec2 persize;
|
|
float x,y;
|
|
|
|
idBounds bounds;
|
|
bounds[0] = idVec3(position.x - (size.x/2.0f), position.y - (size.y/2.0f), position.z);
|
|
bounds[1] = idVec3(position.x + (size.x/2.0f), position.y + (size.y/2.0f), position.z);
|
|
|
|
idBounds screenBounds = WorldToScreen(bounds);
|
|
persize.x = idMath::Fabs(screenBounds[1].x - screenBounds[0].x);
|
|
persize.y = idMath::Fabs(screenBounds[1].y - screenBounds[0].y);
|
|
|
|
x = screenBounds[0].x;
|
|
y = screenBounds[1].y;
|
|
dc->DrawMaterialRotated(x, y, persize.x, persize.y, material, matColor, 1.0f, 1.0f, DEG2RAD(rotation));
|
|
|
|
if(text.Length() > 0) {
|
|
idRectangle rect( x, y, VIRTUAL_WIDTH, VIRTUAL_HEIGHT );
|
|
dc->DrawText( text, textScale, 0, foreColor, rect, false );
|
|
}
|
|
|
|
}
|
|
|
|
void SSDEntity::DestroyEntity() {
|
|
inUse = false;
|
|
}
|
|
|
|
idBounds SSDEntity::WorldToScreen(const idBounds worldBounds) {
|
|
|
|
idVec3 screenMin = WorldToScreen(worldBounds[0]);
|
|
idVec3 screenMax = WorldToScreen(worldBounds[1]);
|
|
|
|
idBounds screenBounds(screenMin, screenMax);
|
|
return screenBounds;
|
|
}
|
|
|
|
idVec3 SSDEntity::WorldToScreen(const idVec3& worldPos) {
|
|
|
|
float d = 0.5f*V_WIDTH*idMath::Tan(DEG2RAD(90.0f)/2.0f);
|
|
|
|
//World To Camera Coordinates
|
|
idVec3 cameraTrans(0,0,d);
|
|
idVec3 cameraPos;
|
|
cameraPos = worldPos + cameraTrans;
|
|
|
|
//Camera To Screen Coordinates
|
|
idVec3 screenPos;
|
|
screenPos.x = d*cameraPos.x/cameraPos.z + (0.5f*V_WIDTH-0.5f);
|
|
screenPos.y = -d*cameraPos.y/cameraPos.z + (0.5f*V_HEIGHT-0.5f);
|
|
screenPos.z = cameraPos.z;
|
|
|
|
return screenPos;
|
|
}
|
|
|
|
idVec3 SSDEntity::ScreenToWorld(const idVec3& screenPos) {
|
|
|
|
idVec3 worldPos;
|
|
|
|
worldPos.x = screenPos.x - 0.5f * V_WIDTH;
|
|
worldPos.y = -(screenPos.y - 0.5f * V_HEIGHT);
|
|
worldPos.z = screenPos.z;
|
|
|
|
return worldPos;
|
|
}
|
|
|
|
/*
|
|
*****************************************************************************
|
|
* SSDMover
|
|
****************************************************************************
|
|
*/
|
|
|
|
SSDMover::SSDMover() {
|
|
}
|
|
|
|
SSDMover::~SSDMover() {
|
|
}
|
|
|
|
void SSDMover::WriteToSaveGame( idFile *savefile ) {
|
|
SSDEntity::WriteToSaveGame(savefile);
|
|
|
|
savefile->Write(&speed, sizeof(speed));
|
|
savefile->Write(&rotationSpeed, sizeof(rotationSpeed));
|
|
}
|
|
|
|
void SSDMover::ReadFromSaveGame( idFile *savefile, idGameSSDWindow* _game ) {
|
|
SSDEntity::ReadFromSaveGame(savefile, _game);
|
|
|
|
savefile->Read(&speed, sizeof(speed));
|
|
savefile->Read(&rotationSpeed, sizeof(rotationSpeed));
|
|
}
|
|
|
|
void SSDMover::MoverInit(const idVec3& _speed, float _rotationSpeed) {
|
|
|
|
speed = _speed;
|
|
rotationSpeed = _rotationSpeed;
|
|
}
|
|
|
|
void SSDMover::EntityUpdate() {
|
|
|
|
SSDEntity::EntityUpdate();
|
|
|
|
//Move forward based on speed (units per second)
|
|
idVec3 moved = ((float)elapsed/1000.0f)*speed;
|
|
position += moved;
|
|
|
|
float rotated = ((float)elapsed/1000.0f)*rotationSpeed*360.0f;
|
|
rotation += rotated;
|
|
if(rotation >= 360) {
|
|
rotation -= 360.0f;
|
|
}
|
|
if(rotation < 0) {
|
|
rotation += 360.0f;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
*****************************************************************************
|
|
* SSDAsteroid
|
|
****************************************************************************
|
|
*/
|
|
|
|
SSDAsteroid SSDAsteroid::asteroidPool[MAX_ASTEROIDS];
|
|
|
|
#define ASTEROID_MATERIAL "game/SSD/asteroid"
|
|
|
|
SSDAsteroid::SSDAsteroid() {
|
|
}
|
|
|
|
SSDAsteroid::~SSDAsteroid() {
|
|
}
|
|
|
|
void SSDAsteroid::WriteToSaveGame( idFile *savefile ) {
|
|
SSDMover::WriteToSaveGame(savefile);
|
|
|
|
savefile->Write(&health, sizeof(health));
|
|
}
|
|
|
|
void SSDAsteroid::ReadFromSaveGame( idFile *savefile, idGameSSDWindow* _game ) {
|
|
SSDMover::ReadFromSaveGame(savefile, _game);
|
|
|
|
savefile->Read(&health, sizeof(health));
|
|
}
|
|
|
|
void SSDAsteroid::Init(idGameSSDWindow* _game, const idVec3& startPosition, const idVec2& _size, float _speed, float rotate, int _health) {
|
|
|
|
EntityInit();
|
|
MoverInit(idVec3(0,0, -_speed), rotate);
|
|
|
|
SetGame(_game);
|
|
|
|
type = SSD_ENTITY_ASTEROID;
|
|
|
|
SetMaterial(ASTEROID_MATERIAL);
|
|
SetSize(_size);
|
|
SetRadius(Max(size.x, size.y), 0.3f);
|
|
SetRotation(game->random.RandomInt(360));
|
|
|
|
|
|
position = startPosition;
|
|
|
|
health = _health;
|
|
}
|
|
|
|
void SSDAsteroid::EntityUpdate() {
|
|
|
|
SSDMover::EntityUpdate();
|
|
}
|
|
|
|
SSDAsteroid* SSDAsteroid::GetNewAsteroid(idGameSSDWindow* _game, const idVec3& startPosition, const idVec2& _size, float _speed, float rotate, int _health) {
|
|
for(int i = 0; i < MAX_ASTEROIDS; i++) {
|
|
if(!asteroidPool[i].inUse) {
|
|
asteroidPool[i].Init(_game, startPosition, _size, _speed, rotate, _health);
|
|
asteroidPool[i].inUse = true;
|
|
asteroidPool[i].id = i;
|
|
|
|
return &asteroidPool[i];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
SSDAsteroid* SSDAsteroid::GetSpecificAsteroid(int id) {
|
|
return &asteroidPool[id];
|
|
}
|
|
|
|
void SSDAsteroid::WriteAsteroids(idFile* savefile) {
|
|
int count = 0;
|
|
for(int i = 0; i < MAX_ASTEROIDS; i++) {
|
|
if(asteroidPool[i].inUse) {
|
|
count++;
|
|
}
|
|
}
|
|
savefile->Write(&count, sizeof(count));
|
|
for(int i = 0; i < MAX_ASTEROIDS; i++) {
|
|
if(asteroidPool[i].inUse) {
|
|
savefile->Write(&(asteroidPool[i].id), sizeof(asteroidPool[i].id));
|
|
asteroidPool[i].WriteToSaveGame(savefile);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SSDAsteroid::ReadAsteroids(idFile* savefile, idGameSSDWindow* _game) {
|
|
|
|
int count;
|
|
savefile->Read(&count, sizeof(count));
|
|
for(int i = 0; i < count; i++) {
|
|
int id;
|
|
savefile->Read(&id, sizeof(id));
|
|
SSDAsteroid* ent = GetSpecificAsteroid(id);
|
|
ent->ReadFromSaveGame(savefile, _game);
|
|
}
|
|
}
|
|
|
|
/*
|
|
*****************************************************************************
|
|
* SSDAstronaut
|
|
****************************************************************************
|
|
*/
|
|
|
|
SSDAstronaut SSDAstronaut::astronautPool[MAX_ASTRONAUT];
|
|
|
|
#define ASTRONAUT_MATERIAL "game/SSD/astronaut"
|
|
|
|
SSDAstronaut::SSDAstronaut() {
|
|
}
|
|
|
|
SSDAstronaut::~SSDAstronaut() {
|
|
}
|
|
|
|
void SSDAstronaut::WriteToSaveGame( idFile *savefile ) {
|
|
SSDMover::WriteToSaveGame(savefile);
|
|
|
|
savefile->Write(&health, sizeof(health));
|
|
}
|
|
|
|
void SSDAstronaut::ReadFromSaveGame( idFile *savefile, idGameSSDWindow* _game ) {
|
|
SSDMover::ReadFromSaveGame(savefile, _game);
|
|
|
|
savefile->Read(&health, sizeof(health));
|
|
}
|
|
|
|
void SSDAstronaut::Init(idGameSSDWindow* _game, const idVec3& startPosition, float _speed, float rotate, int _health) {
|
|
|
|
EntityInit();
|
|
MoverInit(idVec3(0,0, -_speed), rotate);
|
|
|
|
SetGame(_game);
|
|
|
|
type = SSD_ENTITY_ASTRONAUT;
|
|
|
|
SetMaterial(ASTRONAUT_MATERIAL);
|
|
SetSize(idVec2(256,256));
|
|
SetRadius(Max(size.x, size.y), 0.3f);
|
|
SetRotation(game->random.RandomInt(360));
|
|
|
|
position = startPosition;
|
|
health = _health;
|
|
}
|
|
|
|
SSDAstronaut* SSDAstronaut::GetNewAstronaut(idGameSSDWindow* _game, const idVec3& startPosition, float _speed, float rotate, int _health) {
|
|
for(int i = 0; i < MAX_ASTRONAUT; i++) {
|
|
if(!astronautPool[i].inUse) {
|
|
astronautPool[i].Init(_game, startPosition, _speed, rotate, _health);
|
|
astronautPool[i].inUse = true;
|
|
astronautPool[i].id = i;
|
|
return &astronautPool[i];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
SSDAstronaut* SSDAstronaut::GetSpecificAstronaut(int id) {
|
|
return &astronautPool[id];
|
|
|
|
}
|
|
|
|
void SSDAstronaut::WriteAstronauts(idFile* savefile) {
|
|
int count = 0;
|
|
for(int i = 0; i < MAX_ASTRONAUT; i++) {
|
|
if(astronautPool[i].inUse) {
|
|
count++;
|
|
}
|
|
}
|
|
savefile->Write(&count, sizeof(count));
|
|
for(int i = 0; i < MAX_ASTRONAUT; i++) {
|
|
if(astronautPool[i].inUse) {
|
|
savefile->Write(&(astronautPool[i].id), sizeof(astronautPool[i].id));
|
|
astronautPool[i].WriteToSaveGame(savefile);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SSDAstronaut::ReadAstronauts(idFile* savefile, idGameSSDWindow* _game) {
|
|
|
|
int count;
|
|
savefile->Read(&count, sizeof(count));
|
|
for(int i = 0; i < count; i++) {
|
|
int id;
|
|
savefile->Read(&id, sizeof(id));
|
|
SSDAstronaut* ent = GetSpecificAstronaut(id);
|
|
ent->ReadFromSaveGame(savefile, _game);
|
|
}
|
|
}
|
|
|
|
/*
|
|
*****************************************************************************
|
|
* SSDExplosion
|
|
****************************************************************************
|
|
*/
|
|
|
|
SSDExplosion SSDExplosion::explosionPool[MAX_EXPLOSIONS];
|
|
|
|
|
|
//#define EXPLOSION_MATERIAL "game/SSD/fball"
|
|
//#define EXPLOSION_TELEPORT "game/SSD/teleport"
|
|
|
|
const char* explosionMaterials[] = {
|
|
"game/SSD/fball",
|
|
"game/SSD/teleport"
|
|
};
|
|
|
|
#define EXPLOSION_MATERIAL_COUNT 2
|
|
|
|
SSDExplosion::SSDExplosion() {
|
|
type = SSD_ENTITY_EXPLOSION;
|
|
}
|
|
|
|
SSDExplosion::~SSDExplosion() {
|
|
}
|
|
|
|
void SSDExplosion::WriteToSaveGame( idFile *savefile ) {
|
|
SSDEntity::WriteToSaveGame(savefile);
|
|
|
|
savefile->Write(&finalSize, sizeof(finalSize));
|
|
savefile->Write(&length, sizeof(length));
|
|
savefile->Write(&beginTime, sizeof(beginTime));
|
|
savefile->Write(&endTime, sizeof(endTime));
|
|
savefile->Write(&explosionType, sizeof(explosionType));
|
|
|
|
|
|
savefile->Write(&(buddy->type), sizeof(buddy->type));
|
|
savefile->Write(&(buddy->id), sizeof(buddy->id));
|
|
|
|
savefile->Write(&killBuddy, sizeof(killBuddy));
|
|
savefile->Write(&followBuddy, sizeof(followBuddy));
|
|
}
|
|
|
|
void SSDExplosion::ReadFromSaveGame( idFile *savefile, idGameSSDWindow* _game ) {
|
|
SSDEntity::ReadFromSaveGame(savefile, _game);
|
|
|
|
savefile->Read(&finalSize, sizeof(finalSize));
|
|
savefile->Read(&length, sizeof(length));
|
|
savefile->Read(&beginTime, sizeof(beginTime));
|
|
savefile->Read(&endTime, sizeof(endTime));
|
|
savefile->Read(&explosionType, sizeof(explosionType));
|
|
|
|
int type, id;
|
|
savefile->Read(&type, sizeof(type));
|
|
savefile->Read(&id, sizeof(id));
|
|
|
|
//Get a pointer to my buddy
|
|
buddy = _game->GetSpecificEntity(type, id);
|
|
|
|
savefile->Read(&killBuddy, sizeof(killBuddy));
|
|
savefile->Read(&followBuddy, sizeof(followBuddy));
|
|
}
|
|
|
|
void SSDExplosion::Init(idGameSSDWindow* _game, const idVec3& _position, const idVec2& _size, int _length, int _type, SSDEntity* _buddy, bool _killBuddy, bool _followBuddy) {
|
|
|
|
EntityInit();
|
|
|
|
SetGame(_game);
|
|
|
|
type = SSD_ENTITY_EXPLOSION;
|
|
explosionType = _type;
|
|
|
|
SetMaterial(explosionMaterials[explosionType]);
|
|
SetPosition(_position);
|
|
position.z -= 50;
|
|
|
|
finalSize = _size;
|
|
length = _length;
|
|
beginTime = game->ssdTime;
|
|
endTime = beginTime + length;
|
|
|
|
buddy = _buddy;
|
|
killBuddy = _killBuddy;
|
|
followBuddy = _followBuddy;
|
|
|
|
//Explosion Starts from nothing and will increase in size until it gets to final size
|
|
size.Zero();
|
|
|
|
noPlayerDamage = true;
|
|
noHit = true;
|
|
}
|
|
|
|
void SSDExplosion::EntityUpdate() {
|
|
|
|
SSDEntity::EntityUpdate();
|
|
|
|
//Always set my position to my buddies position except change z to be on top
|
|
if(followBuddy) {
|
|
position = buddy->position;
|
|
position.z -= 50;
|
|
} else {
|
|
//Only mess with the z if we are not following
|
|
position.z = buddy->position.z - 50;
|
|
}
|
|
|
|
//Scale the image based on the time
|
|
size = finalSize*((float)(currentTime-beginTime)/(float)length);
|
|
|
|
//Destroy myself after the explosion is done
|
|
if(currentTime > endTime) {
|
|
destroyed = true;
|
|
|
|
if(killBuddy) {
|
|
//Destroy the exploding object
|
|
buddy->destroyed = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
SSDExplosion* SSDExplosion::GetNewExplosion(idGameSSDWindow* _game, const idVec3& _position, const idVec2& _size, int _length, int _type, SSDEntity* _buddy, bool _killBuddy, bool _followBuddy) {
|
|
for(int i = 0; i < MAX_EXPLOSIONS; i++) {
|
|
if(!explosionPool[i].inUse) {
|
|
explosionPool[i].Init(_game, _position, _size, _length, _type, _buddy, _killBuddy, _followBuddy);
|
|
explosionPool[i].inUse = true;
|
|
return &explosionPool[i];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
SSDExplosion* SSDExplosion::GetSpecificExplosion(int id) {
|
|
return &explosionPool[id];
|
|
}
|
|
|
|
void SSDExplosion::WriteExplosions(idFile* savefile) {
|
|
int count = 0;
|
|
for(int i = 0; i < MAX_EXPLOSIONS; i++) {
|
|
if(explosionPool[i].inUse) {
|
|
count++;
|
|
}
|
|
}
|
|
savefile->Write(&count, sizeof(count));
|
|
for(int i = 0; i < MAX_EXPLOSIONS; i++) {
|
|
if(explosionPool[i].inUse) {
|
|
savefile->Write(&(explosionPool[i].id), sizeof(explosionPool[i].id));
|
|
explosionPool[i].WriteToSaveGame(savefile);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SSDExplosion::ReadExplosions(idFile* savefile, idGameSSDWindow* _game) {
|
|
|
|
int count;
|
|
savefile->Read(&count, sizeof(count));
|
|
for(int i = 0; i < count; i++) {
|
|
int id;
|
|
savefile->Read(&id, sizeof(id));
|
|
SSDExplosion* ent = GetSpecificExplosion(id);
|
|
ent->ReadFromSaveGame(savefile, _game);
|
|
}
|
|
}
|
|
|
|
/*
|
|
*****************************************************************************
|
|
* SSDPoints
|
|
****************************************************************************
|
|
*/
|
|
|
|
SSDPoints SSDPoints::pointsPool[MAX_POINTS];
|
|
|
|
SSDPoints::SSDPoints() {
|
|
type = SSD_ENTITY_POINTS;
|
|
}
|
|
|
|
SSDPoints::~SSDPoints() {
|
|
}
|
|
|
|
void SSDPoints::WriteToSaveGame( idFile *savefile ) {
|
|
SSDEntity::WriteToSaveGame(savefile);
|
|
|
|
savefile->Write(&length, sizeof(length));
|
|
savefile->Write(&distance, sizeof(distance));
|
|
savefile->Write(&beginTime, sizeof(beginTime));
|
|
savefile->Write(&endTime, sizeof(endTime));
|
|
|
|
savefile->Write(&beginPosition, sizeof(beginPosition));
|
|
savefile->Write(&endPosition, sizeof(endPosition));
|
|
|
|
savefile->Write(&beginColor, sizeof(beginColor));
|
|
savefile->Write(&endColor, sizeof(endColor));
|
|
|
|
}
|
|
|
|
void SSDPoints::ReadFromSaveGame( idFile *savefile, idGameSSDWindow* _game ) {
|
|
SSDEntity::ReadFromSaveGame(savefile, _game);
|
|
|
|
savefile->Read(&length, sizeof(length));
|
|
savefile->Read(&distance, sizeof(distance));
|
|
savefile->Read(&beginTime, sizeof(beginTime));
|
|
savefile->Read(&endTime, sizeof(endTime));
|
|
|
|
savefile->Read(&beginPosition, sizeof(beginPosition));
|
|
savefile->Read(&endPosition, sizeof(endPosition));
|
|
|
|
savefile->Read(&beginColor, sizeof(beginColor));
|
|
savefile->Read(&endColor, sizeof(endColor));
|
|
}
|
|
|
|
void SSDPoints::Init(idGameSSDWindow* _game, SSDEntity* _ent, int _points, int _length, int _distance, const idVec4& color) {
|
|
|
|
EntityInit();
|
|
|
|
SetGame(_game);
|
|
|
|
length = _length;
|
|
distance = _distance;
|
|
beginTime = game->ssdTime;
|
|
endTime = beginTime + length;
|
|
|
|
textScale = 0.4f;
|
|
text = va("%d", _points);
|
|
|
|
float width = 0;
|
|
for(int i = 0; i < text.Length(); i++) {
|
|
width += game->GetDC()->CharWidth(text[i], textScale);
|
|
}
|
|
|
|
size.Set(0,0);
|
|
|
|
//Set the start position at the top of the passed in entity
|
|
position = WorldToScreen(_ent->position);
|
|
position = ScreenToWorld(position);
|
|
|
|
position.z = 0;
|
|
position.x -= (width/2.0f);
|
|
|
|
beginPosition = position;
|
|
|
|
endPosition = beginPosition;
|
|
endPosition.y += _distance;
|
|
|
|
//beginColor.Set(0,1,0,1);
|
|
endColor.Set(1,1,1,0);
|
|
|
|
beginColor = color;
|
|
beginColor.w = 1;
|
|
|
|
noPlayerDamage = true;
|
|
noHit = true;
|
|
}
|
|
|
|
void SSDPoints::EntityUpdate() {
|
|
|
|
float t = (float)(currentTime - beginTime)/(float)length;
|
|
|
|
//Move up from the start position
|
|
position.Lerp(beginPosition, endPosition, t);
|
|
|
|
//Interpolate the color
|
|
foreColor.Lerp(beginColor, endColor, t);
|
|
|
|
if(currentTime > endTime) {
|
|
destroyed = true;
|
|
}
|
|
}
|
|
|
|
SSDPoints* SSDPoints::GetNewPoints(idGameSSDWindow* _game, SSDEntity* _ent, int _points, int _length, int _distance, const idVec4& color) {
|
|
for(int i = 0; i < MAX_POINTS; i++) {
|
|
if(!pointsPool[i].inUse) {
|
|
pointsPool[i].Init(_game, _ent, _points, _length, _distance, color);
|
|
pointsPool[i].inUse = true;
|
|
return &pointsPool[i];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
SSDPoints* SSDPoints::GetSpecificPoints(int id) {
|
|
return &pointsPool[id];
|
|
}
|
|
|
|
void SSDPoints::WritePoints(idFile* savefile) {
|
|
int count = 0;
|
|
for(int i = 0; i < MAX_POINTS; i++) {
|
|
if(pointsPool[i].inUse) {
|
|
count++;
|
|
}
|
|
}
|
|
savefile->Write(&count, sizeof(count));
|
|
for(int i = 0; i < MAX_POINTS; i++) {
|
|
if(pointsPool[i].inUse) {
|
|
savefile->Write(&(pointsPool[i].id), sizeof(pointsPool[i].id));
|
|
pointsPool[i].WriteToSaveGame(savefile);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SSDPoints::ReadPoints(idFile* savefile, idGameSSDWindow* _game) {
|
|
|
|
int count;
|
|
savefile->Read(&count, sizeof(count));
|
|
for(int i = 0; i < count; i++) {
|
|
int id;
|
|
savefile->Read(&id, sizeof(id));
|
|
SSDPoints* ent = GetSpecificPoints(id);
|
|
ent->ReadFromSaveGame(savefile, _game);
|
|
}
|
|
}
|
|
|
|
/*
|
|
*****************************************************************************
|
|
* SSDProjectile
|
|
****************************************************************************
|
|
*/
|
|
|
|
SSDProjectile SSDProjectile::projectilePool[MAX_PROJECTILES];
|
|
|
|
#define PROJECTILE_MATERIAL "game/SSD/fball"
|
|
|
|
SSDProjectile::SSDProjectile() {
|
|
type = SSD_ENTITY_PROJECTILE;
|
|
}
|
|
|
|
SSDProjectile::~SSDProjectile() {
|
|
}
|
|
|
|
void SSDProjectile::WriteToSaveGame( idFile *savefile ) {
|
|
SSDEntity::WriteToSaveGame(savefile);
|
|
|
|
savefile->Write(&dir, sizeof(dir));
|
|
savefile->Write(&speed, sizeof(speed));
|
|
savefile->Write(&beginTime, sizeof(beginTime));
|
|
savefile->Write(&endTime, sizeof(endTime));
|
|
|
|
savefile->Write(&endPosition, sizeof(endPosition));
|
|
}
|
|
|
|
void SSDProjectile::ReadFromSaveGame( idFile *savefile, idGameSSDWindow* _game ) {
|
|
SSDEntity::ReadFromSaveGame(savefile, _game);
|
|
|
|
savefile->Read(&dir, sizeof(dir));
|
|
savefile->Read(&speed, sizeof(speed));
|
|
savefile->Read(&beginTime, sizeof(beginTime));
|
|
savefile->Read(&endTime, sizeof(endTime));
|
|
|
|
savefile->Read(&endPosition, sizeof(endPosition));
|
|
}
|
|
|
|
void SSDProjectile::Init(idGameSSDWindow* _game, const idVec3& _beginPosition, const idVec3& _endPosition, float _speed, float _size) {
|
|
|
|
EntityInit();
|
|
|
|
SetGame(_game);
|
|
|
|
SetMaterial(PROJECTILE_MATERIAL);
|
|
size.Set(_size,_size);
|
|
|
|
position = _beginPosition;
|
|
endPosition = _endPosition;
|
|
|
|
dir = _endPosition - position;
|
|
dir.Normalize();
|
|
|
|
//speed.Zero();
|
|
speed.x = speed.y = speed.z = _speed;
|
|
|
|
noHit = true;
|
|
}
|
|
|
|
void SSDProjectile::EntityUpdate() {
|
|
|
|
SSDEntity::EntityUpdate();
|
|
|
|
//Move forward based on speed (units per second)
|
|
idVec3 moved = dir*((float)elapsed/1000.0f)*speed.z;
|
|
position += moved;
|
|
|
|
if(position.z > endPosition.z) {
|
|
//We have reached our position
|
|
destroyed = true;
|
|
}
|
|
}
|
|
|
|
SSDProjectile* SSDProjectile::GetNewProjectile(idGameSSDWindow* _game, const idVec3& _beginPosition, const idVec3& _endPosition, float _speed, float _size) {
|
|
for(int i = 0; i < MAX_PROJECTILES; i++) {
|
|
if(!projectilePool[i].inUse) {
|
|
projectilePool[i].Init(_game, _beginPosition, _endPosition, _speed, _size);
|
|
projectilePool[i].inUse = true;
|
|
return &projectilePool[i];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
SSDProjectile* SSDProjectile::GetSpecificProjectile(int id) {
|
|
return &projectilePool[id];
|
|
}
|
|
|
|
void SSDProjectile::WriteProjectiles(idFile* savefile) {
|
|
int count = 0;
|
|
for(int i = 0; i < MAX_PROJECTILES; i++) {
|
|
if(projectilePool[i].inUse) {
|
|
count++;
|
|
}
|
|
}
|
|
savefile->Write(&count, sizeof(count));
|
|
for(int i = 0; i < MAX_PROJECTILES; i++) {
|
|
if(projectilePool[i].inUse) {
|
|
savefile->Write(&(projectilePool[i].id), sizeof(projectilePool[i].id));
|
|
projectilePool[i].WriteToSaveGame(savefile);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SSDProjectile::ReadProjectiles(idFile* savefile, idGameSSDWindow* _game) {
|
|
|
|
int count;
|
|
savefile->Read(&count, sizeof(count));
|
|
for(int i = 0; i < count; i++) {
|
|
int id;
|
|
savefile->Read(&id, sizeof(id));
|
|
SSDProjectile* ent = GetSpecificProjectile(id);
|
|
ent->ReadFromSaveGame(savefile, _game);
|
|
}
|
|
}
|
|
|
|
/*
|
|
*****************************************************************************
|
|
* SSDPowerup
|
|
****************************************************************************
|
|
*/
|
|
|
|
const char* powerupMaterials[][2] = {
|
|
{ "game/SSD/powerupHealthClosed", "game/SSD/powerupHealthOpen" },
|
|
{ "game/SSD/powerupSuperBlasterClosed", "game/SSD/powerupSuperBlasterOpen" },
|
|
{ "game/SSD/powerupNukeClosed", "game/SSD/powerupNukeOpen" },
|
|
{ "game/SSD/powerupRescueClosed", "game/SSD/powerupRescueOpen" },
|
|
{ "game/SSD/powerupBonusPointsClosed", "game/SSD/powerupBonusPointsOpen" },
|
|
{ "game/SSD/powerupDamageClosed", "game/SSD/powerupDamageOpen" },
|
|
};
|
|
|
|
#define POWERUP_MATERIAL_COUNT 6
|
|
|
|
SSDPowerup SSDPowerup::powerupPool[MAX_POWERUPS];
|
|
|
|
SSDPowerup::SSDPowerup() {
|
|
|
|
}
|
|
|
|
SSDPowerup::~SSDPowerup() {
|
|
}
|
|
|
|
void SSDPowerup::WriteToSaveGame( idFile *savefile ) {
|
|
SSDMover::WriteToSaveGame(savefile);
|
|
|
|
savefile->Write(&powerupState, sizeof(powerupState));
|
|
savefile->Write(&powerupType, sizeof(powerupType));
|
|
}
|
|
|
|
void SSDPowerup::ReadFromSaveGame( idFile *savefile, idGameSSDWindow* _game ) {
|
|
SSDMover::ReadFromSaveGame(savefile, _game);
|
|
|
|
savefile->Read(&powerupState, sizeof(powerupState));
|
|
savefile->Read(&powerupType, sizeof(powerupType));
|
|
}
|
|
|
|
void SSDPowerup::OnHit(int key) {
|
|
|
|
if(powerupState == POWERUP_STATE_CLOSED) {
|
|
|
|
//Small explosion to indicate it is opened
|
|
SSDExplosion* explosion = SSDExplosion::GetNewExplosion(game, position, size*2.0f, 300, SSDExplosion::EXPLOSION_NORMAL, this, false, true);
|
|
game->entities.Append(explosion);
|
|
|
|
|
|
powerupState = POWERUP_STATE_OPEN;
|
|
SetMaterial(powerupMaterials[powerupType][powerupState]);
|
|
} else {
|
|
//Destory the powerup with a big explosion
|
|
SSDExplosion* explosion = SSDExplosion::GetNewExplosion(game, position, size*2, 300, SSDExplosion::EXPLOSION_NORMAL, this);
|
|
game->entities.Append(explosion);
|
|
game->PlaySound("arcade_explode");
|
|
|
|
noHit = true;
|
|
noPlayerDamage = true;
|
|
}
|
|
}
|
|
|
|
void SSDPowerup::OnStrikePlayer() {
|
|
|
|
if(powerupState == POWERUP_STATE_OPEN) {
|
|
//The powerup was open so activate it
|
|
OnActivatePowerup();
|
|
}
|
|
|
|
//Just destroy the powerup
|
|
destroyed = true;
|
|
}
|
|
|
|
void SSDPowerup::OnOpenPowerup() {
|
|
}
|
|
|
|
void SSDPowerup::OnActivatePowerup() {
|
|
switch(powerupType) {
|
|
case POWERUP_TYPE_HEALTH:
|
|
{
|
|
game->AddHealth(10);
|
|
break;
|
|
}
|
|
case POWERUP_TYPE_SUPER_BLASTER:
|
|
{
|
|
game->OnSuperBlaster();
|
|
break;
|
|
}
|
|
case POWERUP_TYPE_ASTEROID_NUKE:
|
|
{
|
|
game->OnNuke();
|
|
break;
|
|
}
|
|
case POWERUP_TYPE_RESCUE_ALL:
|
|
{
|
|
game->OnRescueAll();
|
|
break;
|
|
}
|
|
case POWERUP_TYPE_BONUS_POINTS:
|
|
{
|
|
int points = (game->random.RandomInt(5)+1) * 100;
|
|
game->AddScore(this, points);
|
|
break;
|
|
}
|
|
case POWERUP_TYPE_DAMAGE:
|
|
{
|
|
game->AddDamage(10);
|
|
game->PlaySound("arcade_explode");
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
void SSDPowerup::Init(idGameSSDWindow* _game, float _speed, float _rotation) {
|
|
|
|
EntityInit();
|
|
MoverInit(idVec3(0,0, -_speed), _rotation);
|
|
|
|
SetGame(_game);
|
|
SetSize(idVec2(200,200));
|
|
SetRadius(Max(size.x, size.y), 0.3f);
|
|
|
|
type = SSD_ENTITY_POWERUP;
|
|
|
|
idVec3 startPosition;
|
|
startPosition.x = game->random.RandomInt(V_WIDTH)-(V_WIDTH/2.0f);
|
|
startPosition.y = game->random.RandomInt(V_HEIGHT)-(V_HEIGHT/2.0f);
|
|
startPosition.z = ENTITY_START_DIST;
|
|
|
|
position = startPosition;
|
|
//SetPosition(startPosition);
|
|
|
|
powerupState = POWERUP_STATE_CLOSED;
|
|
powerupType = game->random.RandomInt(POWERUP_TYPE_MAX+1);
|
|
if(powerupType >= POWERUP_TYPE_MAX) {
|
|
powerupType = 0;
|
|
}
|
|
|
|
/*OutputDebugString(va("Powerup: %d\n", powerupType));
|
|
if(powerupType == 0) {
|
|
int x = 0;
|
|
}*/
|
|
|
|
SetMaterial(powerupMaterials[powerupType][powerupState]);
|
|
}
|
|
|
|
SSDPowerup* SSDPowerup::GetNewPowerup(idGameSSDWindow* _game, float _speed, float _rotation) {
|
|
|
|
for(int i = 0; i < MAX_POWERUPS; i++) {
|
|
if(!powerupPool[i].inUse) {
|
|
powerupPool[i].Init(_game, _speed, _rotation);
|
|
powerupPool[i].inUse = true;
|
|
return &powerupPool[i];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
SSDPowerup* SSDPowerup::GetSpecificPowerup(int id) {
|
|
return &powerupPool[id];
|
|
}
|
|
|
|
void SSDPowerup::WritePowerups(idFile* savefile) {
|
|
int count = 0;
|
|
for(int i = 0; i < MAX_POWERUPS; i++) {
|
|
if(powerupPool[i].inUse) {
|
|
count++;
|
|
}
|
|
}
|
|
savefile->Write(&count, sizeof(count));
|
|
for(int i = 0; i < MAX_POWERUPS; i++) {
|
|
if(powerupPool[i].inUse) {
|
|
savefile->Write(&(powerupPool[i].id), sizeof(powerupPool[i].id));
|
|
powerupPool[i].WriteToSaveGame(savefile);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SSDPowerup::ReadPowerups(idFile* savefile, idGameSSDWindow* _game) {
|
|
|
|
int count;
|
|
savefile->Read(&count, sizeof(count));
|
|
for(int i = 0; i < count; i++) {
|
|
int id;
|
|
savefile->Read(&id, sizeof(id));
|
|
SSDPowerup* ent = GetSpecificPowerup(id);
|
|
ent->ReadFromSaveGame(savefile, _game);
|
|
}
|
|
}
|
|
|
|
/*
|
|
*****************************************************************************
|
|
* idGameSSDWindow
|
|
****************************************************************************
|
|
*/
|
|
|
|
idRandom idGameSSDWindow::random;
|
|
|
|
idGameSSDWindow::idGameSSDWindow(idDeviceContext *d, idUserInterfaceLocal *g) : idWindow(d, g) {
|
|
dc = d;
|
|
gui = g;
|
|
CommonInit();
|
|
}
|
|
|
|
idGameSSDWindow::idGameSSDWindow(idUserInterfaceLocal *g) : idWindow(g) {
|
|
gui = g;
|
|
CommonInit();
|
|
}
|
|
|
|
idGameSSDWindow::~idGameSSDWindow() {
|
|
ResetGameStats();
|
|
}
|
|
|
|
void idGameSSDWindow::WriteToSaveGame( idFile *savefile ) {
|
|
idWindow::WriteToSaveGame(savefile);
|
|
|
|
savefile->Write(&ssdTime, sizeof(ssdTime));
|
|
|
|
beginLevel.WriteToSaveGame(savefile);
|
|
resetGame.WriteToSaveGame(savefile);
|
|
continueGame.WriteToSaveGame(savefile);
|
|
refreshGuiData.WriteToSaveGame(savefile);
|
|
|
|
crosshair.WriteToSaveGame(savefile);
|
|
savefile->Write(&screenBounds, sizeof(screenBounds));
|
|
|
|
savefile->Write(&levelCount, sizeof(levelCount));
|
|
for(int i = 0; i < levelCount; i++) {
|
|
savefile->Write(&(levelData[i]), sizeof(SSDLevelData_t));
|
|
savefile->Write(&(asteroidData[i]), sizeof(SSDAsteroidData_t));
|
|
savefile->Write(&(astronautData[i]), sizeof(SSDAstronautData_t));
|
|
savefile->Write(&(powerupData[i]), sizeof(SSDPowerupData_t));
|
|
}
|
|
|
|
savefile->Write(&weaponCount, sizeof(weaponCount));
|
|
for(int i = 0; i < weaponCount; i++) {
|
|
savefile->Write(&(weaponData[i]), sizeof(SSDWeaponData_t));
|
|
}
|
|
|
|
savefile->Write(&superBlasterTimeout, sizeof(superBlasterTimeout));
|
|
savefile->Write(&gameStats, sizeof(SSDGameStats_t));
|
|
|
|
//Write All Static Entities
|
|
SSDAsteroid::WriteAsteroids(savefile);
|
|
SSDAstronaut::WriteAstronauts(savefile);
|
|
SSDExplosion::WriteExplosions(savefile);
|
|
SSDPoints::WritePoints(savefile);
|
|
SSDProjectile::WriteProjectiles(savefile);
|
|
SSDPowerup::WritePowerups(savefile);
|
|
|
|
int entCount = entities.Num();
|
|
savefile->Write(&entCount, sizeof(entCount));
|
|
for(int i = 0; i < entCount; i++) {
|
|
savefile->Write(&(entities[i]->type), sizeof(entities[i]->type));
|
|
savefile->Write(&(entities[i]->id), sizeof(entities[i]->id));
|
|
}
|
|
}
|
|
|
|
void idGameSSDWindow::ReadFromSaveGame( idFile *savefile ) {
|
|
idWindow::ReadFromSaveGame(savefile);
|
|
|
|
|
|
savefile->Read(&ssdTime, sizeof(ssdTime));
|
|
|
|
beginLevel.ReadFromSaveGame(savefile);
|
|
resetGame.ReadFromSaveGame(savefile);
|
|
continueGame.ReadFromSaveGame(savefile);
|
|
refreshGuiData.ReadFromSaveGame(savefile);
|
|
|
|
crosshair.ReadFromSaveGame(savefile);
|
|
savefile->Read(&screenBounds, sizeof(screenBounds));
|
|
|
|
savefile->Read(&levelCount, sizeof(levelCount));
|
|
for(int i = 0; i < levelCount; i++) {
|
|
SSDLevelData_t newLevel;
|
|
savefile->Read(&newLevel, sizeof(SSDLevelData_t));
|
|
levelData.Append(newLevel);
|
|
|
|
SSDAsteroidData_t newAsteroid;
|
|
savefile->Read(&newAsteroid, sizeof(SSDAsteroidData_t));
|
|
asteroidData.Append(newAsteroid);
|
|
|
|
SSDAstronautData_t newAstronaut;
|
|
savefile->Read(&newAstronaut, sizeof(SSDAstronautData_t));
|
|
astronautData.Append(newAstronaut);
|
|
|
|
SSDPowerupData_t newPowerup;
|
|
savefile->Read(&newPowerup, sizeof(SSDPowerupData_t));
|
|
powerupData.Append(newPowerup);
|
|
}
|
|
|
|
savefile->Read(&weaponCount, sizeof(weaponCount));
|
|
for(int i = 0; i < weaponCount; i++) {
|
|
SSDWeaponData_t newWeapon;
|
|
savefile->Read(&newWeapon, sizeof(SSDWeaponData_t));
|
|
weaponData.Append(newWeapon);
|
|
}
|
|
|
|
savefile->Read(&superBlasterTimeout, sizeof(superBlasterTimeout));
|
|
|
|
savefile->Read(&gameStats, sizeof(SSDGameStats_t));
|
|
//Reset this because it is no longer valid
|
|
gameStats.levelStats.targetEnt = NULL;
|
|
|
|
SSDAsteroid::ReadAsteroids(savefile, this);
|
|
SSDAstronaut::ReadAstronauts(savefile, this);
|
|
SSDExplosion::ReadExplosions(savefile, this);
|
|
SSDPoints::ReadPoints(savefile, this);
|
|
SSDProjectile::ReadProjectiles(savefile, this);
|
|
SSDPowerup::ReadPowerups(savefile, this);
|
|
|
|
int entCount;
|
|
savefile->Read(&entCount, sizeof(entCount));
|
|
|
|
for(int i = 0; i < entCount; i++) {
|
|
int type, id;
|
|
savefile->Read(&type, sizeof(type));
|
|
savefile->Read(&id, sizeof(id));
|
|
|
|
SSDEntity* ent = GetSpecificEntity(type, id);
|
|
if(ent) {
|
|
entities.Append(ent);
|
|
}
|
|
}
|
|
}
|
|
|
|
const char *idGameSSDWindow::HandleEvent(const sysEvent_t *event, bool *updateVisuals) {
|
|
|
|
// need to call this to allow proper focus and capturing on embedded children
|
|
const char *ret = idWindow::HandleEvent(event, updateVisuals);
|
|
|
|
if(!gameStats.gameRunning) {
|
|
return ret;
|
|
}
|
|
|
|
int key = event->evValue;
|
|
|
|
if ( event->evType == SE_KEY ) {
|
|
|
|
if ( !event->evValue2 ) {
|
|
return ret;
|
|
}
|
|
|
|
if ( key == K_MOUSE1 || key == K_MOUSE2) {
|
|
FireWeapon(key);
|
|
} else {
|
|
return ret;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
idWinVar *idGameSSDWindow::GetWinVarByName (const char *_name, bool winLookup, drawWin_t** owner) {
|
|
|
|
idWinVar *retVar = NULL;
|
|
|
|
if (idStr::Icmp(_name, "beginLevel") == 0) {
|
|
retVar = &beginLevel;
|
|
}
|
|
|
|
if (idStr::Icmp(_name, "resetGame") == 0) {
|
|
retVar = &resetGame;
|
|
}
|
|
|
|
if (idStr::Icmp(_name, "continueGame") == 0) {
|
|
retVar = &continueGame;
|
|
}
|
|
if (idStr::Icmp(_name, "refreshGuiData") == 0) {
|
|
retVar = &refreshGuiData;
|
|
}
|
|
|
|
|
|
if(retVar) {
|
|
return retVar;
|
|
}
|
|
|
|
return idWindow::GetWinVarByName(_name, winLookup, owner);
|
|
}
|
|
|
|
|
|
void idGameSSDWindow::Draw(int time, float x, float y) {
|
|
|
|
//Update the game every frame before drawing
|
|
UpdateGame();
|
|
|
|
RefreshGuiData();
|
|
|
|
if(gameStats.gameRunning) {
|
|
|
|
ZOrderEntities();
|
|
|
|
//Draw from back to front
|
|
for(int i = entities.Num()-1; i >= 0; i--) {
|
|
entities[i]->Draw(dc);
|
|
}
|
|
|
|
//The last thing to draw is the crosshair
|
|
idVec2 cursor;
|
|
//GetCursor(cursor);
|
|
cursor.x = gui->CursorX();
|
|
cursor.y = gui->CursorY();
|
|
|
|
crosshair.Draw(dc, cursor);
|
|
}
|
|
}
|
|
|
|
|
|
bool idGameSSDWindow::ParseInternalVar(const char *_name, idParser *src) {
|
|
|
|
if (idStr::Icmp(_name, "beginLevel") == 0) {
|
|
beginLevel = src->ParseBool();
|
|
return true;
|
|
}
|
|
if (idStr::Icmp(_name, "resetGame") == 0) {
|
|
resetGame = src->ParseBool();
|
|
return true;
|
|
}
|
|
if (idStr::Icmp(_name, "continueGame") == 0) {
|
|
continueGame = src->ParseBool();
|
|
return true;
|
|
}
|
|
if (idStr::Icmp(_name, "refreshGuiData") == 0) {
|
|
refreshGuiData = src->ParseBool();
|
|
return true;
|
|
}
|
|
|
|
if(idStr::Icmp(_name, "levelcount") == 0) {
|
|
levelCount = src->ParseInt();
|
|
for(int i = 0; i < levelCount; i++) {
|
|
SSDLevelData_t newLevel;
|
|
memset(&newLevel, 0, sizeof(SSDLevelData_t));
|
|
levelData.Append(newLevel);
|
|
|
|
SSDAsteroidData_t newAsteroid;
|
|
memset(&newAsteroid, 0, sizeof(SSDAsteroidData_t));
|
|
asteroidData.Append(newAsteroid);
|
|
|
|
SSDAstronautData_t newAstronaut;
|
|
memset(&newAstronaut, 0, sizeof(SSDAstronautData_t));
|
|
astronautData.Append(newAstronaut);
|
|
|
|
SSDPowerupData_t newPowerup;
|
|
memset(&newPowerup, 0, sizeof(SSDPowerupData_t));
|
|
powerupData.Append(newPowerup);
|
|
|
|
|
|
}
|
|
return true;
|
|
}
|
|
if(idStr::Icmp(_name, "weaponCount") == 0) {
|
|
weaponCount = src->ParseInt();
|
|
for(int i = 0; i < weaponCount; i++) {
|
|
SSDWeaponData_t newWeapon;
|
|
memset(&newWeapon, 0, sizeof(SSDWeaponData_t));
|
|
weaponData.Append(newWeapon);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
if(idStr::FindText(_name, "leveldata", false) >= 0) {
|
|
idStr tempName = _name;
|
|
int level = atoi(tempName.Right(2))-1;
|
|
|
|
idStr levelData;
|
|
ParseString(src, levelData);
|
|
ParseLevelData(level, levelData);
|
|
return true;
|
|
}
|
|
|
|
if(idStr::FindText(_name, "asteroiddata", false) >= 0) {
|
|
idStr tempName = _name;
|
|
int level = atoi(tempName.Right(2))-1;
|
|
|
|
idStr asteroidData;
|
|
ParseString(src, asteroidData);
|
|
ParseAsteroidData(level, asteroidData);
|
|
return true;
|
|
}
|
|
|
|
if(idStr::FindText(_name, "weapondata", false) >= 0) {
|
|
idStr tempName = _name;
|
|
int weapon = atoi(tempName.Right(2))-1;
|
|
|
|
idStr weaponData;
|
|
ParseString(src, weaponData);
|
|
ParseWeaponData(weapon, weaponData);
|
|
return true;
|
|
}
|
|
|
|
if(idStr::FindText(_name, "astronautdata", false) >= 0) {
|
|
idStr tempName = _name;
|
|
int level = atoi(tempName.Right(2))-1;
|
|
|
|
idStr astronautData;
|
|
ParseString(src, astronautData);
|
|
ParseAstronautData(level, astronautData);
|
|
return true;
|
|
}
|
|
|
|
if(idStr::FindText(_name, "powerupdata", false) >= 0) {
|
|
idStr tempName = _name;
|
|
int level = atoi(tempName.Right(2))-1;
|
|
|
|
idStr powerupData;
|
|
ParseString(src, powerupData);
|
|
ParsePowerupData(level, powerupData);
|
|
return true;
|
|
}
|
|
|
|
return idWindow::ParseInternalVar(_name, src);
|
|
}
|
|
|
|
void idGameSSDWindow::ParseLevelData(int level, const idStr& levelDataString) {
|
|
|
|
idParser parser;
|
|
idToken token;
|
|
parser.LoadMemory(levelDataString.c_str(), levelDataString.Length(), "LevelData");
|
|
|
|
levelData[level].spawnBuffer = parser.ParseFloat();
|
|
levelData[level].needToWin = parser.ParseInt(); //Required Destroyed
|
|
|
|
}
|
|
|
|
void idGameSSDWindow::ParseAsteroidData(int level, const idStr& asteroidDataString) {
|
|
|
|
idParser parser;
|
|
idToken token;
|
|
parser.LoadMemory(asteroidDataString.c_str(), asteroidDataString.Length(), "AsteroidData");
|
|
|
|
asteroidData[level].speedMin = parser.ParseFloat(); //Speed Min
|
|
asteroidData[level].speedMax = parser.ParseFloat(); //Speed Max
|
|
|
|
asteroidData[level].sizeMin = parser.ParseFloat(); //Size Min
|
|
asteroidData[level].sizeMax = parser.ParseFloat(); //Size Max
|
|
|
|
asteroidData[level].rotateMin = parser.ParseFloat(); //Rotate Min (rotations per second)
|
|
asteroidData[level].rotateMax = parser.ParseFloat(); //Rotate Max (rotations per second)
|
|
|
|
asteroidData[level].spawnMin = parser.ParseInt(); //Spawn Min
|
|
asteroidData[level].spawnMax = parser.ParseInt(); //Spawn Max
|
|
|
|
asteroidData[level].asteroidHealth = parser.ParseInt(); //Health of the asteroid
|
|
asteroidData[level].asteroidDamage = parser.ParseInt(); //Asteroid Damage
|
|
asteroidData[level].asteroidPoints = parser.ParseInt(); //Points awarded for destruction
|
|
}
|
|
|
|
void idGameSSDWindow::ParsePowerupData(int level, const idStr& powerupDataString) {
|
|
|
|
idParser parser;
|
|
idToken token;
|
|
parser.LoadMemory(powerupDataString.c_str(), powerupDataString.Length(), "PowerupData");
|
|
|
|
powerupData[level].speedMin = parser.ParseFloat(); //Speed Min
|
|
powerupData[level].speedMax = parser.ParseFloat(); //Speed Max
|
|
|
|
powerupData[level].rotateMin = parser.ParseFloat(); //Rotate Min (rotations per second)
|
|
powerupData[level].rotateMax = parser.ParseFloat(); //Rotate Max (rotations per second)
|
|
|
|
powerupData[level].spawnMin = parser.ParseInt(); //Spawn Min
|
|
powerupData[level].spawnMax = parser.ParseInt(); //Spawn Max
|
|
|
|
}
|
|
|
|
void idGameSSDWindow::ParseWeaponData(int weapon, const idStr& weaponDataString) {
|
|
|
|
idParser parser;
|
|
idToken token;
|
|
parser.LoadMemory(weaponDataString.c_str(), weaponDataString.Length(), "WeaponData");
|
|
|
|
weaponData[weapon].speed = parser.ParseFloat();
|
|
weaponData[weapon].damage = parser.ParseFloat();
|
|
weaponData[weapon].size = parser.ParseFloat();
|
|
}
|
|
|
|
void idGameSSDWindow::ParseAstronautData(int level, const idStr& astronautDataString) {
|
|
|
|
idParser parser;
|
|
idToken token;
|
|
parser.LoadMemory(astronautDataString.c_str(), astronautDataString.Length(), "AstronautData");
|
|
|
|
astronautData[level].speedMin = parser.ParseFloat(); //Speed Min
|
|
astronautData[level].speedMax = parser.ParseFloat(); //Speed Max
|
|
|
|
astronautData[level].rotateMin = parser.ParseFloat(); //Rotate Min (rotations per second)
|
|
astronautData[level].rotateMax = parser.ParseFloat(); //Rotate Max (rotations per second)
|
|
|
|
astronautData[level].spawnMin = parser.ParseInt(); //Spawn Min
|
|
astronautData[level].spawnMax = parser.ParseInt(); //Spawn Max
|
|
|
|
astronautData[level].health = parser.ParseInt(); //Health of the asteroid
|
|
astronautData[level].points = parser.ParseInt(); //Asteroid Damage
|
|
astronautData[level].penalty = parser.ParseInt(); //Points awarded for destruction
|
|
}
|
|
|
|
void idGameSSDWindow::CommonInit() {
|
|
crosshair.InitCrosshairs();
|
|
|
|
|
|
beginLevel = false;
|
|
resetGame = false;
|
|
continueGame = false;
|
|
refreshGuiData = false;
|
|
|
|
ssdTime = 0;
|
|
levelCount = 0;
|
|
weaponCount = 0;
|
|
screenBounds = idBounds(idVec3(-320,-240,0), idVec3(320,240,0));
|
|
|
|
superBlasterTimeout = 0;
|
|
|
|
currentSound = 0;
|
|
|
|
//Precahce all assets that are loaded dynamically
|
|
declManager->FindMaterial(ASTEROID_MATERIAL);
|
|
declManager->FindMaterial(ASTRONAUT_MATERIAL);
|
|
|
|
for(int i = 0; i < EXPLOSION_MATERIAL_COUNT; i++) {
|
|
declManager->FindMaterial(explosionMaterials[i]);
|
|
}
|
|
declManager->FindMaterial(PROJECTILE_MATERIAL);
|
|
for(int i = 0; i < POWERUP_MATERIAL_COUNT; i++) {
|
|
declManager->FindMaterial(powerupMaterials[i][0]);
|
|
declManager->FindMaterial(powerupMaterials[i][1]);
|
|
}
|
|
|
|
// Precache sounds
|
|
declManager->FindSound( "arcade_blaster" );
|
|
declManager->FindSound( "arcade_capture " );
|
|
declManager->FindSound( "arcade_explode" );
|
|
|
|
ResetGameStats();
|
|
}
|
|
|
|
void idGameSSDWindow::ResetGameStats() {
|
|
|
|
ResetEntities();
|
|
|
|
//Reset the gamestats structure
|
|
memset(&gameStats, 0, sizeof(gameStats));
|
|
|
|
gameStats.health = 100;
|
|
|
|
}
|
|
|
|
void idGameSSDWindow::ResetLevelStats() {
|
|
|
|
ResetEntities();
|
|
|
|
//Reset the level statistics structure
|
|
memset(&gameStats.levelStats, 0, sizeof(gameStats.levelStats));
|
|
|
|
|
|
}
|
|
|
|
void idGameSSDWindow::ResetEntities() {
|
|
//Destroy all of the entities
|
|
for(int i = 0; i < entities.Num(); i++) {
|
|
entities[i]->DestroyEntity();
|
|
}
|
|
entities.Clear();
|
|
}
|
|
|
|
void idGameSSDWindow::StartGame() {
|
|
|
|
gameStats.gameRunning = true;
|
|
}
|
|
|
|
void idGameSSDWindow::StopGame() {
|
|
|
|
gameStats.gameRunning = false;
|
|
}
|
|
|
|
void idGameSSDWindow::GameOver() {
|
|
|
|
|
|
StopGame();
|
|
|
|
gui->HandleNamedEvent("gameOver");
|
|
}
|
|
|
|
void idGameSSDWindow::BeginLevel(int level) {
|
|
|
|
ResetLevelStats();
|
|
|
|
gameStats.currentLevel = level;
|
|
|
|
StartGame();
|
|
}
|
|
|
|
/**
|
|
* Continue game resets the players health
|
|
*/
|
|
void idGameSSDWindow::ContinueGame() {
|
|
gameStats.health = 100;
|
|
|
|
StartGame();
|
|
}
|
|
|
|
void idGameSSDWindow::LevelComplete() {
|
|
|
|
gameStats.prebonusscore = gameStats.score;
|
|
|
|
// Add the bonuses
|
|
int accuracy;
|
|
if( !gameStats.levelStats.shotCount ) {
|
|
accuracy = 0;
|
|
} else {
|
|
accuracy = (int)( ( (float)gameStats.levelStats.hitCount / (float)gameStats.levelStats.shotCount ) * 100.0f );
|
|
}
|
|
int accuracyPoints = Max( 0, accuracy - 50 ) * 20;
|
|
|
|
gui->SetStateString("player_accuracy_score", va("%i", accuracyPoints));
|
|
|
|
gameStats.score += accuracyPoints;
|
|
|
|
int saveAccuracy;
|
|
int totalAst = gameStats.levelStats.savedAstronauts + gameStats.levelStats.killedAstronauts;
|
|
if( !totalAst ) {
|
|
saveAccuracy = 0;
|
|
} else {
|
|
saveAccuracy = (int)( ( (float)gameStats.levelStats.savedAstronauts / (float)totalAst ) * 100.0f );
|
|
}
|
|
accuracyPoints = Max( 0, saveAccuracy - 50 ) * 20;
|
|
|
|
gui->SetStateString("save_accuracy_score", va("%i", accuracyPoints));
|
|
|
|
gameStats.score += accuracyPoints;
|
|
|
|
|
|
|
|
StopSuperBlaster();
|
|
|
|
gameStats.nextLevel++;
|
|
|
|
if(gameStats.nextLevel >= levelCount) {
|
|
//Have they beaten the game
|
|
GameComplete();
|
|
} else {
|
|
|
|
//Make sure we don't go above the levelcount
|
|
//min(gameStats.nextLevel, levelCount-1);
|
|
|
|
StopGame();
|
|
gui->HandleNamedEvent("levelComplete");
|
|
}
|
|
}
|
|
|
|
void idGameSSDWindow::GameComplete() {
|
|
StopGame();
|
|
gui->HandleNamedEvent("gameComplete");
|
|
}
|
|
|
|
|
|
void idGameSSDWindow::UpdateGame() {
|
|
|
|
//Check to see if and functions where called by the gui
|
|
if(beginLevel == true) {
|
|
beginLevel = false;
|
|
BeginLevel(gameStats.nextLevel);
|
|
}
|
|
if(resetGame == true) {
|
|
resetGame = false;
|
|
ResetGameStats();
|
|
}
|
|
if(continueGame == true) {
|
|
continueGame = false;
|
|
ContinueGame();
|
|
}
|
|
if(refreshGuiData == true) {
|
|
refreshGuiData = false;
|
|
RefreshGuiData();
|
|
}
|
|
|
|
if(gameStats.gameRunning) {
|
|
|
|
//We assume an upate every 16 milliseconds
|
|
ssdTime += 16;
|
|
|
|
if(superBlasterTimeout && ssdTime > superBlasterTimeout) {
|
|
StopSuperBlaster();
|
|
}
|
|
|
|
//Find if we are targeting and enemy
|
|
idVec2 cursor;
|
|
//GetCursor(cursor);
|
|
cursor.x = gui->CursorX();
|
|
cursor.y = gui->CursorY();
|
|
gameStats.levelStats.targetEnt = EntityHitTest(cursor);
|
|
|
|
//Update from back to front
|
|
for(int i = entities.Num()-1; i >= 0; i--) {
|
|
entities[i]->Update();
|
|
}
|
|
|
|
CheckForHits();
|
|
|
|
//Delete entities that need to be deleted
|
|
for(int i = entities.Num()-1; i >= 0; i--) {
|
|
if(entities[i]->destroyed) {
|
|
SSDEntity* ent = entities[i];
|
|
ent->DestroyEntity();
|
|
entities.RemoveIndex(i);
|
|
}
|
|
}
|
|
|
|
//Check if we can spawn an asteroid
|
|
SpawnAsteroid();
|
|
|
|
//Check if we should spawn an astronaut
|
|
SpawnAstronaut();
|
|
|
|
//Check if we should spawn an asteroid
|
|
SpawnPowerup();
|
|
}
|
|
}
|
|
|
|
void idGameSSDWindow::CheckForHits() {
|
|
|
|
//See if the entity has gotten close enough
|
|
for(int i = 0; i < entities.Num(); i++) {
|
|
SSDEntity* ent = entities[i];
|
|
if(ent->position.z <= Z_NEAR) {
|
|
|
|
if(!ent->noPlayerDamage) {
|
|
|
|
//Is the object still in the screen
|
|
idVec3 entPos = ent->position;
|
|
entPos.z = 0;
|
|
|
|
idBounds entBounds(entPos);
|
|
entBounds.ExpandSelf(ent->hitRadius);
|
|
|
|
if(screenBounds.IntersectsBounds(entBounds)) {
|
|
|
|
ent->OnStrikePlayer();
|
|
|
|
//The entity hit the player figure out what is was and act appropriately
|
|
if(ent->type == SSD_ENTITY_ASTEROID) {
|
|
AsteroidStruckPlayer(static_cast<SSDAsteroid*>(ent));
|
|
} else if(ent->type == SSD_ENTITY_ASTRONAUT) {
|
|
AstronautStruckPlayer(static_cast<SSDAstronaut*>(ent));
|
|
}
|
|
} else {
|
|
//Tag for removal later in the frame
|
|
ent->destroyed = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void idGameSSDWindow::ZOrderEntities() {
|
|
//Z-Order the entities
|
|
//Using a simple sorting method
|
|
for (int i = entities.Num()-1; i >= 0; i--) {
|
|
bool flipped = false;
|
|
for (int j = 0; j<i ; j++) {
|
|
if (entities[j]->position.z > entities[j+1]->position.z) {
|
|
SSDEntity* ent = entities[j];
|
|
entities[j] = entities[j+1];
|
|
entities[j+1] = ent;
|
|
flipped = true;
|
|
}
|
|
}
|
|
if (!flipped) {
|
|
//Jump out because it is sorted
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void idGameSSDWindow::SpawnAsteroid() {
|
|
|
|
int currentTime = ssdTime;
|
|
|
|
if(currentTime < gameStats.levelStats.nextAsteroidSpawnTime) {
|
|
//Not time yet
|
|
return;
|
|
}
|
|
|
|
//Lets spawn it
|
|
idVec3 startPosition;
|
|
|
|
float spawnBuffer = levelData[gameStats.currentLevel].spawnBuffer*2.0f;
|
|
startPosition.x = random.RandomInt(V_WIDTH+spawnBuffer)-((V_WIDTH/2.0f)+spawnBuffer);
|
|
startPosition.y = random.RandomInt(V_HEIGHT+spawnBuffer)-((V_HEIGHT/2.0f)+spawnBuffer);
|
|
startPosition.z = ENTITY_START_DIST;
|
|
|
|
float speed = random.RandomInt(asteroidData[gameStats.currentLevel].speedMax - asteroidData[gameStats.currentLevel].speedMin) + asteroidData[gameStats.currentLevel].speedMin;
|
|
float size = random.RandomInt(asteroidData[gameStats.currentLevel].sizeMax - asteroidData[gameStats.currentLevel].sizeMin) + asteroidData[gameStats.currentLevel].sizeMin;
|
|
float rotate = (random.RandomFloat() * (asteroidData[gameStats.currentLevel].rotateMax - asteroidData[gameStats.currentLevel].rotateMin)) + asteroidData[gameStats.currentLevel].rotateMin;
|
|
|
|
SSDAsteroid* asteroid = SSDAsteroid::GetNewAsteroid(this, startPosition, idVec2(size, size), speed, rotate, asteroidData[gameStats.currentLevel].asteroidHealth);
|
|
entities.Append(asteroid);
|
|
|
|
gameStats.levelStats.nextAsteroidSpawnTime = currentTime + random.RandomInt(asteroidData[gameStats.currentLevel].spawnMax - asteroidData[gameStats.currentLevel].spawnMin) + asteroidData[gameStats.currentLevel].spawnMin;
|
|
}
|
|
|
|
void idGameSSDWindow::FireWeapon(int key) {
|
|
|
|
idVec2 cursorWorld = GetCursorWorld();
|
|
idVec2 cursor;
|
|
//GetCursor(cursor);
|
|
cursor.x = gui->CursorX();
|
|
cursor.y = gui->CursorY();
|
|
|
|
if(key == K_MOUSE1) {
|
|
|
|
gameStats.levelStats.shotCount++;
|
|
|
|
if(gameStats.levelStats.targetEnt) {
|
|
//Aim the projectile from the bottom of the screen directly at the ent
|
|
//SSDProjectile* newProj = new SSDProjectile(this, idVec3(320,0,0), gameStats.levelStats.targetEnt->position, weaponData[gameStats.currentWeapon].speed, weaponData[gameStats.currentWeapon].size);
|
|
SSDProjectile* newProj = SSDProjectile::GetNewProjectile(this, idVec3(0,-180,0), gameStats.levelStats.targetEnt->position, weaponData[gameStats.currentWeapon].speed, weaponData[gameStats.currentWeapon].size);
|
|
entities.Append(newProj);
|
|
//newProj = SSDProjectile::GetNewProjectile(this, idVec3(-320,-0,0), gameStats.levelStats.targetEnt->position, weaponData[gameStats.currentWeapon].speed, weaponData[gameStats.currentWeapon].size);
|
|
//entities.Append(newProj);
|
|
|
|
//We hit something
|
|
gameStats.levelStats.hitCount++;
|
|
|
|
gameStats.levelStats.targetEnt->OnHit(key);
|
|
|
|
if(gameStats.levelStats.targetEnt->type == SSD_ENTITY_ASTEROID) {
|
|
HitAsteroid(static_cast<SSDAsteroid*>(gameStats.levelStats.targetEnt), key);
|
|
} else if(gameStats.levelStats.targetEnt->type == SSD_ENTITY_ASTRONAUT) {
|
|
HitAstronaut(static_cast<SSDAstronaut*>(gameStats.levelStats.targetEnt), key);
|
|
} else if(gameStats.levelStats.targetEnt->type == SSD_ENTITY_ASTRONAUT) {
|
|
|
|
}
|
|
} else {
|
|
////Aim the projectile at the cursor position all the way to the far clipping
|
|
//SSDProjectile* newProj = SSDProjectile::GetNewProjectile(this, idVec3(0,-180,0), idVec3(cursorWorld.x, cursorWorld.y, (Z_FAR-Z_NEAR)/2.0f), weaponData[gameStats.currentWeapon].speed, weaponData[gameStats.currentWeapon].size);
|
|
|
|
//Aim the projectile so it crosses the cursor 1/4 of screen
|
|
idVec3 vec = idVec3(cursorWorld.x, cursorWorld.y, (Z_FAR-Z_NEAR)/8.0f);
|
|
vec *= 8;
|
|
SSDProjectile* newProj = SSDProjectile::GetNewProjectile(this, idVec3(0,-180,0), vec, weaponData[gameStats.currentWeapon].speed, weaponData[gameStats.currentWeapon].size);
|
|
entities.Append(newProj);
|
|
|
|
}
|
|
|
|
|
|
//Play the blaster sound
|
|
PlaySound("arcade_blaster");
|
|
|
|
} /*else if (key == K_MOUSE2) {
|
|
if(gameStats.levelStats.targetEnt) {
|
|
if(gameStats.levelStats.targetEnt->type == SSD_ENTITY_ASTRONAUT) {
|
|
HitAstronaut(static_cast<SSDAstronaut*>(gameStats.levelStats.targetEnt), key);
|
|
}
|
|
}
|
|
}*/
|
|
}
|
|
|
|
SSDEntity* idGameSSDWindow::EntityHitTest(const idVec2& pt) {
|
|
|
|
for(int i = 0; i < entities.Num(); i++) {
|
|
//Since we ZOrder the entities every frame we can stop at the first entity we hit.
|
|
//ToDo: Make sure this assumption is true
|
|
if(entities[i]->HitTest(pt)) {
|
|
return entities[i];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void idGameSSDWindow::HitAsteroid(SSDAsteroid* asteroid, int key) {
|
|
|
|
|
|
|
|
asteroid->health -= weaponData[gameStats.currentWeapon].damage;
|
|
|
|
if(asteroid->health <= 0) {
|
|
|
|
//The asteroid has been destroyed
|
|
SSDExplosion* explosion = SSDExplosion::GetNewExplosion(this, asteroid->position, asteroid->size*2, 300, SSDExplosion::EXPLOSION_NORMAL, asteroid);
|
|
entities.Append(explosion);
|
|
PlaySound("arcade_explode");
|
|
|
|
AddScore(asteroid, asteroidData[gameStats.currentLevel].asteroidPoints);
|
|
|
|
//Don't let the player hit it anymore because
|
|
asteroid->noHit = true;
|
|
|
|
gameStats.levelStats.destroyedAsteroids++;
|
|
//if(gameStats.levelStats.destroyedAsteroids >= levelData[gameStats.currentLevel].needToWin) {
|
|
// LevelComplete();
|
|
//}
|
|
|
|
} else {
|
|
//This was a damage hit so create a real small quick explosion
|
|
SSDExplosion* explosion = SSDExplosion::GetNewExplosion(this, asteroid->position, asteroid->size/2.0f, 200, SSDExplosion::EXPLOSION_NORMAL, asteroid, false, false);
|
|
entities.Append(explosion);
|
|
}
|
|
}
|
|
|
|
void idGameSSDWindow::AsteroidStruckPlayer(SSDAsteroid* asteroid) {
|
|
|
|
asteroid->noPlayerDamage = true;
|
|
asteroid->noHit = true;
|
|
|
|
AddDamage(asteroidData[gameStats.currentLevel].asteroidDamage);
|
|
|
|
SSDExplosion* explosion = SSDExplosion::GetNewExplosion(this, asteroid->position, asteroid->size*2, 300, SSDExplosion::EXPLOSION_NORMAL, asteroid);
|
|
entities.Append(explosion);
|
|
PlaySound("arcade_explode");
|
|
}
|
|
|
|
void idGameSSDWindow::AddScore(SSDEntity* ent, int points) {
|
|
|
|
SSDPoints* pointsEnt;
|
|
|
|
if(points > 0) {
|
|
pointsEnt = SSDPoints::GetNewPoints(this, ent, points, 1000, 50, idVec4(0,1,0,1));
|
|
} else {
|
|
pointsEnt = SSDPoints::GetNewPoints(this, ent, points, 1000, 50, idVec4(1,0,0,1));
|
|
}
|
|
entities.Append(pointsEnt);
|
|
|
|
gameStats.score += points;
|
|
gui->SetStateString( "player_score", va("%i", gameStats.score ) );
|
|
}
|
|
|
|
void idGameSSDWindow::AddDamage(int damage) {
|
|
gameStats.health -= damage;
|
|
gui->SetStateString( "player_health", va("%i", gameStats.health ) );
|
|
|
|
gui->HandleNamedEvent( "playerDamage" );
|
|
|
|
if(gameStats.health <= 0) {
|
|
//The player is dead
|
|
GameOver();
|
|
}
|
|
}
|
|
|
|
void idGameSSDWindow::AddHealth(int health) {
|
|
gameStats.health += health;
|
|
gameStats.health = Min( 100, gameStats.health );
|
|
}
|
|
|
|
|
|
void idGameSSDWindow::OnNuke() {
|
|
|
|
gui->HandleNamedEvent("nuke");
|
|
|
|
//Destory All Asteroids
|
|
for(int i = 0 ; i < entities.Num(); i++) {
|
|
|
|
if(entities[i]->type == SSD_ENTITY_ASTEROID) {
|
|
|
|
//The asteroid has been destroyed
|
|
SSDExplosion* explosion = SSDExplosion::GetNewExplosion(this, entities[i]->position, entities[i]->size*2, 300, SSDExplosion::EXPLOSION_NORMAL, entities[i]);
|
|
entities.Append(explosion);
|
|
|
|
AddScore(entities[i], asteroidData[gameStats.currentLevel].asteroidPoints);
|
|
|
|
//Don't let the player hit it anymore because
|
|
entities[i]->noHit = true;
|
|
|
|
gameStats.levelStats.destroyedAsteroids++;
|
|
}
|
|
}
|
|
PlaySound("arcade_explode");
|
|
|
|
//Check to see if a nuke ends the level
|
|
/*if(gameStats.levelStats.destroyedAsteroids >= levelData[gameStats.currentLevel].needToWin) {
|
|
LevelComplete();
|
|
|
|
}*/
|
|
}
|
|
|
|
void idGameSSDWindow::OnRescueAll() {
|
|
|
|
gui->HandleNamedEvent("rescueAll");
|
|
|
|
//Rescue All Astronauts
|
|
for(int i = 0 ; i < entities.Num(); i++) {
|
|
|
|
if(entities[i]->type == SSD_ENTITY_ASTRONAUT) {
|
|
|
|
AstronautStruckPlayer((SSDAstronaut*)entities[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void idGameSSDWindow::OnSuperBlaster() {
|
|
|
|
StartSuperBlaster();
|
|
}
|
|
|
|
|
|
|
|
void idGameSSDWindow::RefreshGuiData() {
|
|
|
|
|
|
gui->SetStateString("nextLevel", va("%i", gameStats.nextLevel+1));
|
|
gui->SetStateString("currentLevel", va("%i", gameStats.currentLevel+1));
|
|
|
|
float accuracy;
|
|
if(!gameStats.levelStats.shotCount) {
|
|
accuracy = 0;
|
|
} else {
|
|
accuracy = ((float)gameStats.levelStats.hitCount/(float)gameStats.levelStats.shotCount)*100.0f;
|
|
}
|
|
gui->SetStateString( "player_accuracy", va("%d%%", (int)accuracy));
|
|
|
|
float saveAccuracy;
|
|
int totalAst = gameStats.levelStats.savedAstronauts + gameStats.levelStats.killedAstronauts;
|
|
|
|
if(!totalAst) {
|
|
saveAccuracy = 0;
|
|
} else {
|
|
saveAccuracy = ((float)gameStats.levelStats.savedAstronauts/(float)totalAst)*100.0f;
|
|
}
|
|
gui->SetStateString( "save_accuracy", va("%d%%", (int)saveAccuracy));
|
|
|
|
|
|
|
|
|
|
if(gameStats.levelStats.targetEnt) {
|
|
int dist = (gameStats.levelStats.targetEnt->position.z/100.0f);
|
|
dist *= 100;
|
|
gui->SetStateString("target_info", va("%i meters", dist));
|
|
} else {
|
|
gui->SetStateString("target_info", "No Target");
|
|
}
|
|
|
|
gui->SetStateString( "player_health", va("%i", gameStats.health ) );
|
|
gui->SetStateString( "player_score", va("%i", gameStats.score ) );
|
|
gui->SetStateString( "player_prebonusscore", va("%i", gameStats.prebonusscore ) );
|
|
gui->SetStateString( "level_complete", va("%i/%i", gameStats.levelStats.savedAstronauts, levelData[gameStats.currentLevel].needToWin ));
|
|
|
|
|
|
if(superBlasterTimeout) {
|
|
float timeRemaining = (superBlasterTimeout - ssdTime)/1000.0f;
|
|
gui->SetStateString("super_blaster_time", va("%.2f", timeRemaining));
|
|
}
|
|
}
|
|
|
|
idVec2 idGameSSDWindow::GetCursorWorld() {
|
|
|
|
idVec2 cursor;
|
|
//GetCursor(cursor);
|
|
cursor.x = gui->CursorX();
|
|
cursor.y = gui->CursorY();
|
|
cursor.x = cursor.x - 0.5f * V_WIDTH;
|
|
cursor.y = -(cursor.y - 0.5f * V_HEIGHT);
|
|
return cursor;
|
|
}
|
|
|
|
void idGameSSDWindow::SpawnAstronaut() {
|
|
|
|
int currentTime = ssdTime;
|
|
|
|
if(currentTime < gameStats.levelStats.nextAstronautSpawnTime) {
|
|
//Not time yet
|
|
return;
|
|
}
|
|
|
|
//Lets spawn it
|
|
idVec3 startPosition;
|
|
|
|
startPosition.x = random.RandomInt(V_WIDTH)-(V_WIDTH/2.0f);
|
|
startPosition.y = random.RandomInt(V_HEIGHT)-(V_HEIGHT/2.0f);
|
|
startPosition.z = ENTITY_START_DIST;
|
|
|
|
float speed = random.RandomInt(astronautData[gameStats.currentLevel].speedMax - astronautData[gameStats.currentLevel].speedMin) + astronautData[gameStats.currentLevel].speedMin;
|
|
float rotate = (random.RandomFloat() * (astronautData[gameStats.currentLevel].rotateMax - astronautData[gameStats.currentLevel].rotateMin)) + astronautData[gameStats.currentLevel].rotateMin;
|
|
|
|
SSDAstronaut* astronaut = SSDAstronaut::GetNewAstronaut(this, startPosition, speed, rotate, astronautData[gameStats.currentLevel].health);
|
|
entities.Append(astronaut);
|
|
|
|
gameStats.levelStats.nextAstronautSpawnTime = currentTime + random.RandomInt(astronautData[gameStats.currentLevel].spawnMax - astronautData[gameStats.currentLevel].spawnMin) + astronautData[gameStats.currentLevel].spawnMin;
|
|
}
|
|
|
|
void idGameSSDWindow::HitAstronaut(SSDAstronaut* astronaut, int key) {
|
|
|
|
|
|
if(key == K_MOUSE1) {
|
|
astronaut->health -= weaponData[gameStats.currentWeapon].damage;
|
|
|
|
if(astronaut->health <= 0) {
|
|
|
|
gameStats.levelStats.killedAstronauts++;
|
|
|
|
//The astronaut has been destroyed
|
|
SSDExplosion* explosion = SSDExplosion::GetNewExplosion(this, astronaut->position, astronaut->size*2, 300, SSDExplosion::EXPLOSION_NORMAL, astronaut);
|
|
entities.Append(explosion);
|
|
PlaySound("arcade_explode");
|
|
|
|
//Add the penalty for killing the astronaut
|
|
AddScore(astronaut, astronautData[gameStats.currentLevel].penalty);
|
|
|
|
//Don't let the player hit it anymore
|
|
astronaut->noHit = true;
|
|
} else {
|
|
//This was a damage hit so create a real small quick explosion
|
|
SSDExplosion* explosion = SSDExplosion::GetNewExplosion(this, astronaut->position, astronaut->size/2.0f, 200, SSDExplosion::EXPLOSION_NORMAL, astronaut, false, false);
|
|
entities.Append(explosion);
|
|
}
|
|
}
|
|
}
|
|
|
|
void idGameSSDWindow::AstronautStruckPlayer(SSDAstronaut* astronaut) {
|
|
|
|
gameStats.levelStats.savedAstronauts++;
|
|
|
|
astronaut->noPlayerDamage = true;
|
|
astronaut->noHit = true;
|
|
|
|
//We are saving an astronaut
|
|
SSDExplosion* explosion = SSDExplosion::GetNewExplosion(this, astronaut->position, astronaut->size*2, 300, SSDExplosion::EXPLOSION_TELEPORT, astronaut);
|
|
entities.Append(explosion);
|
|
PlaySound("arcade_capture");
|
|
|
|
//Give the player points for saving the astronaut
|
|
AddScore(astronaut, astronautData[gameStats.currentLevel].points);
|
|
|
|
if(gameStats.levelStats.savedAstronauts >= levelData[gameStats.currentLevel].needToWin) {
|
|
LevelComplete();
|
|
}
|
|
|
|
}
|
|
|
|
void idGameSSDWindow::SpawnPowerup() {
|
|
|
|
int currentTime = ssdTime;
|
|
|
|
if(currentTime < gameStats.levelStats.nextPowerupSpawnTime) {
|
|
//Not time yet
|
|
return;
|
|
}
|
|
|
|
float speed = random.RandomInt(powerupData[gameStats.currentLevel].speedMax - powerupData[gameStats.currentLevel].speedMin) + powerupData[gameStats.currentLevel].speedMin;
|
|
float rotate = (random.RandomFloat() * (powerupData[gameStats.currentLevel].rotateMax - powerupData[gameStats.currentLevel].rotateMin)) + powerupData[gameStats.currentLevel].rotateMin;
|
|
|
|
SSDPowerup* powerup = SSDPowerup::GetNewPowerup(this, speed, rotate);
|
|
entities.Append(powerup);
|
|
|
|
gameStats.levelStats.nextPowerupSpawnTime = currentTime + random.RandomInt(powerupData[gameStats.currentLevel].spawnMax - powerupData[gameStats.currentLevel].spawnMin) + powerupData[gameStats.currentLevel].spawnMin;
|
|
|
|
}
|
|
|
|
void idGameSSDWindow::StartSuperBlaster() {
|
|
|
|
gui->HandleNamedEvent("startSuperBlaster");
|
|
gameStats.currentWeapon = 1;
|
|
superBlasterTimeout = ssdTime + 10000;
|
|
|
|
}
|
|
void idGameSSDWindow::StopSuperBlaster() {
|
|
gui->HandleNamedEvent("stopSuperBlaster");
|
|
gameStats.currentWeapon = 0;
|
|
superBlasterTimeout = 0;
|
|
|
|
}
|
|
|
|
SSDEntity* idGameSSDWindow::GetSpecificEntity(int type, int id) {
|
|
SSDEntity* ent = NULL;
|
|
switch(type) {
|
|
case SSD_ENTITY_ASTEROID:
|
|
ent = SSDAsteroid::GetSpecificAsteroid(id);
|
|
break;
|
|
case SSD_ENTITY_ASTRONAUT:
|
|
ent = SSDAstronaut::GetSpecificAstronaut(id);
|
|
break;
|
|
case SSD_ENTITY_EXPLOSION:
|
|
ent = SSDExplosion::GetSpecificExplosion(id);
|
|
break;
|
|
case SSD_ENTITY_POINTS:
|
|
ent = SSDPoints::GetSpecificPoints(id);
|
|
break;
|
|
case SSD_ENTITY_PROJECTILE:
|
|
ent = SSDProjectile::GetSpecificProjectile(id);
|
|
break;
|
|
case SSD_ENTITY_POWERUP:
|
|
ent = SSDPowerup::GetSpecificPowerup(id);
|
|
break;
|
|
}
|
|
return ent;
|
|
}
|
|
|
|
#define MAX_SOUND_CHANNEL 8
|
|
|
|
void idGameSSDWindow::PlaySound(const char* sound) {
|
|
|
|
session->sw->PlayShaderDirectly(sound, currentSound);
|
|
|
|
currentSound++;
|
|
if(currentSound >= MAX_SOUND_CHANNEL) {
|
|
currentSound = 0;
|
|
}
|
|
}
|