/******************************************************************************
This source file is part of AstroMenace game
(Hardcore 3D space shooter with spaceship upgrade possibilities.)
For the latest info, see http://www.viewizard.com/
File name: Game.cpp
Copyright (c) 2006-2007 Michael Kurinnoy, Viewizard
All Rights Reserved.
File Version: 1.2
******************************************************************************
AstroMenace game source code available under "dual licensing" model.
The licensing options available are:
* Commercial Licensing. This is the appropriate option if you are
creating proprietary applications and you are not prepared to
distribute and share the source code of your application.
Contact us for pricing at viewizard@viewizard.com
* Open Source Licensing. This is the appropriate option if you want
to share the source code of your application with everyone you
distribute it to, and you also want to give them the right to share
who uses it. You should have received a copy of the GNU General Public
License version 3 with this source codes.
If not, see .
******************************************************************************/
#include "../Game.h"
#include "../Defines.h"
ScriptEngine *Script = 0;
extern eParticleSystem *psSpace;
// замедление снарядов NPC ... 1-3...
int GameNPCWeaponPenalty = 1;
// ум. защиты NPC объектов
int GameNPCArmorPenalty = 1;
// "замедление" наведения NPC ... 1-4
int GameNPCTargetingSpeedPenalty = 1;
// 0-ограничено, 1-нет
int GameLimitedAmmo = 0;
// 0-может быть уничтожено, 1-нет
int GameDestroyableWeapon = 0;
// 1-аркада, 0-симулятор
int GameWeaponTargetingMode = 0;
// 1-аркада, 0-симулятор
int GameSpaceShipControlMode = 0;
int GameEngineSystem = 1;
int GameTargetingSystem = 1;
int GameAdvancedProtectionSystem = 0;
int GamePowerSystem = 1;
int GameTargetingMechanicSystem = 1;
// присваиваем в профайл только по завершению уровня!
float GameMoney = 0;
float GameExperience = 0;
int AlienShipsKillQuant;
float AlienShipsKillBonus;
int AlienMotherShipsKillQuant;
float AlienMotherShipsKillBonus;
int PirateShipsKillQuant;
float PirateShipsKillBonus;
int PirateVehiclesKillQuant;
float PirateVehiclesKillBonus;
int PirateBuildingsKillQuant;
float PirateBuildingsKillBonus;
int AsteroidsKillQuant;
float AsteroidsKillBonus;
// статус завершена игра или нет
bool GameMissionCompleteStatus = false;
// собственно сам файтер
CEarthSpaceFighter *PlayerFighter = 0;
// флаг отображения меню
bool GameMenu = false;
float GameContentTransp = 0.0f;
float LastGameUpdateTime = 0.0f;
int GameMenuStatus = 1;
float GameButton1Transp = 1.0f;
float LastGameButton1UpdateTime = 0.0f;
float GameButton2Transp = 1.0f;
float LastGameButton2UpdateTime = 0.0f;
float GameButton3Transp = 1.0f;
float LastGameButton3UpdateTime = 0.0f;
float GameButton4Transp = 1.0f;
float LastGameButton4UpdateTime = 0.0f;
bool NeedShowGameMenu = false;
bool NeedHideGameMenu = false;
// работа с морганием вывода
extern float CurrentAlert2;
extern float CurrentAlert3;
extern float CurentTime;
// прорисовка эмблем энергии и жизни
eParticleSystem2D *EnergyParticleSystem2D = 0;
eParticleSystem2D *LifeParticleSystem2D = 0;
eParticleSystem2D *Life2ParticleSystem2D = 0;
eParticleSystem2D *Life3ParticleSystem2D = 0;
// работа с кораблем игрока
void InitGamePlayerShip();
void GamePlayerShip();
float GetShipMaxEnergy(int Num);
extern float CurrentPlayerShipEnergy;
extern int LastMouseX;
extern int LastMouseY;
extern int LastMouseXR;
extern int LastMouseYR;
// состояние жизни и энергии, которые сейчас рисуем
float CurrentDrawEnergNumFull;
float CurrentDrawLifeNumFull;
// щит или дефлектор
extern eParticleSystem *Shild1;
extern eParticleSystem *Shild2;
// для звука открытия-закрытия меню в игре
int SoundShowHideMenu = 0;
// для прорисовки подложки с тайловой анимацией
float StarsTile=0.0f;
float StarsTileUpdateTime = 0.0f;
float StarsTile2=0.0f;
float StarsTileUpdateTime2 = 0.0f;
float StarsTile3=0.0f;
float StarsTileUpdateTime3 = 0.0f;
float StarsTileStartTransparentLayer1 = 0.0f;
float StarsTileEndTransparentLayer1 = 0.0f;
float StarsTileStartTransparentLayer2 = 0.0f;
float StarsTileEndTransparentLayer2 = 0.0f;
extern CSpaceObject *StartSpaceObject;
// для отображения скорости
float CurrentGameSpeed = 0.0f;
// время, которое показываем скорость
float CurrentGameSpeedShowTime = 0.0f;
float LastGameOnOffUpdateTime = 0.0f;
float GameBlackTransp = 0.0f;
bool NeedOnGame = false;
bool NeedOffGame = false;
// показывать время игры при скорости 1.5
bool ShowGameTime;
float GameTime;
float LastGameTime;
//------------------------------------------------------------------------------------
// данные фонта
//------------------------------------------------------------------------------------
void GetGameNumFontData(char Char, RECT *SrcRest)
{
switch (Char)
{
case '0': SetRect(SrcRest,232,4,245,25); break;
case '1': SetRect(SrcRest,71,4,84,25); break;
case '2': SetRect(SrcRest,88,4,101,25); break;
case '3': SetRect(SrcRest,106,4,119,25); break;
case '4': SetRect(SrcRest,124,4,137,25); break;
case '5': SetRect(SrcRest,142,4,155,25); break;
case '6': SetRect(SrcRest,160,4,173,25); break;
case '7': SetRect(SrcRest,178,4,191,25); break;
case '8': SetRect(SrcRest,196,4,209,25); break;
case '9': SetRect(SrcRest,214,4,227,25); break;
case 'E': SetRect(SrcRest,47,4,66,25); break;
case 'S': SetRect(SrcRest,4,4,21,25); break;
case '$': SetRect(SrcRest,25,4,41,25); break;
case ' ': SetRect(SrcRest,0,0,13,0); break;
}
}
//------------------------------------------------------------------------------------
// прорисовка денег и опыта
//------------------------------------------------------------------------------------
void DrawGameExpMoney(int Exp, int Money)
{
RECT DstRest, SrcRest;
SetRect(&SrcRest, 0, 0, 0, 0);
int Ystart;
float Xstart;
eTexture *Tex = vw_FindTextureByName("DATA/GAME/game_num.tga");
if (Tex == 0) return;
float AW;
float AH;
bool ASpresent=false;
ASpresent = vw_GetAspectWH(&AW, &AH);
int W, H;
vw_GetViewport(0, 0, &W, &H);
float AWw = W*1.0f;
float AHw = H*1.0f;
// Установка текстуры и ее свойств...
vw_SetTextureV(0, Tex);
vw_SetTexAlpha(true, 0.01f);
vw_SetTexAddressMode(0, RI_CLAMP);
vw_SetTexBlend(RI_BLEND_SRCALPHA, RI_BLEND_INVSRCALPHA);
// не можем ставить другое! если нет мипмапа
vw_SetTexFiltering(0, RI_MAGFILTER_LINEAR | RI_MINFILTER_LINEAR | RI_MIPFILTER_NONE, 1);
float ImageHeight = Tex->Height*1.0f;
float ImageWidth = Tex->Width*1.0f;
float tmpPosY = 0;
float R=1.0f;
float G=1.0f;
float B=1.0f;
float Transp=1.0f;
// выделяем память
// буфер для последовательности RI_TRIANGLE_STRIP
// войдет RI_2f_XYZ | RI_2f_TEX | RI_4f_COLOR
float *tmp = 0;
tmp = new float[(2+2+4)*4*16]; if (tmp == 0) return;
int k=0;
// вывод эмблем
Xstart = Setup.iAspectRatioWidth/2-57.0f;
Ystart = 5;
GetGameNumFontData('E', &SrcRest);
SetRect(&DstRest, (int)Xstart, Ystart,
(int)Xstart+SrcRest.right-SrcRest.left, Ystart+SrcRest.bottom-SrcRest.top);
if (ASpresent) tmpPosY = (AH - DstRest.top - DstRest.top - (DstRest.bottom - DstRest.top));
else tmpPosY = (AHw - DstRest.top - DstRest.top - (DstRest.bottom - DstRest.top));
float FrameHeight = (SrcRest.bottom*1.0f )/ImageHeight;
float FrameWidth = (SrcRest.right*1.0f )/ImageWidth;
float Yst = (SrcRest.top*1.0f)/ImageHeight;
float Xst = (SrcRest.left*1.0f)/ImageWidth;
tmp[k++] = DstRest.left; // X
tmp[k++] = DstRest.top +tmpPosY +(DstRest.bottom - DstRest.top); // Y
tmp[k++] = R;
tmp[k++] = G;
tmp[k++] = B;
tmp[k++] = Transp;
tmp[k++] = Xst;
tmp[k++] = 1.0f-Yst;
tmp[k++] = DstRest.left; // X
tmp[k++] = DstRest.top +tmpPosY; // Y
tmp[k++] = R;
tmp[k++] = G;
tmp[k++] = B;
tmp[k++] = Transp;
tmp[k++] = Xst;
tmp[k++] = 1.0f-FrameHeight;
tmp[k++] = DstRest.left + (DstRest.right - DstRest.left); // X
tmp[k++] = DstRest.top +tmpPosY; // Y
tmp[k++] = R;
tmp[k++] = G;
tmp[k++] = B;
tmp[k++] = Transp;
tmp[k++] = FrameWidth;
tmp[k++] = 1.0f-FrameHeight;
tmp[k++] = DstRest.left + (DstRest.right - DstRest.left); // X
tmp[k++] = DstRest.top +tmpPosY +(DstRest.bottom - DstRest.top); // Y
tmp[k++] = R;
tmp[k++] = G;
tmp[k++] = B;
tmp[k++] = Transp;
tmp[k++] = FrameWidth;
tmp[k++] = 1.0f-Yst;
Xstart = Setup.iAspectRatioWidth/2-56.0f;
Ystart = 31;
GetGameNumFontData('$', &SrcRest);
SetRect(&DstRest, (int)Xstart, Ystart,
(int)Xstart+SrcRest.right-SrcRest.left, Ystart+SrcRest.bottom-SrcRest.top);
if (ASpresent) tmpPosY = (AH - DstRest.top - DstRest.top - (DstRest.bottom - DstRest.top));
else tmpPosY = (AHw - DstRest.top - DstRest.top - (DstRest.bottom - DstRest.top));
FrameHeight = (SrcRest.bottom*1.0f )/ImageHeight;
FrameWidth = (SrcRest.right*1.0f )/ImageWidth;
Yst = (SrcRest.top*1.0f)/ImageHeight;
Xst = (SrcRest.left*1.0f)/ImageWidth;
tmp[k++] = DstRest.left; // X
tmp[k++] = DstRest.top +tmpPosY +(DstRest.bottom - DstRest.top); // Y
tmp[k++] = R;
tmp[k++] = G;
tmp[k++] = B;
tmp[k++] = Transp;
tmp[k++] = Xst;
tmp[k++] = 1.0f-Yst;
tmp[k++] = DstRest.left; // X
tmp[k++] = DstRest.top +tmpPosY; // Y
tmp[k++] = R;
tmp[k++] = G;
tmp[k++] = B;
tmp[k++] = Transp;
tmp[k++] = Xst;
tmp[k++] = 1.0f-FrameHeight;
tmp[k++] = DstRest.left + (DstRest.right - DstRest.left); // X
tmp[k++] = DstRest.top +tmpPosY; // Y
tmp[k++] = R;
tmp[k++] = G;
tmp[k++] = B;
tmp[k++] = Transp;
tmp[k++] = FrameWidth;
tmp[k++] = 1.0f-FrameHeight;
tmp[k++] = DstRest.left + (DstRest.right - DstRest.left); // X
tmp[k++] = DstRest.top +tmpPosY +(DstRest.bottom - DstRest.top); // Y
tmp[k++] = R;
tmp[k++] = G;
tmp[k++] = B;
tmp[k++] = Transp;
tmp[k++] = FrameWidth;
tmp[k++] = 1.0f-Yst;
// вывод опыта
Xstart = Setup.iAspectRatioWidth/2-57+23.0f;
Ystart = 5;
char buffer[10];
if (Exp < 0) Exp = 0;
sprintf(buffer,"%i",Exp);
for (int i=0; i<7; i++)
{
if (7-i > strlen(buffer))
{
Transp = 0.2f;
GetGameNumFontData('0', &SrcRest);
}
else
{
Transp = 1.0f;
GetGameNumFontData(buffer[i+strlen(buffer)-7], &SrcRest);
}
SetRect(&DstRest, (int)Xstart, Ystart,
(int)Xstart+SrcRest.right-SrcRest.left, Ystart+SrcRest.bottom-SrcRest.top);
if (ASpresent) tmpPosY = (AH - DstRest.top - DstRest.top - (DstRest.bottom - DstRest.top));
else tmpPosY = (AHw - DstRest.top - DstRest.top - (DstRest.bottom - DstRest.top));
FrameHeight = (SrcRest.bottom*1.0f )/ImageHeight;
FrameWidth = (SrcRest.right*1.0f )/ImageWidth;
Yst = (SrcRest.top*1.0f)/ImageHeight;
Xst = (SrcRest.left*1.0f)/ImageWidth;
tmp[k++] = DstRest.left; // X
tmp[k++] = DstRest.top +tmpPosY +(DstRest.bottom - DstRest.top); // Y
tmp[k++] = R;
tmp[k++] = G;
tmp[k++] = B;
tmp[k++] = Transp;
tmp[k++] = Xst;
tmp[k++] = 1.0f-Yst;
tmp[k++] = DstRest.left; // X
tmp[k++] = DstRest.top +tmpPosY; // Y
tmp[k++] = R;
tmp[k++] = G;
tmp[k++] = B;
tmp[k++] = Transp;
tmp[k++] = Xst;
tmp[k++] = 1.0f-FrameHeight;
tmp[k++] = DstRest.left + (DstRest.right - DstRest.left); // X
tmp[k++] = DstRest.top +tmpPosY; // Y
tmp[k++] = R;
tmp[k++] = G;
tmp[k++] = B;
tmp[k++] = Transp;
tmp[k++] = FrameWidth;
tmp[k++] = 1.0f-FrameHeight;
tmp[k++] = DstRest.left + (DstRest.right - DstRest.left); // X
tmp[k++] = DstRest.top +tmpPosY +(DstRest.bottom - DstRest.top); // Y
tmp[k++] = R;
tmp[k++] = G;
tmp[k++] = B;
tmp[k++] = Transp;
tmp[k++] = FrameWidth;
tmp[k++] = 1.0f-Yst;
Xstart += SrcRest.right - SrcRest.left;
}
// вывод денег
Xstart = Setup.iAspectRatioWidth/2-57+23.0f;
Ystart = 31;
if (Money < 0) Money = 0;
sprintf(buffer,"%i",Money);
for (int i=0; i<7; i++)
{
if (7-i > strlen(buffer))
{
Transp = 0.2f;
GetGameNumFontData('0', &SrcRest);
}
else
{
Transp = 1.0f;
GetGameNumFontData(buffer[i+strlen(buffer)-7], &SrcRest);
}
SetRect(&DstRest, (int)Xstart, Ystart,
(int)Xstart+SrcRest.right-SrcRest.left, Ystart+SrcRest.bottom-SrcRest.top);
if (ASpresent) tmpPosY = (AH - DstRest.top - DstRest.top - (DstRest.bottom - DstRest.top));
else tmpPosY = (AHw - DstRest.top - DstRest.top - (DstRest.bottom - DstRest.top));
FrameHeight = (SrcRest.bottom*1.0f )/ImageHeight;
FrameWidth = (SrcRest.right*1.0f )/ImageWidth;
Yst = (SrcRest.top*1.0f)/ImageHeight;
Xst = (SrcRest.left*1.0f)/ImageWidth;
tmp[k++] = DstRest.left; // X
tmp[k++] = DstRest.top +tmpPosY +(DstRest.bottom - DstRest.top); // Y
tmp[k++] = R;
tmp[k++] = G;
tmp[k++] = B;
tmp[k++] = Transp;
tmp[k++] = Xst;
tmp[k++] = 1.0f-Yst;
tmp[k++] = DstRest.left; // X
tmp[k++] = DstRest.top +tmpPosY; // Y
tmp[k++] = R;
tmp[k++] = G;
tmp[k++] = B;
tmp[k++] = Transp;
tmp[k++] = Xst;
tmp[k++] = 1.0f-FrameHeight;
tmp[k++] = DstRest.left + (DstRest.right - DstRest.left); // X
tmp[k++] = DstRest.top +tmpPosY; // Y
tmp[k++] = R;
tmp[k++] = G;
tmp[k++] = B;
tmp[k++] = Transp;
tmp[k++] = FrameWidth;
tmp[k++] = 1.0f-FrameHeight;
tmp[k++] = DstRest.left + (DstRest.right - DstRest.left); // X
tmp[k++] = DstRest.top +tmpPosY +(DstRest.bottom - DstRest.top); // Y
tmp[k++] = R;
tmp[k++] = G;
tmp[k++] = B;
tmp[k++] = Transp;
tmp[k++] = FrameWidth;
tmp[k++] = 1.0f-Yst;
Xstart += SrcRest.right - SrcRest.left;
}
vw_SendVertices(RI_QUADS, 4*16, RI_2f_XYZ | RI_1_TEX | RI_4f_COLOR, tmp, 8*sizeof(float));
if (tmp != 0){delete [] tmp; tmp = 0;}
vw_SetTexAlpha(false, 0.5f);
vw_SetColor(1.0f, 1.0f, 1.0f, 1.0f);
vw_SetTextureDef(0);
}
//------------------------------------------------------------------------------------
// прорисовка цифр
//------------------------------------------------------------------------------------
void DrawGameNumFontWiaFont(int X, int Y, bool Need0, int NeedNum, const char *Text, ...)
{
// смотрим значения параметров в строке
char text[1024];
va_list ap;
va_start(ap, Text);
vsprintf(text, Text, ap);
va_end(ap);
// в text уже полная строка
// находим макс. ширину цифр
int MaxW = 0;
for (int i=0; i<=9; i++)
{
int TmpMaxW = FontSize("%i",i);
if (TmpMaxW > MaxW) MaxW = TmpMaxW;
}
int Sm = 0;
if (Need0)
if (strlen(text)4) CurrentProfile = 0;
if (CurrentMission == -1) CurrentMission = 0;
GameNPCWeaponPenalty = Setup.Profile[CurrentProfile].NPCWeaponPenalty;
GameNPCArmorPenalty = Setup.Profile[CurrentProfile].NPCArmorPenalty;
GameNPCTargetingSpeedPenalty = Setup.Profile[CurrentProfile].NPCTargetingSpeedPenalty;
GameLimitedAmmo = Setup.Profile[CurrentProfile].LimitedAmmo;
GameDestroyableWeapon = Setup.Profile[CurrentProfile].DestroyableWeapon;
GameWeaponTargetingMode = Setup.Profile[CurrentProfile].WeaponTargetingMode;
GameSpaceShipControlMode = Setup.Profile[CurrentProfile].SpaceShipControlMode;
GameEngineSystem = Setup.Profile[CurrentProfile].EngineSystem;
// если симулятивный режим, ставим 1...
if (GameSpaceShipControlMode == 1)
if (GameEngineSystem == 0) GameEngineSystem = 1;
GameTargetingSystem = Setup.Profile[CurrentProfile].TargetingSystem;
GameAdvancedProtectionSystem = Setup.Profile[CurrentProfile].AdvancedProtectionSystem;
GamePowerSystem = Setup.Profile[CurrentProfile].PowerSystem;
GameTargetingMechanicSystem = Setup.Profile[CurrentProfile].TargetingMechanicSystem;
GameMoney = Setup.Profile[CurrentProfile].Money*1.0f;
// убираем данные этого уровня
GameExperience = (Setup.Profile[CurrentProfile].Experience - Setup.Profile[CurrentProfile].ByMissionExperience[CurrentMission])*1.0f;
// забираем эксклюзивное управление мышкой и клавой, если оконный режим
if (Setup.BPP == 0) SDL_WM_GrabInput(SDL_GRAB_ON);
// сбрасываем все кнопки мыши
for (int i=0; i<8; i++)
SDL_MouseCurrentStatus[i] = false;
// установка мышки на центр
int W, H;
vw_GetViewport(0, 0, &W, &H);
SDL_WarpMouse(W/2, H/2);
DrawGameCursor = false;
LastMouseXR = 0;
LastMouseYR = 0;
SDL_GetMouseState(&LastMouseXR, &LastMouseYR);
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// инициализация счета времени (всегда первым)
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vw_InitTimeNum(1);
vw_SetTimeThreadSpeed(1, Setup.GameSpeed);
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// иним камеру, всегда до работы со скриптом (!!!)
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
InitGameCamera();
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// иним корабль
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
InitGamePlayerShip();
CreateCursor();
// !!! пока загрузка идет полная на уровень, и наверно так и нужно оставить
// иначе нужно выносить перечень загружаемого в скрипт (менять не смогут уровни)
if (Script != 0){delete Script; Script = 0;}
Script = new ScriptEngine;
if (Script != 0)
{
if (GetMissionFileName() != 0)
{
if (!Script->RunScript(GetMissionFileName(), vw_GetTime(1)))
{
delete Script; Script = 0;
}
}
else
{
delete Script; Script = 0;
}
}
// выводим номер миссии 3 секунды
GameSetMissionTitleData(3, CurrentMission+1);
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// активные частицы космоса
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
psSpace = 0;
psSpace = new eParticleSystem;
psSpace->ColorStart.r = 0.80f;
psSpace->ColorStart.g = 0.80f;
psSpace->ColorStart.b = 1.00f;
psSpace->ColorEnd.r = 0.70f;
psSpace->ColorEnd.g = 0.70f;
psSpace->ColorEnd.b = 1.00f;
psSpace->AlphaStart = 1.00f;
psSpace->AlphaEnd = 1.00f;
psSpace->SizeStart = 0.40f;
psSpace->SizeEnd = 0.15f;
psSpace->Speed = 25.00f;
psSpace->SpeedVar = 5.00f;
psSpace->Theta = 0.00f;
psSpace->Life = 14.00f;
psSpace->LifeVar = 0.00f;
psSpace->CreationType = 1;
psSpace->CreationSize = VECTOR3D(200.0f,30.0f,10.0f);
psSpace->ParticlesPerSec = 60;
psSpace->Texture = vw_FindTextureByName("DATA/GFX/flare3.tga");
psSpace->Direction = VECTOR3D(0.0f, 0.0f, -1.0f);
psSpace->SetStartLocation(VECTOR3D(0,10,250));//поправь ниже, на переносе если изменил!!!
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// немного "прокручиваем", чтобы сразу по появлению было заполнено
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
vw_ResizeScene(45.0f, Setup.fAspectRatioWidth/Setup.fAspectRatioHeight, 1.0f, 10000.0f);
vw_SetCameraLocation(VECTOR3D(0,65,-100+10));
vw_SetCameraMoveAroundPoint(VECTOR3D(0,0,10), 0.0f, VECTOR3D(0.0f, 0.0f, 0.0f));
float Time = psSpace->TimeLastUpdate;
for (float i=Time; i