1614 lines
47 KiB
C++
1614 lines
47 KiB
C++
#include "View.h"
|
|
#include "CameraBase.h"
|
|
#include "SimpleConsoleOverlay.h"
|
|
#include "IMGUIControls.h"
|
|
#include "keytable.h"
|
|
#include "DrawingsGL.h"
|
|
|
|
#include "Engine.h"
|
|
#include "Physics.h"
|
|
#include "Model.h"
|
|
#include "Controller.h"
|
|
#include "EventBase.h"
|
|
|
|
#include "Game.h"
|
|
#include "ShipEntity.h"
|
|
#include "AsteroidEntity.h"
|
|
#include "AsteroidsEvents.h"
|
|
#include "RocketEntity.h"
|
|
|
|
#include <GL/gl.h>
|
|
#include <GL/glu.h>
|
|
|
|
#include <iomanip>
|
|
// #define DRAW_BOUNDARIES
|
|
|
|
#ifdef DRAW_BOUNDARIES
|
|
#include "coll2d.h"
|
|
#include "DrawingsGL.h"
|
|
#endif
|
|
|
|
using namespace std;
|
|
|
|
namespace asteroids {
|
|
|
|
static Engine::Variable VarCheatMode ("cheat_mode", "false");
|
|
|
|
int View::OnInit (int argc, char* argv[]) {
|
|
ViewBase::OnInit (argc, argv);
|
|
|
|
/*
|
|
// We want the console
|
|
mConsoleOverlay = boost::shared_ptr<Engine::SimpleConsoleOverlay> (new Engine::SimpleConsoleOverlay);
|
|
// We also want to display the log bar
|
|
mConsoleOverlay->SetDrawLogBar (true);
|
|
mOverlayManager.Register (mConsoleOverlay, GameStateMainMenu);
|
|
*/
|
|
|
|
LoadFont("AldotheApache.ttf size=20 color=#000000");
|
|
|
|
button_width = 250;
|
|
button_height = 40;
|
|
|
|
// This is a simple star field that makes the game so spacy
|
|
int i;
|
|
for (i = 0; i < 200; i++) {
|
|
BackgroundStar star;
|
|
star.position[0] = rand() / float(RAND_MAX) * 1.2;
|
|
star.position[1] = rand() / float(RAND_MAX) * 1.2;
|
|
star.position[2] = rand() / float(RAND_MAX) * 1.2;
|
|
|
|
mBackgroundStars.push_back (star);
|
|
}
|
|
|
|
// Editor default variables
|
|
mEditorEntityId = 0;
|
|
mEditorState = EditorStateUnknown;
|
|
|
|
mGUIShipSprite.LoadFromPNG(Engine::GetResourceFullPath("/data/textures/ship.png"));
|
|
mGUIShipSprite.SetScale (0.1);
|
|
|
|
mAsteroidSprite.LoadFromPNG (Engine::GetResourceFullPath("/data/textures/asteroid.png"));
|
|
mShipSprite.LoadFromPNG (Engine::GetResourceFullPath("/data/textures/ship.png"));
|
|
|
|
mShipThrustSprite.LoadFromPNG (Engine::GetResourceFullPath("/data/textures/ship_thrust.png"));
|
|
mShipThrustSprite.SetAnimation (4, 8);
|
|
|
|
mShipPartsSprite.LoadFromPNG (Engine::GetResourceFullPath("/data/textures/ship_parts.png"));
|
|
mShipPartsSprite.SetSubSpriteCount (10);
|
|
|
|
Engine::RegisterListener (this, EventAccelerateStart);
|
|
Engine::RegisterListener (this, EventAccelerateStop);
|
|
Engine::RegisterListener (this, EventShipExplode);
|
|
Engine::RegisterListener (this, EventPlayerDied);
|
|
Engine::RegisterListener (this, EventGameOver);
|
|
Engine::RegisterListener (this, EventLevelComplete);
|
|
|
|
PushViewState (ViewStateMainMenu);
|
|
|
|
mCreditsPageIndex = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void View::OnDestroy() {
|
|
mBackgroundStars.clear();
|
|
mShipPartsEntityIds.clear();
|
|
|
|
Engine::ViewBase::OnDestroy();
|
|
}
|
|
|
|
bool View::OnReceiveEvent (const Engine::EventBasePtr &event) {
|
|
switch (event->mEventType) {
|
|
case EventAccelerateStart:
|
|
case EventAccelerateStop:
|
|
if (event->mEventType == EventAccelerateStart)
|
|
mShipThrustSprite.ResetAnimation();
|
|
|
|
Engine::LogDebug ("Received Acceleration Event: %d", event->mEventType);
|
|
return true;
|
|
|
|
break;
|
|
case EventLevelComplete:
|
|
if (GetModel()->GetGameState() == GameStateRunning) {
|
|
PushViewState(ViewStateLevelComplete);
|
|
GetController()->ResetPlayerEntity();
|
|
}
|
|
break;
|
|
|
|
case EventGameOver:
|
|
mFadeTimerSecValue = 2.;
|
|
|
|
PopViewState();
|
|
PushViewState(ViewStateGameOver);
|
|
GetController()->ResetPlayerEntity();
|
|
|
|
break;
|
|
case EventPlayerDied:
|
|
mFadeTimerSecValue = 2.;
|
|
PushViewState(ViewStatePlayerDied);
|
|
GetController()->ResetPlayerEntity();
|
|
|
|
break;
|
|
case EventShipExplode: {
|
|
// This event is fired when the ship explodes. Note: this event is not
|
|
// sufficient for EventPlayerDied!
|
|
Engine::LogDebug ("Received PlayerDied Event: %d", event->mEventType);
|
|
|
|
// insert sprits that contains parts of the ship
|
|
Engine::EntityBase *ship_entity = Engine::GetEntity (event->mEventUnsignedInt);
|
|
vector3d position = ship_entity->mPhysicState->mPosition;
|
|
vector3d orientation = ship_entity->mPhysicState->mOrientation;
|
|
vector3d velocity = ship_entity->mPhysicState->mVelocity;
|
|
vector3d rel_velocity = event->mVector3d;
|
|
|
|
unsigned int i;
|
|
mShipPartsEntityIds.clear();
|
|
|
|
for (i = 0; i < mShipPartsSprite.GetSubSpriteCount(); i++) {
|
|
Engine::EntityBase* part_sprite_particle = Engine::CreateEntity (GameEntityTypeShipPart);
|
|
part_sprite_particle->mPhysicState->mPosition = position;
|
|
part_sprite_particle->mPhysicState->mOrientation = orientation;
|
|
vector3d part_velocity (
|
|
rel_velocity[0] * (rand()/float(RAND_MAX)) * 1.7,
|
|
0.,
|
|
rel_velocity[2] * (rand()/float(RAND_MAX)) * 1.5
|
|
);
|
|
part_sprite_particle->mPhysicState->mVelocity = part_velocity * -1.;
|
|
|
|
part_sprite_particle->mPhysicState->mAngleVelocity = (rand()/float(RAND_MAX) - 0.5 ) * 100.;
|
|
|
|
mShipPartsEntityIds.push_back(part_sprite_particle->mId);
|
|
}
|
|
|
|
// We do not need the entity anymore
|
|
Engine::KillEntity(event->mEventUnsignedInt);
|
|
|
|
return true;
|
|
|
|
break;
|
|
}
|
|
|
|
default: Engine::LogWarning ("Received Event with type %d but don't know what to do with it!", event->mEventType);
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
* Module specific functions
|
|
*/
|
|
void View::UpdateCamera () {
|
|
mCamera->SetEye (
|
|
0.,
|
|
9.5,
|
|
0.
|
|
);
|
|
mCamera->SetPointOfIntrest (
|
|
0.,
|
|
0.,
|
|
0.
|
|
);
|
|
mCamera->SetUp (
|
|
0.,
|
|
0.,
|
|
-1.
|
|
);
|
|
|
|
mCamera->Update ();
|
|
}
|
|
|
|
void View::DrawStars() {
|
|
unsigned int i;
|
|
|
|
float world_width, world_height;
|
|
world_width = static_cast<Model*>(mModel)->GetWorldWidth();
|
|
world_height = static_cast<Model*>(mModel)->GetWorldHeight();
|
|
vector3d velocity (1., 0., 0.);
|
|
|
|
glPushMatrix();
|
|
glTranslatef(-world_width * 0.5, 0, -world_height * 0.5);
|
|
glColor3f (1., 1., 1.);
|
|
glPointSize(2.);
|
|
glBegin(GL_POINTS);
|
|
float z_value;
|
|
for (i = 0; i < mBackgroundStars.size(); i++) {
|
|
// glPointSize (2. + 300. *mBackgroundStars.at(i).position[1]);
|
|
z_value = mBackgroundStars.at(i).position[1] + 0.1;
|
|
|
|
glColor3f (z_value, z_value, z_value);
|
|
glVertex3f (mBackgroundStars.at(i).position[0] * world_width,
|
|
-1.,
|
|
mBackgroundStars.at(i).position[2] * world_height);
|
|
|
|
mBackgroundStars.at(i).position -= vector3d(Engine::GetFrameDuration() * 0.7 * mBackgroundStars.at(i).position[1] / world_width, 0., 0.);
|
|
|
|
// we move the stars a little more such that they are not blende out too early
|
|
// \todo compute proper bounds from Physics world size!
|
|
if (mBackgroundStars.at(i).position[0] < -0.1)
|
|
mBackgroundStars.at(i).position[0] += 1.2;
|
|
if (mBackgroundStars.at(i).position[0] >= 1.1)
|
|
mBackgroundStars.at(i).position[0] -= 1.2;
|
|
}
|
|
|
|
glEnd();
|
|
glPopMatrix();
|
|
}
|
|
|
|
void View::Draw() {
|
|
PreDraw();
|
|
|
|
mFadeTimerSecValue -= GetModel()->GetFrameDuration();
|
|
|
|
// Actual Drawing
|
|
UpdateCamera ();
|
|
|
|
if (mDrawGrid)
|
|
DrawGrid ();
|
|
|
|
/*
|
|
if (mDrawAxis)
|
|
DrawAxis ();
|
|
*/
|
|
|
|
std::map<unsigned int, Engine::EntityBase*>::iterator entity_iterator;
|
|
Model *game_model = static_cast<Model*> (mModel);
|
|
unsigned int game_state = game_model->GetGameState();
|
|
unsigned int view_state = GetViewState();
|
|
|
|
DrawStars ();
|
|
|
|
if ( game_state == GameStateRunning
|
|
|| view_state == ViewStateLevelIntro
|
|
|| view_state == ViewStateEditor) {
|
|
DrawWorld ();
|
|
}
|
|
|
|
DrawUi ();
|
|
|
|
// Perform post-Draw actions
|
|
PostDraw();
|
|
}
|
|
|
|
void View::DrawWorld() {
|
|
std::map<unsigned int, Engine::EntityBase*>::iterator entity_iterator;
|
|
Model *game_model = static_cast<Model*> (mModel);
|
|
|
|
ViewBase::DrawWorld();
|
|
|
|
for (entity_iterator = game_model->mEntities.begin ();
|
|
entity_iterator != game_model->mEntities.end();
|
|
entity_iterator++) {
|
|
Engine::EntityBase* entity = entity_iterator->second;
|
|
|
|
// Perform multiple drawing if the entity is at the border
|
|
Physics* game_physics = (Physics*) game_model->mPhysics;
|
|
float world_width = game_physics->GetWorldWidth();
|
|
float world_height = game_physics->GetWorldHeight();
|
|
|
|
// if we are in Edit mode and are currently editing the velocity we must
|
|
// make sure that we display it
|
|
if (GetViewState() == ViewStateEditor) {
|
|
if (mEditorState == EditorStateEntityVelocity) {
|
|
DrawVector (entity->mPhysicState->GetPosition(),
|
|
entity->mPhysicState->GetPosition() + entity->mPhysicState->GetVelocity());
|
|
}
|
|
}
|
|
|
|
// Drawing at the original position:
|
|
glPushMatrix ();
|
|
glTranslatef (entity->mPhysicState->mPosition[0],
|
|
entity->mPhysicState->mPosition[1],
|
|
entity->mPhysicState->mPosition[2]);
|
|
|
|
glRotatef(entity->mPhysicState->mOrientation[0], 0., 0., 1.);
|
|
glRotatef(entity->mPhysicState->mOrientation[1], 0., 1., 0.);
|
|
glRotatef(entity->mPhysicState->mOrientation[2], 1., 0., 0.);
|
|
|
|
glColor3f (1., 1., 1.);
|
|
DrawEntity (entity);
|
|
|
|
glPopMatrix ();
|
|
|
|
// If we move out the right side
|
|
if (entity->mPhysicState->mPosition[0] + entity->mPhysicState->mRadius * 2
|
|
>= world_width * 0.5) {
|
|
glPushMatrix ();
|
|
glTranslatef (entity->mPhysicState->mPosition[0] - world_width,
|
|
entity->mPhysicState->mPosition[1],
|
|
entity->mPhysicState->mPosition[2]);
|
|
|
|
glRotatef(entity->mPhysicState->mOrientation[0], 0., 0., 1.);
|
|
glRotatef(entity->mPhysicState->mOrientation[1], 0., 1., 0.);
|
|
glRotatef(entity->mPhysicState->mOrientation[2], 1., 0., 0.);
|
|
|
|
glColor3f (1., 1., 1.);
|
|
DrawEntity (entity);
|
|
|
|
glPopMatrix ();
|
|
}
|
|
|
|
// if we move out the left side
|
|
if (entity->mPhysicState->mPosition[0] - entity->mPhysicState->mRadius * 2
|
|
< - world_width * 0.5) {
|
|
glPushMatrix ();
|
|
glTranslatef (entity->mPhysicState->mPosition[0] + world_width,
|
|
entity->mPhysicState->mPosition[1],
|
|
entity->mPhysicState->mPosition[2]);
|
|
|
|
glRotatef(entity->mPhysicState->mOrientation[0], 0., 0., 1.);
|
|
glRotatef(entity->mPhysicState->mOrientation[1], 0., 1., 0.);
|
|
glRotatef(entity->mPhysicState->mOrientation[2], 1., 0., 0.);
|
|
|
|
glColor3f (1., 1., 1.);
|
|
DrawEntity (entity);
|
|
|
|
glPopMatrix ();
|
|
}
|
|
|
|
// If we move out the bottom side
|
|
if (entity->mPhysicState->mPosition[2] + entity->mPhysicState->mRadius * 2
|
|
>= world_height * 0.5) {
|
|
|
|
glPushMatrix ();
|
|
glTranslatef (entity->mPhysicState->mPosition[0],
|
|
entity->mPhysicState->mPosition[1],
|
|
entity->mPhysicState->mPosition[2] - world_height);
|
|
|
|
glRotatef(entity->mPhysicState->mOrientation[0], 0., 0., 1.);
|
|
glRotatef(entity->mPhysicState->mOrientation[1], 0., 1., 0.);
|
|
glRotatef(entity->mPhysicState->mOrientation[2], 1., 0., 0.);
|
|
|
|
glColor3f (1., 1., 1.);
|
|
DrawEntity (entity);
|
|
|
|
glPopMatrix ();
|
|
}
|
|
|
|
// if we move out the left side
|
|
if (entity->mPhysicState->mPosition[2] - entity->mPhysicState->mRadius * 2
|
|
< - world_height* 0.5) {
|
|
glPushMatrix ();
|
|
glTranslatef (entity->mPhysicState->mPosition[0],
|
|
entity->mPhysicState->mPosition[1],
|
|
entity->mPhysicState->mPosition[2] + world_height);
|
|
|
|
glRotatef(entity->mPhysicState->mOrientation[0], 0., 0., 1.);
|
|
glRotatef(entity->mPhysicState->mOrientation[1], 0., 1., 0.);
|
|
glRotatef(entity->mPhysicState->mOrientation[2], 1., 0., 0.);
|
|
|
|
glColor3f (1., 1., 1.);
|
|
DrawEntity (entity);
|
|
|
|
glPopMatrix ();
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Userinterface
|
|
*/
|
|
void View::DrawUi () {
|
|
glClearColor (0.1, 0.1, 0.1, 1.);
|
|
|
|
screen_right = static_cast<float> (Engine::GetWindowWidth());
|
|
screen_bottom = static_cast<float> (Engine::GetWindowHeight());
|
|
|
|
// we switch to orthographic projection and draw the contents of the 2d
|
|
// overlay on top of the previous drawings
|
|
glMatrixMode (GL_PROJECTION);
|
|
glPushMatrix ();
|
|
glLoadIdentity ();
|
|
|
|
// first we have to get the size of the current viewport to set up the
|
|
// orthographic projection correctly
|
|
GLint viewport[4];
|
|
glGetIntegerv(GL_VIEWPORT, viewport);
|
|
gluOrtho2D (viewport[0], viewport[2], viewport[3], viewport[1]);
|
|
|
|
glMatrixMode (GL_MODELVIEW);
|
|
glPushMatrix ();
|
|
glLoadIdentity ();
|
|
|
|
unsigned int game_state = GetModel()->GetGameState();
|
|
|
|
SelectFont("console.ttf");
|
|
SetFontJustification (Engine::FontJustificationLeft);
|
|
|
|
ViewState current_view_state = GetViewState();
|
|
|
|
/*
|
|
SelectFont ("console.ttf size=12");
|
|
Engine::GUI::Label (99999, GetStringViewState(current_view_state), 8, 16);
|
|
*/
|
|
|
|
switch (current_view_state) {
|
|
case ViewStateMainMenu:
|
|
DrawUiMainMenu();
|
|
break;
|
|
case ViewStateGameRunning:
|
|
DrawUiGameRunning();
|
|
break;
|
|
case ViewStatePaused:
|
|
DrawUiGamePaused();
|
|
break;
|
|
case ViewStatePlayerDied:
|
|
DrawUiPlayerDied();
|
|
break;
|
|
case ViewStateLevelIntro:
|
|
DrawUiLevelIntro();
|
|
break;
|
|
case ViewStateLevelComplete:
|
|
DrawUiLevelComplete();
|
|
break;
|
|
case ViewStateShowHighscore:
|
|
DrawUiHighscore();
|
|
break;
|
|
case ViewStateOptions:
|
|
DrawUiOptions();
|
|
break;
|
|
case ViewStateEnterPlayername:
|
|
DrawUiEnterPlayername();
|
|
break;
|
|
case ViewStateGameOver:
|
|
DrawUiGameOver();
|
|
break;
|
|
case ViewStateEditor:
|
|
DrawUiEditor();
|
|
break;
|
|
case ViewStateCredits:
|
|
DrawUiCredits();
|
|
break;
|
|
default:
|
|
Engine::LogWarning ("Trying to draw unknown ViewState: %s (%d)",
|
|
GetStringViewState (game_state), game_state);
|
|
break;
|
|
}
|
|
|
|
glPopMatrix ();
|
|
|
|
glMatrixMode (GL_PROJECTION);
|
|
glPopMatrix ();
|
|
|
|
glMatrixMode (GL_MODELVIEW);
|
|
}
|
|
|
|
void View::DrawPageTitle (const std::string& title) {
|
|
SelectFont("console.ttf size=46 color=#808080");
|
|
float width, height;
|
|
DrawGLStringMeasure(title.c_str(), &width, &height);
|
|
|
|
float xpos = (screen_right - width) * 0.5 - 40;
|
|
float ypos = 180;
|
|
DrawGLString (xpos - 2, ypos + 2, title.c_str());
|
|
|
|
SelectFont("console.ttf size=46 color=#ffffff");
|
|
DrawGLString (xpos, ypos, title.c_str());
|
|
}
|
|
|
|
void View::DrawUiMainMenu() {
|
|
DrawPageTitle ("Asteroids");
|
|
|
|
SelectFont("console.ttf size=23 color=#444444");
|
|
DrawGLString( screen_right - 272, screen_bottom - 16, "http://www.fysx.org");
|
|
SelectFont("console.ttf size=23 color=#cccccc");
|
|
DrawGLString( screen_right - 270, screen_bottom - 18, "http://www.fysx.org");
|
|
|
|
SelectFont("console.ttf size=23");
|
|
if (Engine::GUI::Button (1, "New Game", screen_right * 0.5 - 100, 200, button_width, button_height)) {
|
|
PushViewState(ViewStateEnterPlayername);
|
|
}
|
|
|
|
if (Engine::GUI::Button (2, "Options", screen_right * 0.5 - 100, 250, button_width, button_height)) {
|
|
PushViewState (ViewStateOptions);
|
|
}
|
|
|
|
if (Engine::GUI::Button (3, "Highscores", screen_right * 0.5 - 100, 300, button_width, button_height)) {
|
|
GetModel()->LoadHighscoreList();
|
|
PushViewState(ViewStateShowHighscore);
|
|
}
|
|
|
|
if (Engine::GUI::Button (4, "Credits", screen_right * 0.5 - 100, 350, button_width, button_height)) {
|
|
mCreditsPageIndex = 0;
|
|
PushViewState(ViewStateCredits);
|
|
}
|
|
|
|
if (Engine::GUI::Button (5, "Quit", screen_right * 0.5 - 100, 430, button_width, button_height)) {
|
|
Engine::RunCommand("quit");
|
|
}
|
|
}
|
|
|
|
void View::DrawUiGameRunning() {
|
|
SelectFont("console.ttf size=23 color=#ffffff");
|
|
|
|
float str_width, str_height;
|
|
std::ostringstream out_stream;
|
|
|
|
// --- Player Lives ---
|
|
out_stream << GetModel()->GetPlayerLives() << " x ";
|
|
DrawGLStringMeasure (out_stream.str().c_str(), &str_width, &str_height);
|
|
Engine::GUI::Label (1, out_stream.str().c_str(), screen_right - str_width - 45, screen_bottom - 5);
|
|
|
|
mGUIShipSprite.DrawAt2D (screen_right - 20, screen_bottom - 8);
|
|
|
|
// --- Level Score ---
|
|
out_stream.str("");
|
|
out_stream << "Level Score: " << setw(5) << GetModel()->GetLevelPoints();
|
|
DrawGLStringMeasure (out_stream.str().c_str(), &str_width, &str_height);
|
|
Engine::GUI::Label (1, out_stream.str().c_str(), screen_right - str_width - 12, str_height + 48);
|
|
|
|
// --- Game Score ---
|
|
out_stream.str("");
|
|
out_stream << "Score: " << GetModel()->GetPoints();
|
|
DrawGLStringMeasure (out_stream.str().c_str(), &str_width, &str_height);
|
|
Engine::GUI::Label (1, out_stream.str().c_str(), screen_left + 3, str_height + 48);
|
|
|
|
if (VarCheatMode.GetBoolValue()) {
|
|
if (Engine::GUI::CheckKeyPress(SDLK_PAGEDOWN)) {
|
|
Engine::EventBasePtr level_complete_event (new Engine::EventBase());
|
|
level_complete_event->mEventType = EventLevelComplete;
|
|
QueueEvent (level_complete_event);
|
|
} else if (Engine::GUI::CheckKeyPress(SDLK_PAGEUP)) {
|
|
unsigned int current_level = GetModel()->GetCurrentLevelIndex();
|
|
|
|
if (current_level > 0) {
|
|
GetModel()->SetGameState(GameStatePaused);
|
|
GetModel()->LoadLevelFromIndex(current_level - 1);
|
|
PushViewState(ViewStateLevelIntro);
|
|
Engine::StartTimer ("LevelIntroLevelNumber", 0.4);
|
|
Engine::StartTimer ("LevelIntroLevelTitle", 0.6);
|
|
Engine::StartTimer ("LevelIntroLevelAuthor", 0.8);
|
|
Engine::StartTimer ("LevelIntroLevelStart", 1.0);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Engine::GUI::CheckKeyPress(SDLK_ESCAPE)) {
|
|
PushViewState(ViewStatePaused);
|
|
GetModel()->SetGameState(GameStatePaused);
|
|
}
|
|
}
|
|
|
|
void View::DrawUiGameOver() {
|
|
DrawPageTitle ("Game Over");
|
|
|
|
SelectFont("console.ttf size=23 color=#ffffff");
|
|
|
|
if (GetModel()->GetPlayerLives() == 0) {
|
|
int text_xpos = screen_right * 0.5,
|
|
text_ypos = screen_bottom * 0.5 - 64;
|
|
|
|
Engine::GUI::LabelCentered(5,
|
|
"That was pathetic!",
|
|
text_xpos,
|
|
text_ypos);
|
|
|
|
const static int value_width = 10;
|
|
|
|
text_ypos += 48;
|
|
|
|
// ----- New Score -----
|
|
unsigned int player_points = GetModel()->GetPoints();
|
|
|
|
if (player_points != 0) {
|
|
Engine::GUI::LabelCentered (1, "At least you made a score of:",
|
|
text_xpos, text_ypos + 3
|
|
);
|
|
|
|
text_ypos += 32;
|
|
|
|
stringstream temp_stream;
|
|
temp_stream.str("");
|
|
|
|
temp_stream << player_points << " points.";
|
|
Engine::GUI::LabelCentered (1, temp_stream.str().c_str(),
|
|
text_xpos, text_ypos + 3
|
|
);
|
|
} else {
|
|
Engine::GUI::LabelCentered (1, "In fact, it's embarrassing, as you",
|
|
text_xpos, text_ypos + 3
|
|
);
|
|
|
|
text_ypos += 32;
|
|
Engine::GUI::LabelCentered (1, "did not even finish a single level.",
|
|
text_xpos, text_ypos + 3
|
|
);
|
|
}
|
|
|
|
text_ypos += 48;
|
|
Engine::GUI::LabelCentered (1, "Play harder!",
|
|
text_xpos, text_ypos + 3
|
|
);
|
|
|
|
} else {
|
|
Engine::GUI::LabelCentered (6, "You earned yourself the",
|
|
screen_right * 0.5,
|
|
screen_bottom * 0.5 - 32);
|
|
Engine::GUI::LabelCentered (7, "You Rock(TM) award.",
|
|
screen_right * 0.5,
|
|
screen_bottom * 0.5 + 0);
|
|
Engine::GUI::LabelCentered (8, "Go tell your friends.",
|
|
screen_right * 0.5,
|
|
screen_bottom * 0.5 + 32);
|
|
}
|
|
|
|
if (mFadeTimerSecValue > 0.)
|
|
return;
|
|
|
|
if (Engine::GUI::Button (2, "Highscores",
|
|
(screen_right - button_width) * 0.5,
|
|
screen_bottom * 0.5 + 100, button_width, button_height)) {
|
|
// We do not want the background to show the remaining bits of the game
|
|
GetModel()->SetGameState(GameStatePaused);
|
|
GetModel()->SubmitHighscoreEntry(GetModel()->GetPlayerName(), GetModel()->GetPoints());
|
|
|
|
PopViewState();
|
|
PushViewState(ViewStateShowHighscore);
|
|
}
|
|
}
|
|
|
|
void View::DrawUiLevelIntro() {
|
|
SelectFont ("console.ttf size=23");
|
|
|
|
if (VarCheatMode.GetBoolValue()) {
|
|
GetModel()->SetPlayerLives(100);
|
|
}
|
|
|
|
stringstream level_info_stream;
|
|
level_info_stream << "Level " << GetModel()->GetCurrentLevelIndex() + 1;
|
|
|
|
int level_number_dest_x = (screen_right - screen_left) * 0.5 - 180;
|
|
int level_number_dest_y = (screen_bottom - screen_top) * 0.5 - 60;
|
|
|
|
int level_number_start_x = level_number_dest_x;
|
|
int level_number_start_y = (screen_top);
|
|
|
|
int level_number_delta_x = level_number_dest_x - level_number_start_x;
|
|
int level_number_delta_y = level_number_dest_y - level_number_start_y;
|
|
|
|
Engine::GUI::Label (20, level_info_stream.str().c_str(),
|
|
level_number_dest_x - Engine::GetTimer("LevelIntroLevelNumber") * level_number_delta_x,
|
|
level_number_dest_y - Engine::GetTimer("LevelIntroLevelNumber") * level_number_delta_y
|
|
);
|
|
|
|
int level_title_dest_x = (screen_right - screen_left) * 0.5;
|
|
int level_title_dest_y = (screen_bottom) * 0.5 - 36;
|
|
|
|
int level_title_start_x = (screen_right - screen_left) * 0.5;
|
|
int level_title_start_y = (screen_bottom);
|
|
|
|
int level_title_delta_x = level_title_dest_x - level_title_start_x;
|
|
int level_title_delta_y = level_title_dest_y - level_title_start_y;
|
|
|
|
SelectFont("console.ttf size=46 color=#505050");
|
|
|
|
std::string level_title = GetModel()->GetLevelTitle();
|
|
|
|
if (level_title.size() > 24) {
|
|
// in that case we break up the level title in two lines
|
|
|
|
size_t first_line_end = level_title.find_last_of (" ", 24);
|
|
std::string first_line = level_title.substr (0, first_line_end);
|
|
std::string second_line = level_title.substr (first_line_end + 1, level_title.size());
|
|
|
|
Engine::GUI::LabelCentered (21, first_line.c_str(),
|
|
level_title_dest_x - Engine::GetTimer("LevelIntroLevelTitle") * level_title_delta_x - 2,
|
|
level_title_dest_y - Engine::GetTimer("LevelIntroLevelTitle") * level_title_delta_y + 2
|
|
);
|
|
|
|
Engine::GUI::LabelCentered (21, second_line.c_str(),
|
|
level_title_dest_x - Engine::GetTimer("LevelIntroLevelTitle") * level_title_delta_x - 2,
|
|
level_title_dest_y - Engine::GetTimer("LevelIntroLevelTitle") * level_title_delta_y + 2 + 40
|
|
);
|
|
} else {
|
|
Engine::GUI::LabelCentered (21, level_title.c_str(),
|
|
level_title_dest_x - Engine::GetTimer("LevelIntroLevelTitle") * level_title_delta_x - 2,
|
|
level_title_dest_y - Engine::GetTimer("LevelIntroLevelTitle") * level_title_delta_y + 2
|
|
);
|
|
}
|
|
|
|
SelectFont ("console.ttf size=23");
|
|
|
|
level_info_stream.str("");
|
|
level_info_stream << "by " << GetModel()->GetLevelAuthor();
|
|
|
|
int level_author_dest_x = (screen_right - screen_left) * 0.5 + 80;
|
|
int level_author_dest_y = (screen_bottom - screen_top) * 0.5 + 20;
|
|
|
|
if (level_title.size() > 24) {
|
|
level_author_dest_y += 40;
|
|
}
|
|
|
|
// draw a greyish backround behind the title which can improve
|
|
// readability
|
|
glColor4f( 1., 1., 1., 0.1);
|
|
DrawRect2D (screen_left, level_title_dest_y - 24,
|
|
screen_right - screen_left,
|
|
level_author_dest_y - level_title_dest_y - 4);
|
|
|
|
int level_author_start_x = screen_right;
|
|
int level_author_start_y = level_author_dest_y;
|
|
|
|
int level_author_delta_x = level_author_dest_x - level_author_start_x;
|
|
int level_author_delta_y = level_author_dest_y - level_author_start_y;
|
|
|
|
Engine::GUI::Label (22, level_info_stream.str().c_str(),
|
|
level_author_dest_x - Engine::GetTimer("LevelIntroLevelAuthor") * level_author_delta_x,
|
|
level_author_dest_y - Engine::GetTimer("LevelIntroLevelAuthor") * level_author_delta_y
|
|
);
|
|
|
|
if (Engine::CheckTimer("LevelIntroLevelStart")) {
|
|
if(Engine::GUI::Button (1, "Start", (screen_right - button_width) * 0.5, screen_bottom * 0.5 + 180, button_width, button_height)) {
|
|
PopViewState();
|
|
GetModel()->SetGameState(GameStateRunning);
|
|
}
|
|
}
|
|
|
|
if (Engine::GUI::CheckKeyPressed(SDLK_ESCAPE) ) {
|
|
PushViewState(ViewStatePaused);
|
|
}
|
|
}
|
|
|
|
void split_time_seconds (float time_seconds, int *minutes, int *seconds) {
|
|
float current_time = roundf(time_seconds);
|
|
|
|
*minutes = static_cast<int> (floor (current_time / 60.f));
|
|
*seconds = static_cast<int> (current_time - *minutes * 60);
|
|
}
|
|
|
|
std::string time_seconds_to_string (float time_seconds) {
|
|
stringstream time_stream;
|
|
int minutes, seconds;
|
|
split_time_seconds (time_seconds, &minutes, &seconds);
|
|
|
|
time_stream << minutes << ":";
|
|
if (seconds < 10)
|
|
time_stream << "0";
|
|
time_stream << seconds;
|
|
|
|
return time_stream.str();
|
|
}
|
|
|
|
void View::DrawUiLevelComplete() {
|
|
DrawPageTitle ("Level Complete!");
|
|
|
|
if (GetModel()->GetGameModified()) {
|
|
SelectFont("console.ttf size=23 color=#cc0000");
|
|
float width, height;
|
|
std::string message ("* UNOFFICIAL GAME * UNOFFICIAL GAME * UNOFFICIAL GAME *");
|
|
|
|
float xpos = (screen_left) + 5;
|
|
float ypos = 20;
|
|
|
|
DrawGLString (xpos, ypos, message.c_str());
|
|
|
|
ypos = screen_bottom - 4;
|
|
DrawGLString (xpos, ypos, message.c_str());
|
|
}
|
|
|
|
SelectFont ("console.ttf size=23 color=#ffffff");
|
|
|
|
stringstream temp_stream;
|
|
int minutes, seconds;
|
|
split_time_seconds (GetModel()->GetLevelTimeSeconds(), &minutes, &seconds);
|
|
|
|
int level_time_xpos, level_time_ypos;
|
|
|
|
float level_time = roundf(GetModel()->GetLevelTimeSeconds());
|
|
float level_par_time = roundf(GetModel()->GetLevelParTimeSeconds());
|
|
|
|
const static int value_width = 10;
|
|
|
|
// ----- Your Time -----
|
|
temp_stream << "Your time: " << setw(value_width) << time_seconds_to_string (level_time);
|
|
|
|
level_time_xpos = (screen_right - screen_left) * 0.5 - 170;
|
|
level_time_ypos = 250;
|
|
|
|
Engine::GUI::Label (1, temp_stream.str().c_str(),
|
|
level_time_xpos, level_time_ypos + 3
|
|
);
|
|
|
|
// ----- PAR Time -----
|
|
temp_stream.str("");
|
|
temp_stream << "PAR time: " << setw(value_width) << time_seconds_to_string (level_par_time);
|
|
|
|
level_time_ypos += 32;
|
|
|
|
Engine::GUI::Label (1, temp_stream.str().c_str(),
|
|
level_time_xpos, level_time_ypos + 3
|
|
);
|
|
|
|
// ----- Level Points -----
|
|
unsigned int level_points = GetModel()->GetLevelPoints() - GetModel()->GetLevelTimeBonusPoints();
|
|
temp_stream.str("");
|
|
temp_stream << "Level Points: " << setw(value_width) << level_points;
|
|
|
|
level_time_ypos += 32;
|
|
|
|
Engine::GUI::Label (1, temp_stream.str().c_str(),
|
|
level_time_xpos, level_time_ypos + 3
|
|
);
|
|
|
|
// ----- Bonus Points -----
|
|
unsigned int bonus_points = GetModel()->GetLevelTimeBonusPoints();
|
|
temp_stream.str("");
|
|
temp_stream << "Time Bonus: " << setw(value_width) << bonus_points;
|
|
|
|
level_time_ypos += 32;
|
|
|
|
Engine::GUI::Label (1, temp_stream.str().c_str(),
|
|
level_time_xpos, level_time_ypos + 3
|
|
);
|
|
|
|
// ----- New Score -----
|
|
unsigned int player_points = GetModel()->GetPoints();
|
|
|
|
temp_stream.str("");
|
|
temp_stream << "New Score: " << setw(value_width) << player_points;
|
|
|
|
level_time_ypos += 32;
|
|
|
|
Engine::GUI::Label (1, temp_stream.str().c_str(),
|
|
level_time_xpos, level_time_ypos + 3
|
|
);
|
|
|
|
level_time_ypos += 64;
|
|
|
|
if(Engine::GUI::Button (1, "Next level ...", (screen_right - button_width) * 0.5, level_time_ypos, button_width, button_height)) {
|
|
PopViewState();
|
|
// we have to take care when we are testing the level to not proceed to
|
|
// the next level...
|
|
if (GetViewState() == ViewStateEditor) {
|
|
GetModel()->SetGameState(GameStatePaused);
|
|
|
|
if (mEditorState == EditorStateTest) {
|
|
GetModel()->DoLoadLevel("level_edit_temp.map");
|
|
mEditorState = EditorStateUnknown;
|
|
}
|
|
} else {
|
|
PushViewState(ViewStateLevelIntro);
|
|
Engine::StartTimer ("LevelIntroLevelNumber", 0.4);
|
|
Engine::StartTimer ("LevelIntroLevelTitle", 0.6);
|
|
Engine::StartTimer ("LevelIntroLevelAuthor", 0.8);
|
|
Engine::StartTimer ("LevelIntroLevelStart", 1.0);
|
|
|
|
GetModel()->ProceedToNextLevel();
|
|
GetModel()->SetGameState(GameStatePaused);
|
|
}
|
|
}
|
|
}
|
|
|
|
void View::DrawUiGamePaused() {
|
|
DrawPageTitle ("Game Paused");
|
|
SelectFont ("console.ttf size=23");
|
|
|
|
if (Engine::GUI::Button (1, "Resume Game", screen_right * 0.5 - 100, 200, button_width, button_height)) {
|
|
PopViewState();
|
|
|
|
if (GetViewState() == ViewStateGameRunning)
|
|
GetModel()->SetGameState(GameStateRunning);
|
|
}
|
|
|
|
if (Engine::GUI::Button (2, "Options", screen_right * 0.5 - 100, 250, button_width, button_height)) {
|
|
PushViewState (ViewStateOptions);
|
|
}
|
|
|
|
if (Engine::GUI::Button (3, "Abort Game", screen_right * 0.5 - 100, 300, button_width, button_height)) {
|
|
ResetViewState();
|
|
|
|
PushViewState(ViewStateMainMenu);
|
|
GetModel()->SetGameState(GameStatePaused);
|
|
}
|
|
|
|
if (Engine::GUI::Button (4, "Quit", screen_right * 0.5 - 100, 380, button_width, button_height)) {
|
|
Engine::RunCommand("quit");
|
|
}
|
|
}
|
|
|
|
void View::DrawUiPlayerDied() {
|
|
DrawPageTitle ("You died!");
|
|
SelectFont ("console.ttf size=23");
|
|
|
|
if (mFadeTimerSecValue > 0.)
|
|
return;
|
|
|
|
if (Engine::GUI::Button (1, "Continue", screen_right * 0.5 - 100, 380, button_width, button_height)) {
|
|
PopViewState();
|
|
|
|
// we have to take care when we are testing the level to not proceed to
|
|
// the next level...
|
|
if (GetViewState() == ViewStateEditor) {
|
|
GetModel()->SetGameState(GameStatePaused);
|
|
|
|
if (mEditorState == EditorStateTest) {
|
|
GetModel()->DoLoadLevel("level_edit_temp.map");
|
|
mEditorState = EditorStateUnknown;
|
|
}
|
|
} else {
|
|
GetModel()->ReloadLevel();
|
|
GetModel()->SetGameState(GameStatePaused);
|
|
PushViewState(ViewStateLevelIntro);
|
|
Engine::StartTimer ("LevelIntroLevelNumber", 0.4);
|
|
Engine::StartTimer ("LevelIntroLevelTitle", 0.6);
|
|
Engine::StartTimer ("LevelIntroLevelAuthor", 0.8);
|
|
Engine::StartTimer ("LevelIntroLevelStart", 1.0);
|
|
}
|
|
}
|
|
}
|
|
|
|
/** \brief Draws an entry in the form <name> .... <points>
|
|
*
|
|
* The amount of dots is also computed within this function. Not necessarily
|
|
* fast, however it works for now.
|
|
*/
|
|
void View::DrawHighscoreEntry (float x, float y, float entry_width, const std::string &name, unsigned int points) {
|
|
const float width_buffer = 30.;
|
|
float width, height;
|
|
float name_width, points_value_width;
|
|
|
|
// Measure and draw the name
|
|
DrawGLStringMeasure (name.c_str(), &name_width, &height);
|
|
name_width = fabsf(name_width);
|
|
Engine::DrawGLString ( x, y, name.c_str());
|
|
|
|
// Compute the width of the points value when it is printed out
|
|
std::ostringstream points_value_stream;
|
|
points_value_stream << points;
|
|
DrawGLStringMeasure (points_value_stream.str().c_str(), &points_value_width, &height);
|
|
points_value_width = fabsf(points_value_width);
|
|
|
|
// Compute the amount of dots. This is done by iteratively adding a dot '.'
|
|
// to a stream and check whether it has the desired width.
|
|
float dots_width = 0.;
|
|
std::ostringstream dots_stream;
|
|
|
|
while (ceil(name_width) + dots_width + points_value_width + width_buffer < entry_width) {
|
|
dots_stream << ".";
|
|
DrawGLStringMeasure (dots_stream.str().c_str(), &dots_width, &height);
|
|
dots_width = fabsf(dots_width);
|
|
}
|
|
|
|
// Drawing of the dots and the points value
|
|
Engine::DrawGLString ( x + entry_width - points_value_width - dots_width - 10, y, dots_stream.str().c_str());
|
|
Engine::DrawGLString ( x + entry_width - points_value_width, y, points_value_stream.str().c_str());
|
|
}
|
|
|
|
void View::DrawUiHighscore() {
|
|
// DrawPageTitle but centered:
|
|
SelectFont("console.ttf size=46 color=#808080");
|
|
|
|
float width, height;
|
|
DrawGLStringMeasure("Highscores", &width, &height);
|
|
|
|
float xpos = (screen_right - width) * 0.5;
|
|
float ypos = 180;
|
|
DrawGLString (xpos, ypos, "Highscores");
|
|
SelectFont("console.ttf size=46 color=#ffffff");
|
|
DrawGLString (xpos, ypos, "Highscores");
|
|
|
|
if (GetModel()->GetHighscoreIsOnline()) {
|
|
SelectFont("console.ttf size=23 color=#887500");
|
|
std::string title= "-online-";
|
|
float width, height;
|
|
DrawGLStringMeasure(title.c_str(), &width, &height);
|
|
|
|
float xpos = (screen_right - width) * 0.5;
|
|
float ypos = 130;
|
|
Engine::GUI::Label (4, title.c_str(), xpos, ypos);
|
|
SelectFont("console.ttf size=23 color=#e8d500");
|
|
DrawGLString (xpos, ypos - 1, title.c_str());
|
|
} else {
|
|
SelectFont("console.ttf size=23 color=#808080");
|
|
std::string title= "-offline-";
|
|
float width, height;
|
|
DrawGLStringMeasure(title.c_str(), &width, &height);
|
|
|
|
float xpos = (screen_right - width) * 0.5;
|
|
float ypos = 130;
|
|
SelectFont("console.ttf size=23 color=#ffffff");
|
|
Engine::GUI::Label (4, title.c_str(), xpos, ypos);
|
|
}
|
|
|
|
SelectFont ("console.ttf size=23");
|
|
unsigned int entry_length = 32;
|
|
float char_width;
|
|
DrawGLStringMeasure ("M", &char_width, &height);
|
|
height = fabsf(height);
|
|
float entry_width = fabsf(char_width * entry_length);
|
|
float x = screen_right * 0.5 - entry_width * 0.5;
|
|
float y = screen_bottom * 0.5 - 8 - 128;
|
|
|
|
// then we do the drawings
|
|
y += 60;
|
|
std::list<Model::HighscoreEntry>::iterator highscore_iter = GetModel()->mHighscoreList.begin();
|
|
|
|
SetFontJustification(Engine::FontJustificationLeft);
|
|
|
|
unsigned int i = 0;
|
|
while (highscore_iter != GetModel()->mHighscoreList.end()) {
|
|
// Check whether we have to highlight an entry (such as when entering
|
|
// the name)
|
|
if (GetModel()->GetPlayerName() == highscore_iter->name
|
|
&& GetModel()->GetPoints() == highscore_iter->points) {
|
|
// we highlight the newest entry
|
|
SelectFont("console.ttf color=#e8d500 size=23");
|
|
} else {
|
|
SelectFont("console.ttf color=#ffffff size=23");
|
|
}
|
|
DrawHighscoreEntry ( x, y, entry_width, highscore_iter->name, highscore_iter->points);
|
|
|
|
// go down one line
|
|
y += height * 1.3;
|
|
|
|
i++;
|
|
highscore_iter++;
|
|
}
|
|
|
|
if (Engine::GUI::Button (1, "Back to Menu", screen_right * 0.5 - 250 * 0.5, y + 16, button_width, button_height)
|
|
|| Engine::GUI::CheckKeyPressed(SDLK_ESCAPE) ) {
|
|
// Remove the ViewStateGameRunning
|
|
|
|
while (GetViewState() != ViewStateMainMenu) {
|
|
PopViewState();
|
|
}
|
|
}
|
|
}
|
|
|
|
void View::DrawUiOptions() {
|
|
DrawPageTitle ("Options");
|
|
SelectFont ("console.ttf size=23");
|
|
|
|
Engine::GUI::Label (10, "Effects Volume: ", screen_right * 0.5 - 150, 240);
|
|
|
|
float effects_volume = Engine::GetEffectsVolume();
|
|
if (Engine::GUI::VerticalSlider (1, screen_right * 0.5 - 100, 250, 250, 16, 0., 1., effects_volume)) {
|
|
Engine::LogDebug ("Setting effects volume to: %f", effects_volume);
|
|
Engine::SetEffectsVolume(effects_volume);
|
|
}
|
|
|
|
Engine::GUI::Label (11, "Music Volume: ", screen_right * 0.5 - 150, 300);
|
|
|
|
float music_volume = Engine::GetMusicVolume();
|
|
if (Engine::GUI::VerticalSlider (2, screen_right * 0.5 - 100, 310, 250, 16, 0., 1., music_volume)) {
|
|
Engine::LogDebug ("Setting music volume to: %f", music_volume);
|
|
Engine::SetMusicVolume(music_volume);
|
|
}
|
|
|
|
bool use_online_mode = Model::UseServerHighscore.GetBoolValue();
|
|
|
|
std::string online_button_caption;
|
|
if (use_online_mode) {
|
|
online_button_caption = "Highscore: online";
|
|
} else {
|
|
online_button_caption = "Highscore: offline";
|
|
}
|
|
|
|
if (Engine::GUI::CheckButton (12, online_button_caption.c_str(), use_online_mode,
|
|
screen_right*0.5 - 130, 360,
|
|
300, button_height)) {
|
|
if (use_online_mode)
|
|
Model::UseServerHighscore.Set("no");
|
|
else
|
|
Model::UseServerHighscore.Set("yes");
|
|
}
|
|
|
|
if (Engine::GUI::Button (5, "Back", screen_right * 0.5 - 100, 480, button_width, button_height)
|
|
|| Engine::GUI::CheckKeyPressed(SDLK_ESCAPE) ) {
|
|
PopViewState();
|
|
}
|
|
}
|
|
|
|
void View::DrawUiCredits() {
|
|
// DrawPageTitle ("Credits");
|
|
SelectFont ("console.ttf size=23");
|
|
|
|
static std::string credits_content (
|
|
"_Programming, Design,\r\
|
|
_ Sounds, and Graphics\r\
|
|
Martin Felis\r\
|
|
\r\
|
|
_Top Level Designer\r\
|
|
Sir Wolle\r\
|
|
\r\
|
|
\r\
|
|
_Additional Level Design\r\
|
|
Martin Felis\r\
|
|
michi\r\
|
|
Andi\r\
|
|
Sebastian Felis\r\
|
|
Khai-Long Ho Hoang\r\
|
|
\r\
|
|
_Music\r\
|
|
DJad - Space Exploration\r\
|
|
\r\
|
|
_Libraries\r\
|
|
libSDL\r\
|
|
SDL_mixer\r\
|
|
OGLFT\r\
|
|
freetype2\r\
|
|
boost\r\
|
|
libpng\r\
|
|
\r\
|
|
Aaron D. Gifford's sha2 code\r\
|
|
\r\
|
|
_Tools\r\
|
|
GIMP\r\
|
|
Blender\r\
|
|
CMake\r\
|
|
sfxr-sdl\r\
|
|
Audacity\r\
|
|
\r\
|
|
_Special Thanks\r\
|
|
to my wonderful wife Katrina\r\
|
|
\r\
|
|
\r\
|
|
\r\
|
|
\r\
|
|
\r\
|
|
_http://www.fysx.org\r\
|
|
\r\
|
|
\r\
|
|
\r\
|
|
\r\
|
|
\r\
|
|
\r\
|
|
\r\
|
|
\r\
|
|
:created with vim.\r\
|
|
::wq\r\
|
|
\r\
|
|
EOF\r\
|
|
");
|
|
static float page_duration = 5.;
|
|
static float page_draw_duration = page_duration;
|
|
|
|
stringstream credits_stream (credits_content);
|
|
std::string line;
|
|
|
|
float xpos = 270, ypos = 200.f;
|
|
float dy = 20.f;
|
|
|
|
unsigned int index = 0;
|
|
bool first_content_line = false;
|
|
while (getline (credits_stream, line, '\r')) {
|
|
if (line.size() == 0) {
|
|
index ++;
|
|
continue;
|
|
}
|
|
|
|
if (index == mCreditsPageIndex) {
|
|
if (line[0] == '_') {
|
|
SelectFont ("console.ttf size=23 color=#e8d500");
|
|
line = line.substr (1, line.size());
|
|
first_content_line = true;
|
|
} else if (line[0] == ':') {
|
|
SelectFont ("console.ttf size=23 color=#ffffff");
|
|
line = line.substr (1, line.size());
|
|
} else {
|
|
if (first_content_line) {
|
|
ypos += 20;
|
|
first_content_line = false;
|
|
}
|
|
SelectFont ("console.ttf size=23 color=#ffffff");
|
|
}
|
|
|
|
DrawGLString (xpos, ypos, line.c_str());
|
|
ypos += dy;
|
|
} else {
|
|
continue;
|
|
}
|
|
|
|
if (index == mCreditsPageIndex && line == std::string("EOF")) {
|
|
PopViewState();
|
|
}
|
|
}
|
|
|
|
if (page_draw_duration < 0.) {
|
|
mCreditsPageIndex ++;
|
|
|
|
page_draw_duration = page_duration;
|
|
|
|
// Level contributors are shown a bit longer
|
|
if (mCreditsPageIndex == 1) {
|
|
page_draw_duration *= 1.5;
|
|
}
|
|
}
|
|
|
|
page_draw_duration -= Engine::GetFrameDuration();
|
|
|
|
if (Engine::GUI::CheckKeyPressed(SDLK_ESCAPE)
|
|
|| Engine::GUI::CheckKeyPressed(SDLK_SPACE) ) {
|
|
PopViewState();
|
|
}
|
|
}
|
|
|
|
void View::DrawUiEnterPlayername() {
|
|
DrawPageTitle ("Asteroids");
|
|
SelectFont ("console.ttf size=23");
|
|
|
|
// Enter your name
|
|
std::string player_name = GetModel()->GetPlayerName();
|
|
|
|
SelectFont("console.ttf size=23");
|
|
Engine::GUI::Label (1, "Enter your name: ", screen_right * 0.5 - 220, 250);
|
|
|
|
std::string valid_chars ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890-_!. ");
|
|
|
|
if (Engine::GUI::LineEditMasked (2, screen_right * 0.5 + 20, 238, player_name, 16, valid_chars)) {
|
|
GetModel()->SetPlayerName(player_name);
|
|
}
|
|
|
|
if (Engine::GUI::Button (3, "Start Game", screen_right - 180 - 20, 500, 180, 40)) {
|
|
PopViewState();
|
|
GetModel()->OnNewGame();
|
|
PushViewState(ViewStateGameRunning);
|
|
PushViewState(ViewStateLevelIntro);
|
|
Engine::StartTimer ("LevelIntroLevelNumber", 0.4);
|
|
Engine::StartTimer ("LevelIntroLevelTitle", 0.6);
|
|
Engine::StartTimer ("LevelIntroLevelAuthor", 0.8);
|
|
Engine::StartTimer ("LevelIntroLevelStart", 1.0);
|
|
GetModel()->SetGameState(GameStatePaused);
|
|
}
|
|
|
|
if (Engine::GUI::Button (5, "Back", 20, 500, 180, 40)
|
|
|| Engine::GUI::CheckKeyPressed(SDLK_ESCAPE) ) {
|
|
PopViewState();
|
|
}
|
|
}
|
|
|
|
void View::DrawUiEditor() {
|
|
// DrawPageTitle ("Editor");
|
|
SelectFont ("console.ttf size=23");
|
|
|
|
// The close button
|
|
if (Engine::GUI::Button (1, "X", screen_right - 48, 20, 32, button_height)
|
|
|| Engine::GUI::CheckKeyPressed(SDLK_ESCAPE)) {
|
|
|
|
if (mEditorState == EditorStateTest) {
|
|
mEditorState = EditorStateUnknown;
|
|
|
|
GetModel()->DoLoadLevel("level_edit_temp.map");
|
|
GetModel()->SetGameState(GameStatePaused);
|
|
return;
|
|
} else if (!Engine::GUI::CheckKeyPressed(SDLK_ESCAPE)){
|
|
PopViewState();
|
|
}
|
|
}
|
|
|
|
if (mEditorState != EditorStateTest) {
|
|
if (Engine::GUI::CheckButton (2, "Add", mEditorState == EditorStateAddEntity, 30, 20, 50, button_height)) {
|
|
mEditorState = EditorStateAddEntity;
|
|
Engine::LogDebug ("Editor state now Add");
|
|
return;
|
|
}
|
|
|
|
if (Engine::GUI::CheckButton (3, "Del", mEditorState == EditorStateDelEntity, 85, 20, 50, button_height)) {
|
|
mEditorState = EditorStateDelEntity;
|
|
Engine::LogDebug ("Editor state now Del");
|
|
return;
|
|
}
|
|
|
|
if (Engine::GUI::CheckButton (4, "Move", mEditorState == EditorStateMoveEntity, 140, 20, 65, button_height)) {
|
|
mEditorState = EditorStateMoveEntity;
|
|
Engine::LogDebug ("Editor state now Move");
|
|
return;
|
|
}
|
|
|
|
if (Engine::GUI::CheckButton (5, "Rot", mEditorState == EditorStateRotateEntity, 210, 20, 50, button_height)) {
|
|
mEditorState = EditorStateRotateEntity;
|
|
Engine::LogDebug ("Editor state now Move");
|
|
return;
|
|
}
|
|
|
|
if (Engine::GUI::CheckButton (6, "Spd", mEditorState == EditorStateEntityVelocity, 265, 20, 50, button_height)) {
|
|
mEditorState = EditorStateEntityVelocity;
|
|
Engine::LogDebug ("Editor state now Add");
|
|
return;
|
|
}
|
|
|
|
if (Engine::GUI::Button (7, "Save", 325, 20, 65, button_height)) {
|
|
mEditorState = EditorStateSave;
|
|
Engine::LogDebug ("Editor state now Save");
|
|
return;
|
|
}
|
|
|
|
if (Engine::GUI::Button (8, "Load", 400, 20, 65, button_height)) {
|
|
mEditorState = EditorStateLoad;
|
|
Engine::LogDebug ("Editor state now Load");
|
|
return;
|
|
}
|
|
|
|
// we only show the Test button when there is actually something to play
|
|
// (i.e. a player entity and at least one asteroid)
|
|
if (GetModel()->GetPlayerEntityId() != 0
|
|
&& GetModel()->mAsteroids.size() > 0) {
|
|
if (Engine::GUI::Button (9, "Test", 475, 20, 64, button_height)) {
|
|
mEditorState = EditorStateTest;
|
|
|
|
GetModel()->DoSaveLevel("level_edit_temp.map");
|
|
GetModel()->SetGameState(GameStateRunning);
|
|
}
|
|
}
|
|
}
|
|
|
|
std::ostringstream mouse_pos_str;
|
|
vector3d mouse_world_pos;
|
|
Controller* controller = GetController();
|
|
|
|
controller->GetMouseWorldPosition(mouse_world_pos);
|
|
mouse_pos_str << mouse_world_pos[0] << "," << mouse_world_pos[2];
|
|
|
|
if (mEditorState == EditorStateAddEntity) {
|
|
SelectFont ("console.ttf size=12");
|
|
// Engine::GUI::Label (9999, "Adding", 128, 16);
|
|
|
|
if (Engine::GUI::CheckKeyPressed(MouseButtonLeft)) {
|
|
// if there is no entity so far we create a player, otherwise we create
|
|
// an asteroid
|
|
|
|
Engine::EntityBase* entity = NULL;
|
|
if (GetModel()->GetPlayerEntityId() != Engine::NullEntityId) {
|
|
entity = Engine::CreateEntity(GameEntityTypeAsteroid);
|
|
entity->mPhysicState->SetVelocity (vector3d (0., 0., -1.));
|
|
entity->mPhysicState->SetAngleVelocity ( (rand()/float(RAND_MAX) - 0.5) * 120);
|
|
} else {
|
|
entity = Engine::CreateEntity(GameEntityTypeShip);
|
|
GetModel()->SetPlayerEntityId(entity->mId);
|
|
entity->mPhysicState->SetOrientation (vector3d (0., 90., 0.));
|
|
}
|
|
|
|
// Now we want to insert an Asteroid at the given position
|
|
entity->mPhysicState->SetPosition (vector3d (mouse_world_pos[0], 0., mouse_world_pos[2]));
|
|
}
|
|
}
|
|
|
|
if (mEditorState == EditorStateDelEntity) {
|
|
SelectFont ("console.ttf size=12");
|
|
// Engine::GUI::Label (9999, "Deleting", 128, 16);
|
|
|
|
if (Engine::GUI::CheckKeyPressed(MouseButtonLeft)) {
|
|
// Check if there is an entity near the given position
|
|
Engine::EntityBase* entity = Engine::GetEntityAt (mouse_world_pos);
|
|
|
|
if (entity && entity->mType == GameEntityTypeAsteroid) {
|
|
Engine::LogMessage ("Killing entity with id %u", entity->mId);
|
|
GetModel()->UnregisterEntity (entity->mId);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (mEditorState == EditorStateMoveEntity) {
|
|
SelectFont ("console.ttf size=12");
|
|
// Engine::GUI::Label (9999, "Moving", 128, 16);
|
|
|
|
if (Engine::GUI::CheckKeyPress(MouseButtonLeft)) {
|
|
// Check if there is an entity near the given position
|
|
Engine::EntityBase* asteroid = Engine::GetEntityAt (mouse_world_pos);
|
|
if (asteroid) {
|
|
mEditorEntityId = asteroid->mId;
|
|
}
|
|
}
|
|
|
|
if (mEditorEntityId != 0) {
|
|
Engine::EntityBase* asteroid = Engine::GetEntity (mEditorEntityId);
|
|
asteroid->mPhysicState->SetPosition (mouse_world_pos);
|
|
}
|
|
|
|
if (!Engine::GUI::CheckKeyPress(MouseButtonLeft)) {
|
|
if (mEditorEntityId != 0) {
|
|
mEditorEntityId = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (mEditorState == EditorStateRotateEntity) {
|
|
SelectFont ("console.ttf size=12");
|
|
|
|
// static vector3d mouse_start_rotate (0., 0., 0.);
|
|
static float start_angle = 0.;
|
|
if (mEditorEntityId == 0) {
|
|
if (Engine::GUI::CheckKeyPress(MouseButtonLeft)) {
|
|
// Check if there is an entity near the given position
|
|
Engine::EntityBase* entity = Engine::GetEntityAt (mouse_world_pos);
|
|
|
|
if (entity) {
|
|
mEditorEntityId = entity->mId;
|
|
vector3d mouse_start_rotate = mouse_world_pos - entity->mPhysicState->GetPosition();
|
|
start_angle = atan2 (mouse_start_rotate[0], mouse_start_rotate[2]) * 180 / M_PI - entity->mPhysicState->mOrientation[1];
|
|
} else {
|
|
mEditorEntityId = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (mEditorEntityId != 0) {
|
|
Engine::EntityBase* entity = Engine::GetEntity (mEditorEntityId);
|
|
|
|
vector3d new_velocity = mouse_world_pos - entity->mPhysicState->GetPosition();
|
|
new_velocity[1] = 0.;
|
|
float angle = atan2 (new_velocity[0], new_velocity[2]) * 180. / M_PI;
|
|
|
|
entity->mPhysicState->SetOrientation (vector3d (0., angle - start_angle, 0.));
|
|
|
|
if (!Engine::GUI::CheckKeyPress(MouseButtonLeft)) {
|
|
mEditorEntityId = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (mEditorState == EditorStateEntityVelocity) {
|
|
SelectFont ("console.ttf size=12");
|
|
// Engine::GUI::Label (9999, "Velocity", 128, 16);
|
|
|
|
if (mEditorEntityId == 0) {
|
|
if (Engine::GUI::CheckKeyPress(MouseButtonLeft)) {
|
|
// Check if there is an entity near the given position
|
|
Engine::EntityBase* asteroid = Engine::GetEntityAt (mouse_world_pos);
|
|
if (asteroid) {
|
|
mEditorEntityId = asteroid->mId;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (mEditorEntityId != 0) {
|
|
Engine::EntityBase* asteroid = Engine::GetEntity (mEditorEntityId);
|
|
|
|
vector3d new_velocity = mouse_world_pos - asteroid->mPhysicState->GetPosition();
|
|
new_velocity[1] = 0.;
|
|
asteroid->mPhysicState->SetVelocity (new_velocity);
|
|
|
|
if (!Engine::GUI::CheckKeyPress(MouseButtonLeft)) {
|
|
if (mEditorEntityId != 0) {
|
|
mEditorEntityId = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (mEditorState == EditorStateSave) {
|
|
glColor3f (0.2, 0.2, 0.2);
|
|
Engine::GUI::DrawRoundedBlock (140, 150, screen_right - 280, 280);
|
|
// Engine::GUI::Label (9999, "Saving", 128, 16);
|
|
SelectFont ("console.ttf size=23");
|
|
|
|
Engine::GUI::Label(51, "Filename: ", 145, 180);
|
|
std::string level_name = GetModel()->GetLevelName();
|
|
|
|
glColor3f (1., 1., 1.);
|
|
if (Engine::GUI::LineEdit(52, 150, 200, level_name, 31))
|
|
GetModel()->SetLevelName(level_name);
|
|
|
|
Engine::GUI::Label(53, "Author: ", 145, 250);
|
|
std::string level_author = GetModel()->GetLevelAuthor();
|
|
if (Engine::GUI::LineEdit(531, 150, 270, level_author, 31))
|
|
GetModel()->SetLevelAuthor(level_author);
|
|
|
|
Engine::GUI::Label(54, "Level Title: ", 145, 320);
|
|
std::string level_title = GetModel()->GetLevelTitle();
|
|
if (Engine::GUI::LineEdit(541, 150, 340, level_title, 31))
|
|
GetModel()->SetLevelTitle(level_title);
|
|
|
|
if (Engine::GUI::Button (55, "Save", 145, 380, button_width, button_height)) {
|
|
GetModel()->DoSaveLevel((level_name + std::string(".map")).c_str());
|
|
Engine::LogMessage ("Save");
|
|
mEditorState = EditorStateUnknown;
|
|
}
|
|
|
|
if (Engine::GUI::Button (56, "Cancel", screen_right - 140 - 5 - button_width, 380, button_width, button_height))
|
|
mEditorState = EditorStateUnknown;
|
|
}
|
|
|
|
if (mEditorState == EditorStateLoad) {
|
|
glColor3f (0.2, 0.2, 0.2);
|
|
Engine::GUI::DrawRoundedBlock (140, 150, screen_right - 280, 200);
|
|
// Engine::GUI::Label (9999, "Loading", 128, 16);
|
|
SelectFont ("console.ttf size=23");
|
|
|
|
Engine::GUI::Label(51, "Filename: ", 145, 180);
|
|
std::string level_name = GetModel()->GetLevelName();
|
|
|
|
glColor3f (1., 1., 1.);
|
|
if (Engine::GUI::LineEdit(52, 145, 210, level_name, 32))
|
|
GetModel()->SetLevelName(level_name);
|
|
|
|
if (Engine::FileExists (level_name + std::string(".map"))) {
|
|
if (Engine::GUI::Button (54, "Load", 145, 300, button_width, button_height)) {
|
|
GetModel()->DoLoadLevel((level_name + std::string(".map")).c_str());
|
|
Engine::LogMessage ("Load");
|
|
mEditorState = EditorStateUnknown;
|
|
}
|
|
}
|
|
|
|
if (Engine::GUI::Button (55, "Cancel", screen_right - 140 - 5 - button_width, 300, button_width, button_height))
|
|
mEditorState = EditorStateUnknown;
|
|
}
|
|
|
|
if (Engine::GUI::CheckKeyPressed(SDLK_ESCAPE)) {
|
|
if (mEditorState != EditorStateUnknown)
|
|
mEditorState = EditorStateUnknown;
|
|
}
|
|
|
|
if (Engine::GUI::CheckKeyPressed(MouseButtonRight)
|
|
|| Engine::GUI::CheckKeyPressed(SDLK_ESCAPE) ) {
|
|
mEditorState = EditorStateUnknown;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Entities
|
|
*/
|
|
void View::DrawEntity (Engine::EntityBase *entity) {
|
|
if (entity->mType == GameEntityTypeAsteroid)
|
|
DrawAsteroid ((AsteroidEntity*) entity);
|
|
else if (entity->mType == GameEntityTypeShip)
|
|
DrawShip ((ShipEntity*) entity);
|
|
else if (entity->mType == GameEntityTypeRocket)
|
|
DrawRocket ((RocketEntity*) entity);
|
|
else if (entity->mType == GameEntityTypeShipPart)
|
|
DrawShipPart (entity);
|
|
else {
|
|
Engine::LogError ("Cannot draw entity: unknown type '%d'", entity->mType);
|
|
}
|
|
|
|
}
|
|
|
|
/// \todo: Update of the animation ??
|
|
void View::DrawShip (ShipEntity *ship) {
|
|
if (!ship->mAlive)
|
|
return;
|
|
|
|
mShipSprite.SetScale (2. * ship->mPhysicState->mRadius / mShipSprite.GetHeight());
|
|
mShipThrustSprite.SetScale (2. * ship->mPhysicState->mRadius / mShipSprite.GetHeight());
|
|
|
|
if (ship->mState == ShipEntity::Accelerating) {
|
|
mShipThrustSprite.UpdateAnimation (Engine::GetFrameDuration());
|
|
mShipThrustSprite.DrawAt(-0.5, 0., 0.);
|
|
}
|
|
|
|
mShipSprite.DrawAt(0., 0., 0.);
|
|
|
|
#ifdef DRAW_BOUNDARIES
|
|
glColor3f (1., 1., 1.);
|
|
DrawCircle (ship->mPhysicState->mRadius, 20);
|
|
#endif
|
|
}
|
|
|
|
void View::DrawAsteroid (AsteroidEntity *asteroid) {
|
|
mAsteroidSprite.SetScale (2. * asteroid->mPhysicState->mRadius / mAsteroidSprite.GetWidth());
|
|
mAsteroidSprite.DrawAt(0., 0., 0.);
|
|
|
|
#ifdef DRAW_BOUNDARIES
|
|
glColor3f (1., 1., 1.);
|
|
DrawCircle (asteroid->mPhysicState->mRadius, 20);
|
|
#endif
|
|
}
|
|
|
|
void View::DrawRocket (RocketEntity *rocket) {
|
|
glColor3f (1., 1., 1.);
|
|
glBegin (GL_QUADS);
|
|
glVertex3f (-0.25, 0., 0.05);
|
|
glVertex3f (0.05, 0., 0.05);
|
|
glVertex3f (0.05, 0., -0.05);
|
|
glVertex3f (-0.25, 0., -0.05);
|
|
glEnd ();
|
|
}
|
|
|
|
void View::DrawShipPart (Engine::EntityBase *entity) {
|
|
unsigned int i;
|
|
mShipPartsSprite.SetScale (1. / mShipSprite.GetHeight());
|
|
|
|
for (i = 0; i < mShipPartsEntityIds.size(); i++) {
|
|
if (mShipPartsEntityIds.at(i) == entity->mId) {
|
|
mShipPartsSprite.DrawSubAt (i, 0., 0., 0.);
|
|
}
|
|
}
|
|
#ifdef DRAW_BOUNDARIES
|
|
glColor3f (1., 1., 1.);
|
|
DrawCircle (entity->mPhysicState->mRadius, 20);
|
|
#endif
|
|
}
|
|
|
|
}
|