mirror of
https://github.com/id-Software/DOOM-3-BFG.git
synced 2024-11-23 12:32:49 +00:00
2289 lines
60 KiB
C++
2289 lines
60 KiB
C++
/*
|
|
===========================================================================
|
|
|
|
Doom 3 BFG Edition GPL Source Code
|
|
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
|
|
|
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
|
|
|
Doom 3 BFG Edition 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 BFG Edition 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 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
In addition, the Doom 3 BFG Edition 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 BFG Edition 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.
|
|
|
|
===========================================================================
|
|
*/
|
|
#pragma hdrstop
|
|
#include "../idlib/precompiled.h"
|
|
|
|
#include "DeviceContext.h"
|
|
#include "Window.h"
|
|
#include "UserInterfaceLocal.h"
|
|
#include "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(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() {
|
|
|
|
|
|
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);
|
|
|
|
idVec3 center = screenBounds.GetCenter();
|
|
|
|
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 += dc->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(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();
|
|
}
|
|
|
|
//The last thing to draw is the crosshair
|
|
idVec2 cursor;
|
|
//GetCursor(cursor);
|
|
cursor.x = gui->CursorX();
|
|
cursor.y = gui->CursorY();
|
|
|
|
crosshair.Draw(cursor);
|
|
}
|
|
}
|
|
|
|
|
|
bool idGameSSDWindow::ParseInternalVar(const char *_name, idTokenParser *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 (TAG_OLD_UI) 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 {
|
|
////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) {
|
|
|
|
common->SW()->PlayShaderDirectly(sound, currentSound);
|
|
|
|
currentSound++;
|
|
if(currentSound >= MAX_SOUND_CHANNEL) {
|
|
currentSound = 0;
|
|
}
|
|
}
|