Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
143 KB
Referenced Files
None
Subscribers
None
This document is not UTF8. It was detected as JIS and converted to UTF8 for display.
diff --git a/src/Demo.cpp b/src/Demo.cpp
index 98594c8..8822a3e 100644
--- a/src/Demo.cpp
+++ b/src/Demo.cpp
@@ -1,440 +1,438 @@
/***************************************************************************
Demo.cpp - description
-------------------
begin : Wed Aug 16 22:18:47 CEST 2003
copyright : (C) 2003 by upi
email : upi@apocalypse.rulez.org
***************************************************************************/
#include "FlyingChars.h"
#include "SDL.h"
#include "State.h"
#include "gfx.h"
#include "common.h"
#include "Backend.h"
#include "RlePack.h"
#include "FighterStats.h" // #includes Demo.h
+#include "Event.h"
#include "config.h"
Demo::Demo()
{
m_poFlyingChars = NULL;
m_bAdvanceGame = false;
}
Demo::~Demo()
{
delete m_poFlyingChars;
m_poFlyingChars = NULL;
}
int Demo::Advance( int a_iNumFrames, bool a_bFlip )
{
int iRetVal = 1;
if ( a_iNumFrames > 5 )
a_iNumFrames = 5;
if ( m_poBackground )
{
SDL_BlitSurface( m_poBackground, NULL, gamescreen, NULL );
}
if ( m_poFlyingChars )
{
iRetVal &= AdvanceFlyingChars( a_iNumFrames );
m_poFlyingChars->Draw();
}
if ( m_bAdvanceGame )
{
iRetVal &= AdvanceGame( a_iNumFrames );
//@ DRAW GAME?
}
if ( a_bFlip )
{
SDL_Flip( gamescreen );
}
return iRetVal;
}
int Demo::AdvanceFlyingChars( int a_iNumFrames )
{
m_poFlyingChars->Advance( a_iNumFrames );
return ( m_poFlyingChars->IsDone() ? 1 : 0 );
}
int Demo::AdvanceGame( int a_iNumFrames )
{
for ( int i=0; i<a_iNumFrames; ++i )
{
g_oBackend.AdvancePerl();
}
return 0;
}
int Demo::Run()
{
SState::TGameMode enOriginalGameMode = g_oState.m_enGameMode;
int thisTick, lastTick, firstTick, gameSpeed;
- SDL_Event event;
gameSpeed = 12;
+ /*
if ( m_poBackground )
{
DrawTextMSZ( "Press Escape for the menu", impactFont, 10, 450, UseShadow, C_WHITE, m_poBackground );
}
+ */
thisTick = SDL_GetTicks() / gameSpeed;
lastTick = thisTick - 1;
firstTick = SDL_GetTicks() / gameSpeed;
while ( 1 )
{
// 1. Wait for the next tick (on extremely fast machines..)
while (1)
{
thisTick = SDL_GetTicks() / gameSpeed;
if ( thisTick==lastTick )
{
SDL_Delay(1);
}
else
{
break;
}
}
// 2. Call ADVANCE.
int iRetVal = Advance(thisTick-lastTick, true);
lastTick = thisTick;
if ( iRetVal )
{
return 0;
}
// 3. Handle events.
- while (SDL_PollEvent(&event))
+ SMortalEvent oEvent;
+
+ while ( MortalPollEvent(oEvent) )
{
- switch (event.type)
+ switch (oEvent.m_enType)
{
- case SDL_QUIT:
+ case Me_QUIT:
g_oState.m_bQuitFlag = true;
break;
- case SDL_KEYDOWN:
- if ( event.key.keysym.sym == SDLK_ESCAPE )
- {
- OnMenu();
- break;
- }
- if ( event.key.keysym.sym == SDLK_F1 )
- {
- return 0;
- }
- for ( int i=0; i<2; ++i )
- {
- for ( int j=0; j<9; ++j )
- {
- if ( g_oState.m_aiPlayerKeys[i][j] == event.key.keysym.sym)
- {
- g_oState.m_enGameMode = SState::IN_MULTI;
- }
- }
- }
+
+ case Me_MENU:
+ case Me_PLAYERKEYDOWN:
+ OnMenu();
+ break;
+
+ case Me_SKIP:
+ return 0;
+
+ case Me_NOTHING:
+ case Me_PLAYERKEYUP:
break;
+
} // switch
- } // while SDL_PollEvent
+ } // while MortalPollEvent
if ( g_oState.m_enGameMode != enOriginalGameMode
|| g_oState.m_bQuitFlag )
{
return 1;
}
} // while 1;
}
void Demo::OnMenu()
{
::DoMenu();
}
class CreditsDemo: public Demo
{
public:
CreditsDemo()
{
m_poBackground = LoadBackground( "Credits.png", 240 );
SDL_UnlockSurface( m_poBackground );
DrawGradientText( "Credits", titleFont, 20, m_poBackground );
SDL_Flip( m_poBackground );
SDL_Rect oRect;
oRect.x = 110; oRect.w = gamescreen->w - 220;
oRect.y = 100; oRect.h = 350;
m_poFlyingChars = new FlyingChars( creditsFont, oRect );
m_sText1 = Translate( "CreditsText1" );
m_sText2 = Translate( "CreditsText2" );
m_sText3 = Translate( "CreditsText3" );
m_poFlyingChars->AddText( m_sText1.c_str(), FlyingChars::FC_AlignCenter, true );
m_poFlyingChars->AddText( m_sText2.c_str(), FlyingChars::FC_AlignJustify, true );
m_poFlyingChars->AddText( m_sText3.c_str(), FlyingChars::FC_AlignCenter, true );
m_poFlyingChars->AddText( "\n\n\n\n\n\n:)", FlyingChars::FC_AlignRight, true );
}
protected:
std::string m_sText1;
std::string m_sText2;
std::string m_sText3;
};
class Story1Demo: public Demo
{
public:
Story1Demo()
{
m_poBackground = LoadBackground( "Story1.png", 240 );
SDL_UnlockSurface( m_poBackground );
SDL_Rect oRect;
oRect.x = 50; oRect.w = gamescreen->w - 100;
oRect.y = 50; oRect.h = gamescreen->h - 100;
m_poFlyingChars = new FlyingChars( storyFont, oRect, -1 );
m_sText1 = Translate( "Story1Text" );
m_poFlyingChars->AddText( m_sText1.c_str(), FlyingChars::FC_AlignJustify, true );
}
protected:
std::string m_sText1;
};
class Story2Demo: public Demo
{
public:
Story2Demo()
{
m_poBackground = LoadBackground( "Story2.png", 240 );
SDL_UnlockSurface( m_poBackground );
SDL_Rect oRect;
oRect.x = 50; oRect.w = gamescreen->w - 100;
oRect.y = 50; oRect.h = gamescreen->h - 100;
m_poFlyingChars = new FlyingChars( storyFont, oRect, -1 );
m_sText1 = Translate( "Story2Text" );
m_poFlyingChars->AddText( m_sText1.c_str(), FlyingChars::FC_AlignJustify, true );
}
protected:
std::string m_sText1;
};
class MainScreenDemo: public Demo
{
public:
MainScreenDemo()
{
i = 0;
m_iTimeLeft = 50;
m_poBackground = LoadBackground( "Mortal.png", 240 );
- DrawTextMSZ( VERSION, inkFont, 540, 430, UseShadow | AlignHCenter, C_WHITE, m_poBackground, false );
+
+ DrawTextMSZ( "Version " VERSION " ゥ 2003-2004 by UPi", inkFont, 320, 430, UseShadow | AlignHCenter, C_WHITE, m_poBackground, false );
+
std::string sStaffFilename = DATADIR;
sStaffFilename += "/characters/STAFF.DAT";
m_poPack = new RlePack( sStaffFilename.c_str(), 240 );
m_poPack->ApplyPalette();
SDL_BlitSurface( m_poBackground, NULL, gamescreen, NULL );
SDL_Flip( gamescreen );
int j, k, l;
for ( j=0; j<14; ++j )
{
m_aiOrder[j] = j;
m_bShown[j] = false;
}
for ( j=0; j<14; ++j )
{
k = rand() % 14;
l = m_aiOrder[j]; m_aiOrder[j] = m_aiOrder[k]; m_aiOrder[k] = l;
}
}
~MainScreenDemo()
{
delete m_poPack;
m_poPack = NULL;
}
int Advance( int a_iNumFrames, bool a_bFlip )
{
static int x[14] = {
0, 26, 67, 125, 159, 209,
249, 289, 358, 397, 451, 489, 532, 161 };
static int y[14] = {
5, 4, 5, 5, 5, 7,
4, 0, 7, 5, 5, 6, 5, 243 };
m_iTimeLeft -= a_iNumFrames;
if ( m_iTimeLeft <= 0
&& i >= 14 )
{
return 1;
}
if ( m_iTimeLeft <= 0 )
{
m_bShown[ m_aiOrder[i] ] = true;
for ( int j=0; j<=14; ++j )
{
if ( m_bShown[j] )
{
m_poPack->Draw( j, x[j], y[j], false );
}
}
SDL_Flip( gamescreen );
++i;
m_iTimeLeft += 20;
if ( i >= 14 )
{
m_iTimeLeft += 50;
}
}
return 0;
}
protected:
RlePack* m_poPack;
int m_iTimeLeft;
int i;
int m_aiOrder[14];
bool m_bShown[14];
};
void DoReplayDemo()
{
static int aiOrder[6] = {-1, -1, -1, -1, -1, -1};
static int iNext = 0;
if ( aiOrder[0]<0 )
{
// shuffle
int i, j, k;
for ( i=0; i<6; ++i ) aiOrder[i]=i;
for ( i=0; i<6; ++i )
{
j = rand() % 6;
k = aiOrder[i];
aiOrder[i] = aiOrder[j];
aiOrder[j] = k;
}
iNext = 0;
}
char acFilename[1024];
sprintf( acFilename, DATADIR "/demo%d.om", aiOrder[iNext] );
// DoGame( acFilename, true, false );
iNext = ( iNext + 1 ) % 6;
}
static bool g_bFirstTime = true;
void DoDemos()
{
#define DoDemos_BREAKONEND \
if ( g_oState.m_enGameMode != SState::IN_DEMO \
|| g_oState.m_bQuitFlag ) \
return;
if ( g_bFirstTime )
{
g_bFirstTime = false;
}
else
{
MainScreenDemo oDemo;
oDemo.Run();
}
while (1)
{
DoDemos_BREAKONEND;
DoReplayDemo();
DoDemos_BREAKONEND;
{
Story1Demo oDemo;
oDemo.Run();
}
DoDemos_BREAKONEND;
DoReplayDemo();
DoDemos_BREAKONEND;
{
FighterStatsDemo oDemo;
oDemo.Run();
}
DoDemos_BREAKONEND;
DoReplayDemo();
DoDemos_BREAKONEND;
{
Story2Demo oDemo;
oDemo.Run();
}
DoDemos_BREAKONEND;
{
FighterStatsDemo oDemo;
oDemo.Run();
}
DoDemos_BREAKONEND;
DoReplayDemo();
DoDemos_BREAKONEND;
{
CreditsDemo oDemo;
oDemo.Run();
}
DoDemos_BREAKONEND;
{
MainScreenDemo oDemo;
oDemo.Run();
}
DoDemos_BREAKONEND;
}
}
diff --git a/src/Event.h b/src/Event.h
new file mode 100644
index 0000000..6c0d9f1
--- /dev/null
+++ b/src/Event.h
@@ -0,0 +1,51 @@
+/***************************************************************************
+ Event.h - description
+ -------------------
+ begin : Sat Feb 14 2004
+ copyright : (C) 2004 by upi
+ email : upi@feel
+ ***************************************************************************/
+
+
+#ifndef EVENT_H
+#define EVENT_H
+
+
+enum TMortalEventEnum
+{
+ Me_NOTHING,
+ Me_QUIT,
+ Me_MENU,
+ Me_SKIP,
+ Me_PLAYERKEYDOWN,
+ Me_PLAYERKEYUP,
+};
+
+
+enum TMortalKeysEnum
+{
+ Mk_UP = 0,
+ Mk_DOWN = 1,
+ Mk_LEFT = 2,
+ Mk_RIGHT = 3,
+ Mk_BLOCK = 4,
+ Mk_LPUNCH = 5,
+ Mk_HPUNCH = 6,
+ Mk_LKICK = 7,
+ Mk_HKICK = 8,
+};
+
+struct SMortalEvent
+{
+ TMortalEventEnum m_enType;
+ int m_iPlayer;
+ int m_iKey;
+};
+
+bool TranslateEvent( const SDL_Event* a_poInSDLEvent, SMortalEvent* a_poOutEvent );
+bool MortalPollEvent( SMortalEvent& a_roOutEvent );
+void MortalWaitEvent( SMortalEvent& a_roOutEvent );
+
+
+#endif
+
diff --git a/src/Game.cpp b/src/Game.cpp
index e37303c..b0c243e 100644
--- a/src/Game.cpp
+++ b/src/Game.cpp
@@ -1,1093 +1,1066 @@
/***************************************************************************
Game.cpp - description
-------------------
begin : Mon Sep 24 2001
copyright : (C) 2001 by upi
email : upi@apocalypse.rulez.org
***************************************************************************/
#include <string.h>
#include <stdio.h>
#include "SDL_image.h"
#include "sge_surface.h"
#include "sge_primitives.h"
#include "sge_bm_text.h"
#include "SDL_events.h"
#include "SDL_keysym.h"
#include <fstream>
+#include "Event.h"
#include "PlayerSelect.h"
#include "Background.h"
#include "common.h"
#include "gfx.h"
#include "Backend.h"
#include "RlePack.h"
#include "State.h"
#include "Game.h"
#include "Audio.h"
#include "MortalNetwork.h"
#include "MszPerl.h"
extern PerlInterpreter* my_perl;
int Game::mg_iBackgroundNumber = 1;
/*
GAME PALETTE
From To Num Desc
---------------------------------------
0 .. 63 64 Background
64 .. 111 48 Doodads
112 .. 175 64 1st Fighter
176 .. 239 64 2nd Fighter
240 .. 255 16 basic colors
*/
#define MAXFRAMESKIP 5
/***************************************************************************
SFpsCounter CLASS
***************************************************************************/
struct SFpsCounter
{
int m_iLastCheck; // Last second then Tick() was called
int m_iFrames; // The number of frames in this second so far
int m_iFps; // The number of frames in the last second
void Reset()
{
m_iLastCheck = m_iFrames = m_iFps = 0;
}
void Tick()
{
int iSecond = SDL_GetTicks() / 1000;
if ( iSecond > m_iLastCheck )
{
m_iLastCheck = iSecond;
m_iFps = m_iFrames;
m_iFrames = 0;
// fprintf( stderr, "%d ", m_iFps);
}
++m_iFrames;
}
} oFpsCounter;
/***************************************************************************
CKeyQueue CLASS
***************************************************************************/
CKeyQueue::CKeyQueue()
{
Reset();
}
CKeyQueue::~CKeyQueue() {}
void CKeyQueue::Reset()
{
m_oKeys.clear();
}
void CKeyQueue::EnqueueKey( int a_iAtTime, int a_iPlayer, int a_iKey, bool a_bDown )
{
debug( "EnqueueKey( %d, %d, %d, %d ) at %d\n", a_iAtTime, a_iPlayer, a_iKey, a_bDown, g_oBackend.m_iGameTick );
SEnqueuedKey oKey;
oKey.iTime = a_iAtTime;
oKey.iPlayer = a_iPlayer;
oKey.iKey = a_iKey;
oKey.bDown = a_bDown;
if ( m_oKeys.size() == 0 )
{
m_oKeys.push_front( oKey );
return;
}
// Try to find the appropriate time in the list
// We maintain the list so that it is sorted in a descending time
// order. This means that usually we enqueue keys at the front and
// dequeue them at the end, but sometimes a key is inserted in mid-queue.
TEnqueuedKeyList::iterator it;
for ( it=m_oKeys.begin(); it!=m_oKeys.end(); ++it )
{
if ( it->iTime <= a_iAtTime )
{
m_oKeys.insert( it, oKey );
return;
}
}
// a_iAtTime is smaller than any time in the queue, so it goes to the end.
m_oKeys.push_back( oKey );
}
/**
If
*/
void CKeyQueue::DequeueKeys( int a_iToTime )
{
while ( m_oKeys.size() > 0
&& m_oKeys.back().iTime <= a_iToTime )
{
SEnqueuedKey& roKey = m_oKeys.back();
debug( "Dequeued key at %d tick: %d time, %d player, %d key, %d down\n", a_iToTime, roKey.iTime, roKey.iPlayer, roKey.iKey, roKey.bDown );
g_oBackend.PerlEvalF( roKey.bDown ? "KeyDown(%d,%d);" : "KeyUp(%d,%d);", roKey.iPlayer, roKey.iKey );
m_oKeys.pop_back();
}
}
/***************************************************************************
GAME PUBLIC METHODS
***************************************************************************/
Game::Game( bool a_bIsReplay, bool a_bDebug)
{
m_bIsReplay = a_bIsReplay;
m_bDebug = a_bDebug;
m_enInitialGameMode = g_oState.m_enGameMode;
m_poBackground = new Background();
m_poBackground->Load(mg_iBackgroundNumber++);
if ( !m_poBackground->IsOK() )
{
m_poBackground->Load(1);
mg_iBackgroundNumber = 1;
}
m_poDoodads = LoadBackground( "Doodads.png", 48, 64 );
m_aiRoundsWonByPlayer[0] = m_aiRoundsWonByPlayer[1] = 0;
m_iNumberOfRounds = 0;
SDL_EnableUNICODE( 0 );
m_iEnqueueDelay = 10;
}
Game::~Game()
{
delete m_poBackground;
m_poBackground = NULL;
SDL_FreeSurface( m_poDoodads );
m_poDoodads = NULL;
}
/** Runs a whole game, with two or three rounds.
\retval 0 if player 1 has won.
\retval 1 if player 2 has won.
\retval -1 if the game was a draw.
*/
int Game::Run()
{
do
{
m_sReplayString = "";
m_aReplayOffsets.clear();
DoOneRound();
if ( g_oState.m_bQuitFlag
|| m_enInitialGameMode != g_oState.m_enGameMode )
{
return -1;
}
} while ( m_aiRoundsWonByPlayer[0] < 2
&& m_aiRoundsWonByPlayer[1] < 2
&& m_iNumberOfRounds < 3 );
if ( m_aiRoundsWonByPlayer[1] > m_aiRoundsWonByPlayer[0] ) return 1;
if ( m_aiRoundsWonByPlayer[1] < m_aiRoundsWonByPlayer[0] ) return 0;
return -1;
}
/** Returns the replay string of the last round.
*/
std::string& Game::GetReplay()
{
return m_sReplayString;
}
/***************************************************************************
GAME DRAWING METHODS
***************************************************************************/
/** Draws the hitpoint bars that are displayed on the top of the screen.
Also draws the fighter names below the bars.
Input variables:
\li g_oBackend.m_aoPlayers[x].m_iHitPoints
\li g_oPlayerSelect.GetFighterName
*/
void Game::DrawHitPointDisplay()
{
int hp1 = g_oBackend.m_aoPlayers[0].m_iHitPoints;// * 100 / g_oState.m_iHitPoints;
int hp2 = g_oBackend.m_aoPlayers[1].m_iHitPoints;// * 100 / g_oState.m_iHitPoints;
SDL_Rect src, dst;
src.y = 154;
src.h = 20;
dst.y = 15;
// Player 1, green part.
dst.x = 40;
src.x = 0;
src.w = hp1*2;
SDL_BlitSurface( m_poDoodads, &src, gamescreen, &dst );
// Player 1, red part.
dst.x += hp1*2;
src.x = (100 + hp1)*2;
src.w = (100-hp1)*2;
SDL_BlitSurface( m_poDoodads, &src, gamescreen, &dst );
// Player 2, red part.
dst.x = 400;
src.x = 200;
src.w = (100-hp2)*2;
SDL_BlitSurface( m_poDoodads, &src, gamescreen, &dst );
// Player 2, green part.
dst.x = 400 + (100-hp2)*2;
src.x = (100-hp2)*2;
src.w = hp2*2;
SDL_BlitSurface( m_poDoodads, &src, gamescreen, &dst );
// "Won" icon for Player 1
src.x = 0; src.y = 276; src.w = 32; src.h = 32;
if ( m_aiRoundsWonByPlayer[0] > 0 )
{
dst.x = 4; dst.y = 11;
SDL_BlitSurface( m_poDoodads, &src, gamescreen, &dst );
}
if ( m_aiRoundsWonByPlayer[1] > 0 )
{
dst.x = 604; dst.y = 11;
SDL_BlitSurface( m_poDoodads, &src, gamescreen, &dst );
}
int iTextX = 230 - g_oPlayerSelect.GetFighterNameWidth(0);
if ( iTextX < 5 ) iTextX = 5;
sge_BF_textout( gamescreen, fastFont, g_oPlayerSelect.GetFighterName(0),
iTextX, 38 );
iTextX = g_oPlayerSelect.GetFighterNameWidth(1);
iTextX = iTextX < (635-410) ? 410 : 635-iTextX;
sge_BF_textout( gamescreen, fastFont, g_oPlayerSelect.GetFighterName(1),
iTextX, 38 );
}
/** Draws the background, using the m_poBackground object.
*/
void Game::DrawBackground()
{
m_poBackground->Draw( g_oBackend.m_iBgX, g_oBackend.m_iBgY );
}
/** In debug mode, this method is used to draw the frame of the fighters.
\param a_sName The name of the polygon (in the perl namespace)
\param a_iColor The game color to draw the polygon with.
*/
void Game::DrawPoly( const char* a_pcName, int a_iColor )
{
AV *poList;
int n;
poList = get_av( a_pcName, FALSE );
if ( poList == NULL )
{
return;
}
n = av_len( poList ) + 1;
if ( n< 2 )
{
return;
}
for ( int i=0; i<n; i += 2 )
{
int j = (i+2) % n;
int x1 = SvIV( *av_fetch( poList, i, false) );
int y1 = SvIV( *av_fetch( poList, i+1, false) );
int x2 = SvIV( *av_fetch( poList, j, false) );
int y2 = SvIV( *av_fetch( poList, j+1, false) );
sge_Line( gamescreen, x1, y1, x2, y2, a_iColor ) ;
}
}
/** Draws every doodad that is currently defined in the backend.
*/
void Game::DrawDoodads()
{
for ( int i=0; i<g_oBackend.m_iNumDoodads; ++i )
{
Backend::SDoodad& roDoodad = g_oBackend.m_aoDoodads[i];
if ( 0 == roDoodad.m_iType )
{
// Handle text doodads
const char *s = roDoodad.m_sText.c_str();
int iWidth = sge_BF_TextSize(fastFont, s).w;
int iDoodadX = roDoodad.m_iX - iWidth/2;
if ( iDoodadX + iWidth > 640 ) iDoodadX = 640 - iWidth;
if ( iDoodadX < 0 ) iDoodadX = 0;
int iDoodadY = roDoodad.m_iY;
sge_BF_textout( gamescreen, fastFont, s, iDoodadX, iDoodadY );
continue;
}
if ( roDoodad.m_iGfxOwner < 2 )
{
g_oPlayerSelect.GetPlayerInfo(roDoodad.m_iGfxOwner).m_poPack->Draw(
roDoodad.m_iFrame, roDoodad.m_iX, roDoodad.m_iY, roDoodad.m_iDir < 1 );
continue;
}
SDL_Rect rsrc, rdst;
rdst.x = roDoodad.m_iX;
rdst.y = roDoodad.m_iY;
rsrc.x = 64 * roDoodad.m_iFrame;
rsrc.y = 0;
rsrc.w = 64;
rsrc.h = 64;
SDL_BlitSurface( m_poDoodads, &rsrc, gamescreen, &rdst );
//debug( "Doodad x: %d, y: %d, t: %d, f: %d\n", dx, dy, dt, df );
}
}
/** Draws the entire game screen:
\li First, the background.
\li The players.
\li The debug wireframes (if debugging is turned on)
\li The doodads.
\li The hitpoint display.
\li The gametime display.
\li The FPS display.
\li The "Round x" text during Ph_Start
Input:
\li m_enGamePhase
\li g_oBackend.m_iGameTime
\li m_iNumberOfRounds
\li oFpsCounter
*/
void Game::Draw()
{
#define GROUNDZERO 440
DrawBackground();
// DRAW THE SHADOWS
int i;
for ( i=0; i<2; ++i )
{
Backend::SPlayer& roPlayer = g_oBackend.m_aoPlayers[i];
int iFrame = roPlayer.m_iFrame;
if ( iFrame == 0 )
continue;
RlePack* poPack = g_oPlayerSelect.GetPlayerInfo(i).m_poPack;
int w = poPack->GetWidth( ABS(iFrame)-1 );
int h = poPack->GetHeight( ABS(iFrame)-1 );
h = GROUNDZERO - ( h + roPlayer.m_iY ); // Distance of feet from ground
if ( h < 0 ) h = 0;
if ( h > 500 ) h = 500;
h = 500 - h;
int h2 = 15 * h / 500;
h = ( w / 2 ) * h / 500;
sge_FilledEllipse( gamescreen,
g_oBackend.m_aoPlayers[i].m_iX + w/2, GROUNDZERO,
h, h2, C_BLACK );
}
for ( i=0; i<2; ++i )
{
Backend::SPlayer& roPlayer = g_oBackend.m_aoPlayers[i];
int iFrame = roPlayer.m_iFrame;
if ( iFrame == 0 )
continue;
RlePack* poPack = g_oPlayerSelect.GetPlayerInfo(i).m_poPack;
poPack->Draw( ABS(iFrame)-1, roPlayer.m_iX, roPlayer.m_iY, iFrame<0 );
}
if ( m_bDebug )
{
DrawPoly( "p1head", C_LIGHTRED );
DrawPoly( "p1body", C_LIGHTGREEN );
DrawPoly( "p1legs", C_LIGHTBLUE );
DrawPoly( "p1hit", C_YELLOW );
DrawPoly( "p2head", C_LIGHTRED );
DrawPoly( "p2body", C_LIGHTGREEN );
DrawPoly( "p2legs", C_LIGHTBLUE );
DrawPoly( "p2hit", C_YELLOW );
}
DrawDoodads();
DrawHitPointDisplay();
if ( Ph_NORMAL == m_enGamePhase )
{
char s[100];
sprintf( s, "%d", m_iGameTime ); // m_iGameTime is maintained by DoGame
DrawTextMSZ( s, inkFont, 320, 10, AlignHCenter, C_LIGHTCYAN, gamescreen, false );
}
else if ( Ph_START == m_enGamePhase )
{
char s[100];
const char* format = Translate( "Round %d" );
sprintf( s, format, m_iNumberOfRounds+1 );
DrawTextMSZ( s, inkFont, 320, 200, AlignHCenter, C_WHITE, gamescreen, false );
}
else if ( Ph_REWIND == m_enGamePhase )
{
DrawTextMSZ( "REW", inkFont, 320, 10, AlignHCenter, C_WHITE, gamescreen );
sge_BF_textout( gamescreen, fastFont, Translate("Press F1 to skip..."), 230, 450 );
}
else if ( Ph_SLOWFORWARD == m_enGamePhase )
{
DrawTextMSZ( "REPLAY", inkFont, 320, 10, AlignHCenter, C_WHITE, gamescreen );
sge_BF_textout( gamescreen, fastFont, Translate("Press F1 to skip..."), 230, 450 );
}
else if ( Ph_REPLAY == m_enGamePhase )
{
DrawTextMSZ( "DEMO", inkFont, 320, 10, AlignHCenter, C_WHITE, gamescreen );
}
if ( oFpsCounter.m_iFps > 0 )
{
sge_BF_textoutf( gamescreen, fastFont, 2, 2, "%d fps", oFpsCounter.m_iFps );
}
SDL_Flip( gamescreen );
}
/***************************************************************************
GAME PROTECTED METHODS
***************************************************************************/
bool Game::IsNetworkGame()
{
return SState::IN_NETWORK == g_oState.m_enGameMode;
}
/** Returns true if we control our own data, or false if the network supplies
us with game data. */
bool Game::IsMaster()
{
return !IsNetworkGame() || g_poNetwork->IsMaster();
}
/**
This method reads and updates the game's variables. In replay mode,
this is done by parsing the replay string. Otherwise the perl
backend is advanced the given number of steps.
Whichever the case, the variables will be available in g_oBackend.
Only the backend-driven variables are modified, the GamePhase and
GameTime remain unchanged; these are up for DoOneRound and friends
to modify.
*/
void Game::Advance( int a_iNumFrames )
{
if ( m_bIsReplay )
{
// Replay mode...
m_iFrame += a_iNumFrames;
if ( m_iFrame >= ((int)m_aReplayOffsets.size())-1 ) m_iFrame = m_aReplayOffsets.size() - 2;
if ( m_iFrame <= 0 ) m_iFrame = 0;
std::string sFrameDesc = m_sReplayString.substr(
m_aReplayOffsets[m_iFrame],
m_aReplayOffsets[m_iFrame+1] - m_aReplayOffsets[m_iFrame] );
g_oBackend.ReadFromString( sFrameDesc );
return;
}
static std::string sFrameDesc;
int i;
if ( IsNetworkGame() )
{
g_poNetwork->SendGameTick( g_oBackend.m_iGameTick );
g_poNetwork->Update();
int i = 0;
while ( g_poNetwork->GetGameTick() + m_iEnqueueDelay < g_oBackend.m_iGameTick + a_iNumFrames )
{
++i;
if ( i > 300 ) {
// Waited for too long..
g_poNetwork->Stop();
}
// The remote side is lagging behind.. Wait for it.
SDL_Delay( 10 );
g_poNetwork->Update();
if ( m_enInitialGameMode != g_oState.m_enGameMode ) {
return;
}
}
int iTime;
int iKey;
bool bPressed;
while ( g_poNetwork->GetKeystroke( iTime, iKey, bPressed ) )
{
debug( "Got GetKeystroke: %d, %d, %d at %d\n", iTime, iKey, bPressed, g_oBackend.m_iGameTick );
// g_oBackend.PerlEvalF( bPressed ? "KeyDown(%d,%d);" : "KeyUp(%d,%d);", 1, iKey );
m_oKeyQueue.EnqueueKey( iTime, IsMaster() ? 1 : 0, iKey, bPressed );
if ( iTime <= g_oBackend.m_iGameTick )
{
debug( "KEY ARRIVED TOO LATE!!!\n" );
}
}
}
while ( a_iNumFrames > 0 )
{
-- a_iNumFrames;
g_oBackend.AdvancePerl();
g_oBackend.ReadFromPerl();
g_oBackend.PlaySounds();
m_oKeyQueue.DequeueKeys( g_oBackend.m_iGameTick );
g_oBackend.WriteToString( sFrameDesc );
m_sReplayString += sFrameDesc;
m_sReplayString += '\n';
m_aReplayOffsets.push_back( m_sReplayString.size() );
}
}
/** A helper method of ProcessEvents; it manages keypresses and releases of
players. It is only called when keypresses are actually relevant for the
backend (not during instant replay, etc).
*/
void Game::HandleKey( int a_iPlayer, int a_iKey, bool a_bDown )
{
int iCurrentTick = g_oBackend.m_iGameTick + m_iEnqueueDelay;
if ( IsNetworkGame() )
{
a_iPlayer = IsMaster() ? 0 : 1;
g_poNetwork->SendKeystroke( iCurrentTick, a_iKey, a_bDown );
}
m_oKeyQueue.EnqueueKey( iCurrentTick, a_iPlayer, a_iKey, a_bDown );
}
/** ProcessEvents reads events from the SDL event system.
Relevant key events are fed to the backend.
Esc brings up the menu.
Returns 1 on quit event (e.g. if the current game or replay should be aborted), 0 otherwise.
*/
int Game::ProcessEvents()
{
- SDL_Event event;
- while (SDL_PollEvent(&event))
+ SMortalEvent oEvent;
+
+ while (MortalPollEvent(oEvent))
{
- switch (event.type)
+ switch (oEvent.m_enType)
{
- case SDL_QUIT:
+ case Me_QUIT:
g_oState.m_bQuitFlag = true;
return 1;
+
+ case Me_MENU:
+ if ( Ph_REWIND == m_enGamePhase
+ || Ph_SLOWFORWARD == m_enGamePhase )
+ {
+ // Menu counts as 'skip' during instant replay
+ return 1;
+ }
- case SDL_KEYDOWN:
- {
- if ( event.key.keysym.sym == SDLK_ESCAPE && !IsNetworkGame() )
+ if ( !IsNetworkGame() )
{
SState::TGameMode enMode = g_oState.m_enGameMode;
::DoMenu();
return g_oState.m_enGameMode == enMode ? 0 : 1;
}
- if ( event.key.keysym.sym == SDLK_F1 /*&& !IsNetworkGame()*/ )
- {
- // shortcut: abort the current round. This shall is here
- // to ease testing, and will be removed from the final
- // version.
- return 1;
- }
-
+
+ case Me_SKIP:
+ return 1;
+
+ case Me_PLAYERKEYDOWN:
+ case Me_PLAYERKEYUP:
+ {
if ( Ph_NORMAL != m_enGamePhase &&
Ph_REPLAY != m_enGamePhase )
break;
-
- for (int i=0; i<2; i++)
- {
- for (int j=0; j<9; j++ )
- {
- if (g_oState.m_aiPlayerKeys[i][j] == event.key.keysym.sym)
- {
- if (g_oState.m_enGameMode == SState::IN_DEMO)
- {
- g_oState.m_enGameMode = SState::IN_MULTI;
- return 1;
- }
- HandleKey( i, j, true );
- //g_oBackend.PerlEvalF( "KeyDown(%d,%d);", i, j );
- return 0;
- }
- }
- }
-
- break;
+
+ HandleKey( oEvent.m_iPlayer, oEvent.m_iKey, Me_PLAYERKEYDOWN == oEvent.m_enType );
}
-
- case SDL_KEYUP:
- {
- if ( Ph_NORMAL != m_enGamePhase )
- break;
- for (int i=0; i<2; i++)
- {
- for (int j=0; j<9; j++ )
- {
- if (g_oState.m_aiPlayerKeys[i][j] == event.key.keysym.sym)
- {
- HandleKey( i, j, false );
- //g_oBackend.PerlEvalF( "KeyUp(%d,%d);", i, j );
- return 0;
- }
- }
- }
+ case Me_NOTHING:
break;
- }
+
} // End of switch
- } // End of while SDL_PollEvent;
+ } // End of while polling events;
return 0;
}
void Game::HurryUp()
{
Audio->PlaySample( "aroooga.voc" );
DrawGradientText( "HURRY UP!", titleFont, 200, gamescreen );
SDL_Delay( 1000 );
Audio->PlaySample( "machine_start.voc" );
}
void Game::TimeUp()
{
DrawGradientText( "TIME IS UP!", titleFont, 200, gamescreen );
SDL_Delay( 1000 );
}
/** This methods starts and runs the "instant replay" mode that is done
at the end of a game round. This means doing phases Ph_REWIND and Ph_SLOWFORWARD.
Rewind will go back in time 200 ticks before the parameter a_iKoAt.
*/
void Game::InstantReplay( int a_iKoAt )
{
int iCurrentFrame = m_aReplayOffsets.size() - 200;
int iThisTick, iLastTick, iGameSpeed;
m_enGamePhase = Ph_REWIND;
iGameSpeed = 8;
iThisTick = SDL_GetTicks() / iGameSpeed;
iLastTick = iThisTick - 1;
while ( iCurrentFrame < (int)m_aReplayOffsets.size() - 150 )
{
// 1. Wait for the next tick (on extremely fast machines..)
while (iThisTick == iLastTick)
{
iThisTick = SDL_GetTicks() / iGameSpeed;
if ( iThisTick==iLastTick ) SDL_Delay(1);
}
// 2. Advance as many ticks as necessary..
int iNumTicks = iThisTick - iLastTick;
if ( iNumTicks > 10 ) iNumTicks = 10;
if ( iNumTicks < 0 ) iNumTicks = 0;
iCurrentFrame += ( Ph_REWIND == m_enGamePhase ) ? -iNumTicks : +iNumTicks ;
if ( Ph_REWIND == m_enGamePhase
&& ( iCurrentFrame < a_iKoAt - 200 || iCurrentFrame <= 0 )
)
{
m_enGamePhase = Ph_SLOWFORWARD;
iGameSpeed = 16;
SDL_Delay(500);
}
iLastTick = iThisTick;
if ( iCurrentFrame < 0 ) iCurrentFrame = 0;
m_iFrame = iCurrentFrame;
if ( m_iFrame >= ((int)m_aReplayOffsets.size())-1 ) m_iFrame = m_aReplayOffsets.size() - 2;
if ( m_iFrame <= 0 ) m_iFrame = 0;
std::string sFrameDesc = m_sReplayString.substr(
m_aReplayOffsets[m_iFrame],
m_aReplayOffsets[m_iFrame+1] - m_aReplayOffsets[m_iFrame] );
//debug( "PB: Frame %d ofs %d-%d; data: '%s'\n", m_iFrame,
// m_aReplayOffsets[m_iFrame], m_aReplayOffsets[m_iFrame+1], sFrameDesc.c_str() );
g_oBackend.ReadFromString( sFrameDesc );
if ( ProcessEvents() )
{
break;
}
oFpsCounter.Tick();
// 3. Draw the next game screen..
Draw();
if ( g_oState.m_bQuitFlag
|| SState::IN_DEMO == g_oState.m_enGameMode )
{
break;
}
}
}
/** This methods executes one round of gameplay.
The game progresses through phases Ph_START, Ph_NORMAL, and
Ph_KO. If a KO happened, it will invoke InstantReplay. At the end of
the round m_aiRoundsWonByPlayer[x] will be incremented depending on the
outcome. m_iNumberOfRounds will also increase by 1.
*/
void Game::DoOneRound()
{
m_enGamePhase = Ph_START;
g_oBackend.PerlEvalF( "GameStart(%d,%d);",
IsMaster() ? g_oState.m_iHitPoints : g_poNetwork->GetGameParams().iHitPoints,
m_bDebug );
g_oBackend.ReadFromPerl();
if ( IsNetworkGame() )
{
g_poNetwork->SynchStartRound();
g_poNetwork->SendGameTick( g_oBackend.m_iGameTick-1 );
}
int iKoFrame = -1;
double dGameTime = 2 * 1000; // Only for the "greeting phase", the real gametime will be set after.
int iThisTick, iLastTick, iGameSpeed;
bool bHurryUp = false;
bool bReplayAfter = true;
iGameSpeed = IsMaster() ? g_oState.m_iGameSpeed : g_poNetwork->GetGameParams().iGameSpeed;
iThisTick = SDL_GetTicks() / iGameSpeed;
iLastTick = iThisTick - 1;
m_oKeyQueue.Reset();
oFpsCounter.Reset();
// 1. DO THE NORMAL GAME ROUND (START, NORMAL, KO, TIMEUP)
while ( dGameTime >= 0 )
{
if ( m_enInitialGameMode != g_oState.m_enGameMode )
{
return;
}
// 1. Wait for the next tick (on extremely fast machines..)
while (iThisTick == iLastTick)
{
iThisTick = SDL_GetTicks() / iGameSpeed;
if ( iThisTick==iLastTick ) SDL_Delay(1);
}
// 2. Advance as many ticks as necessary..
int iNumTicks = iThisTick - iLastTick;
if ( iNumTicks > MAXFRAMESKIP ) iNumTicks = MAXFRAMESKIP;
Advance( iNumTicks );
dGameTime -= iNumTicks * iGameSpeed;
// 3. Check for state transitions and game time.
// START -> NORMAL
// NORMAL -> KO
// NORMAL -> TIMEUP
// bHurryUp flag can be set during NORMAL phase
if ( Ph_START == m_enGamePhase ) // Check for the end of the START phase
{
if ( dGameTime <= 0 )
{
m_enGamePhase = Ph_NORMAL;
dGameTime = (IsMaster() ? g_oState.m_iGameTime : g_poNetwork->GetGameParams().iGameTime) * 1000;
}
}
else if ( Ph_NORMAL == m_enGamePhase ) // Check for the end of the NORMAL phase
{
if ( dGameTime < 10 * 1000
&& !bHurryUp )
{
bHurryUp = true;
g_poNetwork->SendHurryup( 1 );
HurryUp();
iGameSpeed = iGameSpeed * 3 / 4;
}
if ( g_oBackend.m_bKO )
{
m_enGamePhase = Ph_KO;
dGameTime = 10 * 1000;
iKoFrame = m_aReplayOffsets.size();
}
else if ( dGameTime <= 0 )
{
m_enGamePhase = Ph_TIMEUP;
g_poNetwork->SendHurryup( 2 );
TimeUp();
break;
}
}
m_iGameTime = (int) ((dGameTime + 500.0) / 1000.0);
iLastTick = iThisTick;
// ProcessEvents will read keyboard/gamepad input
// It will also transmit them to the remote side in a network game.
if ( ProcessEvents() || g_oState.m_bQuitFlag )
{
bReplayAfter = false;
break;
}
oFpsCounter.Tick();
// 3. Draw the next game screen..
Draw();
// 4. Check 'end of round' condition.
if ( !IsMaster() )
{
if ( g_poNetwork->IsRoundOver() )
{
break;
}
}
else if ( g_oBackend.m_iGameOver )
{
break;
}
}
int p1h = g_oBackend.m_aoPlayers[0].m_iHitPoints;
int p2h = g_oBackend.m_aoPlayers[1].m_iHitPoints;
// 3. DO THE REPLAY (IF THERE WAS A KO)
if ( iKoFrame>0 && bReplayAfter && !IsNetworkGame() )
{
InstantReplay( iKoFrame );
}
// 4. END OF ROUND
debug( "Game over; p1h = %d; p2h = %d\n", p1h, p2h );
if ( IsMaster() )
{
int iWhoWon = -1;
if ( p1h > p2h ) { ++m_aiRoundsWonByPlayer[0]; iWhoWon = 0; }
if ( p2h > p1h ) { ++m_aiRoundsWonByPlayer[1]; iWhoWon = 1; }
if ( IsNetworkGame() )
{
g_poNetwork->SendGameTick( g_oBackend.m_iGameTick + m_iEnqueueDelay * 100 );
g_poNetwork->SendRoundOver( iWhoWon, m_iNumberOfRounds > 0 );
}
}
else
{
int iWhoWon = g_poNetwork->GetWhoWon();
if ( iWhoWon>=0 )
{
++m_aiRoundsWonByPlayer[iWhoWon];
}
}
++m_iNumberOfRounds;
}
void Game::DoReplay( const char* a_pcReplayFile )
{
std::ifstream oInput( a_pcReplayFile );
int iPlayer1, iPlayer2;
oInput >> iPlayer1 >> iPlayer2;
std::string sLine;
std::getline( oInput, sLine );
g_oPlayerSelect.SetPlayer( 0, (FighterEnum) iPlayer1 );
g_oPlayerSelect.SetPlayer( 1, (FighterEnum) iPlayer2 );
int iThisTick, iLastTick, iGameSpeed;
m_enGamePhase = Ph_REPLAY;
iGameSpeed = 12;
iThisTick = SDL_GetTicks() / iGameSpeed;
iLastTick = iThisTick - 1;
while ( !oInput.eof() )
{
// 1. Wait for the next tick (on extremely fast machines..)
while (iThisTick == iLastTick)
{
iThisTick = SDL_GetTicks() / iGameSpeed;
if ( iThisTick==iLastTick ) SDL_Delay(1);
}
// 2. Advance as many ticks as necessary..
int iNumTicks = iThisTick - iLastTick;
if ( iNumTicks > 5 ) iNumTicks = 5;
for ( int i=0; i< iNumTicks; ++i )
{
std::getline( oInput, sLine );
}
if ( 0 == sLine.size() )
{
break;
}
iLastTick = iThisTick;
g_oBackend.ReadFromString( sLine );
if ( ProcessEvents() )
{
break;
}
oFpsCounter.Tick();
// 3. Draw the next game screen..
Draw();
if ( g_oState.m_bQuitFlag )
{
break;
}
}
}
/** Public static function.
Other parts of OpenMortal need not include "Game.h" so long as they have
the definition of this method (defined in "common.h"). The method runs
a cycle of the game (either a normal game, or replay).
In replay mode, DoReplay() is called, and the replay file is required.
In normal mode, Run() is called. The replay file is recorded, if it is not NULL.
*/
int DoGame( char* a_pcReplayFile, bool a_bIsReplay, bool a_bDebug )
{
Game oGame( a_bIsReplay, a_bDebug );
if ( a_bIsReplay )
{
if ( NULL == a_pcReplayFile )
{
return 0;
}
oGame.DoReplay( a_pcReplayFile );
return 0;
}
else
{
int iRetval = oGame.Run();
if ( NULL != a_pcReplayFile )
{
std::ofstream oOutput( a_pcReplayFile );
oOutput <<
g_oPlayerSelect.GetPlayerInfo(0).m_enFighter << ' ' <<
g_oPlayerSelect.GetPlayerInfo(1).m_enFighter << '\n' << oGame.GetReplay();
}
return iRetval;
}
}
diff --git a/src/GameOver.cpp b/src/GameOver.cpp
index 0c4540c..60eb3a6 100644
--- a/src/GameOver.cpp
+++ b/src/GameOver.cpp
@@ -1,220 +1,218 @@
/***************************************************************************
GameOver.cpp - description
-------------------
begin : Wed Aug 21 20:25:30 CEST 2003
copyright : (C) 2003 by upi
email : upi@apocalypse.rulez.org
***************************************************************************/
#include "PlayerSelect.h"
#include "SDL.h"
#include "gfx.h"
#include "Backend.h"
#include "common.h"
#include "State.h"
#include "RlePack.h"
#include "Audio.h"
+#include "Event.h"
#include <stdio.h>
void DrawPlayer( int i )
{
int iFrame = g_oBackend.m_aoPlayers[i].m_iFrame;
if ( 0 != iFrame )
{
g_oPlayerSelect.GetPlayerInfo(i).m_poPack->Draw(
ABS(iFrame)-1,
g_oBackend.m_aoPlayers[i].m_iX,
g_oBackend.m_aoPlayers[i].m_iY - 15,
iFrame<0 );
}
}
void GameOver( int a_iPlayerWon )
{
SDL_Surface* poBackground = LoadBackground( "GameOver.png", 112 );
DrawGradientText( "Final Judgement", titleFont, 20, poBackground );
DrawTextMSZ( "Continue?", inkFont, 320, 100, AlignHCenter, C_LIGHTCYAN, poBackground );
SDL_Surface* poFoot = LoadBackground( "Foot.png", 112 );
SDL_BlitSurface( poBackground, NULL, gamescreen, NULL );
g_oBackend.PerlEvalF( "JudgementStart(%d);", a_iPlayerWon );
int thisTick, lastTick, firstTick, iGameSpeed;
iGameSpeed = 14 ;
firstTick = thisTick = SDL_GetTicks() / iGameSpeed;
lastTick = thisTick - 1;
char acString[100];
int iTimeLeft = 8000 / iGameSpeed;
int FOOTHEIGHT = poFoot->h;
int GROUNDLEVEL = 440;
int iFootY = -FOOTHEIGHT;
bool bTimeUp = false;
bool bKeyPressed = false;
int iCounter = -1;
- SDL_Event event;
-
while (1)
{
// 1. Wait for the next tick (on extremely fast machines..)
while (1)
{
thisTick = SDL_GetTicks() / iGameSpeed;
if ( thisTick==lastTick )
{
SDL_Delay(1);
}
else
{
break;
}
}
// 2. Advance as many ticks as necessary..
if ( thisTick - lastTick > 5 )
{
iTimeLeft -= 5;
}
else
{
iTimeLeft = iTimeLeft - thisTick + lastTick;
}
if ( iTimeLeft < 0 && !bTimeUp )
{
bTimeUp = true;
Audio->FadeMusic( 1500 );
}
if ( bTimeUp )
{
iFootY += 12 * (thisTick - lastTick );
if ( iFootY > GROUNDLEVEL - FOOTHEIGHT )
{
break;
}
}
int iNumFrames = thisTick - lastTick;
for ( int i=0; i<iNumFrames; ++i )
{
g_oBackend.AdvancePerl();
};
lastTick = thisTick;
-
- while (SDL_PollEvent(&event))
+
+ SMortalEvent oEvent;
+ while (MortalPollEvent(oEvent))
{
- switch (event.type)
+ switch (oEvent.m_enType)
{
- case SDL_QUIT:
+ case Me_QUIT:
g_oState.m_bQuitFlag = true;
break;
+
+ case Me_MENU:
+ DoMenu();
+ break;
- case SDL_KEYDOWN:
- {
- if ( event.key.keysym.sym == SDLK_ESCAPE )
+ case Me_PLAYERKEYDOWN:
+ if ( 1-a_iPlayerWon == oEvent.m_iPlayer
+ && oEvent.m_iKey>= 4 )
{
- DoMenu();
- break;
+ bKeyPressed = true;
}
+ break;
- for (int j=4; j<9; j++ )
- {
- if (g_oState.m_aiPlayerKeys[1-a_iPlayerWon][j] == event.key.keysym.sym)
- {
- bKeyPressed = true;
- break;
- }
- }
- }
- break;
+ case Me_NOTHING:
+ case Me_PLAYERKEYUP:
+ case Me_SKIP:
+ break;
} // switch statement
} // Polling events
g_oBackend.ReadFromPerl();
SDL_BlitSurface( poBackground, NULL, gamescreen, NULL );
DrawPlayer( a_iPlayerWon );
if ( bTimeUp )
{
SDL_Rect oRect;
oRect.x = 0;
oRect.y = iFootY + FOOTHEIGHT - 10;
oRect.w = gamescreen->w;
oRect.h = gamescreen->h - oRect.y;
SDL_SetClipRect(gamescreen, &oRect);
}
DrawPlayer( 1-a_iPlayerWon );
SDL_SetClipRect( gamescreen, NULL );
if ( !bTimeUp )
{
int iNewCounter = iTimeLeft * iGameSpeed / 1000;
sprintf( acString, "%d", iNewCounter );
DrawTextMSZ( acString, inkFont, 320, 130, AlignHCenter, C_LIGHTCYAN, gamescreen );
if ( iNewCounter != iCounter )
{
Audio->PlaySample( "alarm.voc" );
iCounter = iNewCounter;
}
}
else
{
SDL_Rect oRect;
oRect.x = 40;
oRect.y = iFootY;
SDL_BlitSurface( poFoot, NULL, gamescreen, &oRect );
}
SDL_Flip( gamescreen );
if ( g_oState.m_bQuitFlag ||
SState::IN_DEMO == g_oState.m_enGameMode ||
bKeyPressed )
{
break;
}
}
if ( g_oState.m_bQuitFlag ||
SState::IN_DEMO == g_oState.m_enGameMode )
{
SDL_FreeSurface( poBackground );
return;
}
SDL_FillRect( gamescreen, NULL, C_BLACK );
if ( bTimeUp )
{
SDL_UnlockSurface( gamescreen );
DrawGradientText( "SPLAT!", titleFont, 220, gamescreen );
Audio->PlaySample( "splat2.voc" );
SDL_Flip( gamescreen );
SDL_Delay( 1500 );
g_oState.m_enGameMode = SState::IN_DEMO;
}
else
{
SDL_Flip( gamescreen );
}
SDL_FreeSurface( poBackground );
return;
}
diff --git a/src/Joystick.cpp b/src/Joystick.cpp
new file mode 100644
index 0000000..ca30805
--- /dev/null
+++ b/src/Joystick.cpp
@@ -0,0 +1,255 @@
+/***************************************************************************
+ Joystick.cpp - description
+ -------------------
+ begin : Sat Feb 14 2004
+ copyright : (C) 2004 by upi
+ email : upi@feel
+ ***************************************************************************/
+
+
+#include "SDL/SDL.h"
+#include "Event.h"
+#include "common.h"
+#include "Joystick.h"
+
+#include <string.h>
+
+CJoystick g_oJoystick;
+
+
+
+CJoystick::CJoystick()
+{
+ m_iNumJoysticks = 0;
+}
+
+
+CJoystick::~CJoystick()
+{
+}
+
+
+int InitJoystick()
+{
+ return g_oJoystick.Init();
+}
+
+
+
+int CJoystick::Init()
+{
+ m_iNumJoysticks = 0;
+ int iResult = SDL_InitSubSystem(SDL_INIT_JOYSTICK);
+
+ if ( iResult < 0 )
+ {
+ debug( "CJoystick::Init() failed: %s\n", SDL_GetError() );
+ return 0;
+ }
+
+ int iNumJoysticks = SDL_NumJoysticks();
+ debug( "CJoystick::Init(): Number of joysticks is %d\n", iNumJoysticks );
+
+ int i;
+ for ( i=0; i<iNumJoysticks; ++i )
+ {
+ const char* poName = SDL_JoystickName(i);
+ debug( "CJoystick::Init(): Joystick #%d is '%s'\n", i, poName );
+
+ SDL_Joystick* poJoystick = SDL_JoystickOpen(i);
+ if ( NULL == poJoystick )
+ {
+ continue;
+ }
+
+ m_apoJoysticks[m_iNumJoysticks] = poJoystick;
+ m_apcJoystickNames[m_iNumJoysticks] = poName;
+ m_abWorkaround[m_iNumJoysticks] = false;
+ m_aiHorizontalAxis[m_iNumJoysticks] = 0;
+ m_aiVerticalAxis[m_iNumJoysticks] = 0;
+
+ debug( "CJoystick::Init(): Joystick #%d has %d axes, %d buttons, %d balls, %d hats\n",
+ SDL_JoystickNumAxes( poJoystick ),
+ SDL_JoystickNumButtons( poJoystick ),
+ SDL_JoystickNumBalls( poJoystick ),
+ SDL_JoystickNumHats( poJoystick ) );
+
+ if ( strstr( poName, "SIGHT FIGHTER ACTION USB" ) )
+ {
+ m_abWorkaround[m_iNumJoysticks] = true;
+ debug( "CJoystick::Init(): Infuriatingly stupid joystick detected.\n" );
+ }
+ ++m_iNumJoysticks;
+ }
+
+ if ( m_iNumJoysticks )
+ {
+ SDL_JoystickEventState( SDL_ENABLE );
+ }
+
+ return m_iNumJoysticks;
+}
+
+
+
+const char* CJoystick::GetJoystickName( int a_iJoystickNumber )
+{
+ if ( a_iJoystickNumber >= m_iNumJoysticks
+ || a_iJoystickNumber < 0 )
+ {
+ return NULL;
+ }
+
+ return m_apcJoystickNames[a_iJoystickNumber];
+}
+
+
+
+bool CJoystick::TranslateEvent( const SDL_Event* a_poInEvent, SMortalEvent* a_poOutEvent )
+{
+ a_poOutEvent->m_enType = Me_NOTHING;
+
+ switch ( a_poInEvent->type )
+ {
+ case SDL_JOYAXISMOTION:
+ {
+ int iJoyNumber = a_poInEvent->jaxis.which;
+ int iAxisNumber = a_poInEvent->jaxis.axis;
+ int iValue = a_poInEvent->jaxis.value;
+
+ if ( iAxisNumber > 1 )
+ {
+ // Only translate axis 0 and 1.
+ return false;
+ }
+
+ if ( m_abWorkaround[iJoyNumber] )
+ {
+ iValue = AxisWorkaround( a_poInEvent->jaxis );
+ debug( "Translated %d to %d\n", a_poInEvent->jaxis.value, iValue );
+ }
+
+ // Try the new value into motion.
+ int& riOldValue = iAxisNumber ? m_aiVerticalAxis[iJoyNumber] : m_aiHorizontalAxis[iJoyNumber];
+
+ if ( -1 == riOldValue )
+ {
+ if ( iValue < -3200 )
+ {
+ return false;
+ }
+ riOldValue = 0;
+ a_poOutEvent->m_enType = Me_PLAYERKEYUP;
+ a_poOutEvent->m_iPlayer = iJoyNumber;
+ a_poOutEvent->m_iKey = iAxisNumber ? Mk_UP : Mk_LEFT;
+ return true;
+ }
+
+ if ( 0 == riOldValue )
+ {
+ if ( iValue < -6400 )
+ {
+ riOldValue = -1;
+ a_poOutEvent->m_enType = Me_PLAYERKEYDOWN;
+ a_poOutEvent->m_iPlayer = iJoyNumber;
+ a_poOutEvent->m_iKey = iAxisNumber ? Mk_UP : Mk_LEFT;
+ return true;
+ }
+ if ( iValue > 6400 )
+ {
+ riOldValue = 1;
+ a_poOutEvent->m_enType = Me_PLAYERKEYDOWN;
+ a_poOutEvent->m_iPlayer = iJoyNumber;
+ a_poOutEvent->m_iKey = iAxisNumber ? Mk_DOWN : Mk_RIGHT;
+ return true;
+ }
+ return false;
+ }
+ if ( 1 == riOldValue )
+ {
+ if ( iValue > 3200 )
+ {
+ return false;
+ }
+ riOldValue = 0;
+ a_poOutEvent->m_enType = Me_PLAYERKEYUP;
+ a_poOutEvent->m_iPlayer = iJoyNumber;
+ a_poOutEvent->m_iKey = iAxisNumber ? Mk_DOWN : Mk_RIGHT;
+ return true;
+ }
+
+ riOldValue = 0;
+ return false;
+ }
+
+ case SDL_JOYBUTTONDOWN:
+ case SDL_JOYBUTTONUP:
+ {
+ int iJoyNumber = a_poInEvent->jbutton.which;
+ int iButton = a_poInEvent->jbutton.button;
+ int iPressed = a_poInEvent->jbutton.state == SDL_PRESSED;
+
+ debug( "Button down: joy %d, button %d, state %d\n", iJoyNumber, iButton, iPressed );
+
+ if ( iButton > 4 )
+ {
+ if ( iButton == SDL_JoystickNumButtons(m_apoJoysticks[iJoyNumber]) - 1
+ && iPressed )
+ {
+ a_poOutEvent->m_enType = Me_MENU;
+ return true;
+ }
+ return false;
+ }
+
+ if ( iJoyNumber > 1 )
+ {
+ return false;
+ }
+
+ a_poOutEvent->m_enType = iPressed ? Me_PLAYERKEYDOWN : Me_PLAYERKEYUP;
+ a_poOutEvent->m_iPlayer = iJoyNumber;
+ a_poOutEvent->m_iKey = iButton + 4;
+
+ return true;
+ }
+
+ case SDL_JOYBALLMOTION:
+ if( a_poInEvent->jball.ball == 0 )
+ {
+ // Nothing for now.
+ }
+ break;
+
+ case SDL_JOYHATMOTION:
+ if ( a_poInEvent->jhat.hat & SDL_HAT_UP )
+ {
+ // Nothing for now.
+ }
+ if ( a_poInEvent->jhat.hat & SDL_HAT_LEFT )
+ {
+ // Nothing for now.
+ }
+ if ( a_poInEvent->jhat.hat & SDL_HAT_RIGHTDOWN )
+ {
+ // Nothing for now.
+ }
+ break;
+
+ } // end of switch statement
+
+ return false;
+}
+
+
+int CJoystick::AxisWorkaround( const SDL_JoyAxisEvent& a_roEvent )
+{
+ if ( 0 == a_roEvent.value ) return -32768;
+ if ( 127 == a_roEvent.value ) return 0;
+ if ( -1 == a_roEvent.value ) return 32768;
+
+ return 0;
+}
+
+
+
diff --git a/src/Joystick.h b/src/Joystick.h
new file mode 100644
index 0000000..9803e62
--- /dev/null
+++ b/src/Joystick.h
@@ -0,0 +1,47 @@
+/***************************************************************************
+ Joystick.h - description
+ -------------------
+ begin : Sat Feb 14 2004
+ copyright : (C) 2004 by upi
+ email : upi@feel
+ ***************************************************************************/
+
+
+#ifndef JOYSTICK_H
+#define JOYSTICK_H
+
+#include "SDL/SDL.h"
+
+struct SMortalEvent;
+
+class CJoystick
+{
+public:
+ CJoystick();
+ ~CJoystick();
+
+ int Init();
+ bool TranslateEvent( const SDL_Event* a_poInEvent, SMortalEvent* a_poOutEvent );
+ const char* GetJoystickName( int a_iJoystickNumber );
+
+protected:
+
+ int AxisWorkaround( const SDL_JoyAxisEvent& a_roEvent );
+
+ enum {
+ mg_iMaxJoysticks = 32,
+ };
+
+ int m_iNumJoysticks;
+ SDL_Joystick* m_apoJoysticks[mg_iMaxJoysticks];
+ const char* m_apcJoystickNames[mg_iMaxJoysticks];
+ bool m_abWorkaround[mg_iMaxJoysticks];
+
+ int m_aiHorizontalAxis[mg_iMaxJoysticks];
+ int m_aiVerticalAxis[mg_iMaxJoysticks];
+};
+
+
+extern CJoystick g_oJoystick;
+
+#endif // JOYSTICK_H
diff --git a/src/OnlineChat.cpp b/src/OnlineChat.cpp
index b5a5386..2158365 100644
--- a/src/OnlineChat.cpp
+++ b/src/OnlineChat.cpp
@@ -1,712 +1,742 @@
/***************************************************************************
OnlineChat.cpp - description
-------------------
begin : Fri Jan 30 2004
copyright : (C) 2004 by upi
email : upi@feel
***************************************************************************/
#include "OnlineChat.h"
#include "TextArea.h"
#include "State.h"
#include "menu.h"
#include "Audio.h"
#include "sge_tt_text.h"
#include "gfx.h"
#include "common.h"
#include "config.h"
+#include "Event.h"
//#include "SDL_video.h"
#define MORTALNETSERVER "apocalypse.game-host.org"
#define MORTALNETWORKPORT 0x3A23
// Layout
#define READLINE_Y 440
#define NICKLIST_X 500
void MortalNetworkResetMessages( bool a_bClear );
void MortalNetworkMessage( const char* format, ... );
bool MortalNetworkCheckKey();
/*************************************************************************
CHAT / CHALLENGE MENUS
*************************************************************************/
enum
{
MENU_DISCONNECT = 100,
MENU_CHALLENGE,
MENU_CHANGENICK,
MENU_OK,
MENU_ACCEPTCHALLENGE,
MENU_REJECTHALLENGE,
};
class CChallengeMenu: public Menu
{
public:
CChallengeMenu::CChallengeMenu( std::string a_sChallenger )
: Menu( "You have been challenged!" ),
m_sChallenger( a_sChallenger )
{
m_bAccepted = false;
AddTextMenuItem( "ACCEPT CHALLENGE FROM ", m_sChallenger.c_str(), MENU_ACCEPTCHALLENGE );
AddMenuItem( "NO, I'M REALLY SCARED", SDLK_UNKNOWN, MENU_REJECTHALLENGE );
}
~CChallengeMenu() {}
bool GetAccepted()
{
return m_bAccepted;
}
void ItemActivated( int a_iItemCode, MenuItem* a_poMenuItem )
{
switch ( a_iItemCode )
{
case MENU_ACCEPTCHALLENGE:
m_bAccepted = true;
+ // intentional fall through
case MENU_REJECTHALLENGE:
m_iReturnCode = 100;
m_bDone = true;
+ break;
}
}
protected:
std::string m_sChallenger;
bool m_bAccepted;
};
class CChatMenu: public Menu
{
public:
CChatMenu( const TNickMap& a_roNicks )
: Menu( "MortalNet Menu" ),
m_roNicks( a_roNicks )
{
int i=0;
TNickMap::const_iterator it;
for ( it=m_roNicks.begin();
it != m_roNicks.end() && i < 1023;
++it, ++i )
{
if ( it->first == g_oState.m_acNick )
{
--i;
continue;
}
m_apcNicks[i] = (it->first).c_str();
m_aiNicks[i] = i;
}
m_apcNicks[i] = NULL;
m_sNick = g_oState.m_acNick;
AddMenuItem( "DISCONNECT", SDLK_UNKNOWN, MENU_DISCONNECT );
if ( i > 0 )
{
AddEnumMenuItem( "CHALLENGE USER: ", 0, m_apcNicks, m_aiNicks, MENU_CHALLENGE );
}
m_poNickMenuItem = AddTextMenuItem( "Nickname: ", g_oState.m_acNick, MENU_CHANGENICK );
+ AddMenuItem( "~OPTIONS", SDLK_o, MENU_OPTIONS );
+ AddMenuItem( "QUIT", SDLK_UNKNOWN, MENU_QUIT );
AddOkCancel( MENU_OK );
}
virtual ~CChatMenu() {}
std::string GetNick()
{
return m_sNick;
}
std::string GetChallengedNick()
{
return m_sChallengedNick;
}
void ItemActivated( int a_iItemCode, MenuItem* a_poMenuItem )
{
switch ( a_iItemCode )
{
case MENU_DISCONNECT:
g_oState.m_enGameMode = SState::IN_DEMO;
m_bDone = true;
m_iReturnCode = -1;
break;
case MENU_CHANGENICK:
{
EnterName( "Nickname: ", m_sNick, m_poNickMenuItem, 12 );
break;
}
case MENU_CHALLENGE:
{
m_sChallengedNick = ((EnumMenuItem*)a_poMenuItem)->GetCurrentText();
m_bDone = true;
m_iReturnCode = 100;
break;
}
case MENU_OK:
{
m_bDone = true;
m_iReturnCode = -1;
break;
}
- }
+
+ default:
+ Menu::ItemActivated( a_iItemCode, a_poMenuItem );
+
+ } // end of switch statement
}
protected:
std::string m_sChallengedNick;
std::string m_sNick;
const TNickMap& m_roNicks;
const char* m_apcNicks[1024];
int m_aiNicks[1024];
TextMenuItem* m_poNickMenuItem;
};
/*************************************************************************
CHAT CONNECT/DISCONNECT
*************************************************************************/
COnlineChat::COnlineChat()
{
m_poScreen = gamescreen;
m_poBackground = NULL;
m_poSocket = NULL;
m_poSocketSet = NULL;
m_iIncomingBufferSize = 0;
m_poReadline = NULL;
m_poTextArea = NULL;
}
COnlineChat::~COnlineChat()
{
Stop();
if ( m_poBackground )
{
SDL_FreeSurface( m_poBackground );
m_poBackground = NULL;
}
}
#define CHECKCONNECTION if ( m_poSocket == NULL ) return;
bool COnlineChat::Start()
{
if ( m_poSocket != NULL )
{
return true; // Already connected.
}
#define RETURNNOERROR { \
debug( "%s\n", m_sLastError.c_str() ); \
return false; }
#define RETURNWITHERROR { \
m_sLastError = SDLNet_GetError(); \
debug( "%s\n", m_sLastError.c_str() ); \
return false; }
#define RETURNWITHADDITIONALERROR { \
m_sLastError += SDLNet_GetError(); \
debug( "%s\n", m_sLastError.c_str() ); \
return false; }
m_poBackground = LoadBackground( "FighterStats.png", 64 );
if ( NULL == m_poBackground )
{
return false; // Should carp
}
SDL_BlitSurface( m_poBackground, NULL, m_poScreen, NULL );
SDL_Flip( m_poScreen );
MortalNetworkResetMessages( false );
MortalNetworkMessage( Translate("Resolving hostname (%s)..."), MORTALNETSERVER );
IPaddress oAddress;
int iResult = SDLNet_ResolveHost( &oAddress, MORTALNETSERVER, MORTALNETWORKPORT );
if ( iResult )
{
m_sLastError = Translate( "Couldn't resolve host." );
RETURNNOERROR;
}
debug( "IP Address of server is 0x%x\n", oAddress.host );
Uint32 ipaddr=SDL_SwapBE32(oAddress.host);
MortalNetworkMessage("Connecting to %d.%d.%d.%d port %d",
ipaddr>>24, (ipaddr>>16)&0xff, (ipaddr>>8)&0xff, ipaddr&0xff, oAddress.port);
MortalNetworkMessage ( Translate("Waiting for connection... (press any key to abort)") );
while (1)
{
m_poSocket = SDLNet_TCP_Open( &oAddress );
if ( m_poSocket ) break;
if ( MortalNetworkCheckKey() ) break;
SDL_Delay( 100 );
}
if ( NULL == m_poSocket )
{
RETURNWITHERROR;
}
// CONNECTION ESTABLISHED. SEND INTRO PACKETS
MortalNetworkMessage( Translate("Connection established.") );
m_poSocketSet = SDLNet_AllocSocketSet( 1 );
SDLNet_TCP_AddSocket( m_poSocketSet, m_poSocket ); // Check for errors?
m_iIncomingBufferSize = 0;
m_bMyNickIsOk = false;
m_asNicks.clear();
SendRawData( 'N', g_oState.m_acNick );
return ( m_poSocket != NULL );
}
void COnlineChat::Stop()
{
if ( m_poSocketSet )
{
SDLNet_FreeSocketSet( m_poSocketSet );
m_poSocketSet = NULL;
}
if ( m_poSocket )
{
SDLNet_TCP_Close( m_poSocket );
m_poSocket = NULL;
}
m_bMyNickIsOk = false;
m_asNicks.clear();
if ( g_oState.m_enGameMode == SState::IN_CHAT )
{
g_oState.m_enGameMode = SState::IN_DEMO;
}
}
/*************************************************************************
SENDING / RECEIVING CHAT DATA
*************************************************************************/
void COnlineChat::SendRawData( char a_cID, const std::string& a_rsData )
{
CHECKCONNECTION;
SDLNet_TCP_Send( m_poSocket, &a_cID, 1 );
SDLNet_TCP_Send( m_poSocket, (void*) a_rsData.c_str(), a_rsData.length() );
char cNL = '\n';
SDLNet_TCP_Send( m_poSocket, &cNL, 1 );
}
void COnlineChat::Update()
{
CHECKCONNECTION;
// 1. CHECK FOR STUFF TO READ
int iRetval = SDLNet_CheckSockets( m_poSocketSet, 0 );
if ( iRetval <= 0 )
{
return;
}
// 2. APPEND AT MOST 1024 bytes TO THE END OF THE INCOMING BUFFER
// CHECK FOR BUFFER OVERFLOW HERE.
if ( m_iIncomingBufferSize >= 1024*3 )
{
m_acIncomingBuffer[m_iIncomingBufferSize] = '\n';
m_acIncomingBuffer[m_iIncomingBufferSize+1] = 'x';
m_iIncomingBufferSize += 1;
}
else
{
iRetval = SDLNet_TCP_Recv( m_poSocket, m_acIncomingBuffer + m_iIncomingBufferSize, 1024 );
if ( iRetval <= 0 )
{
m_sLastError = SDLNet_GetError();
Stop();
return;
}
m_iIncomingBufferSize += iRetval;
}
// 3. CONSUME THE INCOMING BUFFER.
// We always make sure the incoming buffer starts with a package header.
int iOffset = 0;
m_acIncomingBuffer[ m_iIncomingBufferSize ] = 0;
bool bRedraw = false;
while ( iOffset < m_iIncomingBufferSize )
{
// 3.1. Find the end of the line.
char* pcLineEnd = strchr( m_acIncomingBuffer + iOffset, '\n' );
if ( NULL == pcLineEnd )
{
// The buffer doesn't have the end of the line (yet)
debug( "Buffer doesn't have the NL (%d buffer, %d offset)\n", m_iIncomingBufferSize, iOffset );
break;
}
*pcLineEnd = 0;
debug( "Receiving message: %d ('%c') type, %d length, %d offset, %d in buffer.\n",
m_acIncomingBuffer[iOffset], m_acIncomingBuffer[iOffset],
pcLineEnd - m_acIncomingBuffer - iOffset, iOffset, m_iIncomingBufferSize );
// 3.2. Receive the data.
switch ( m_acIncomingBuffer[iOffset] )
{
case 'M':
case 'S':
ReceiveMsg( m_acIncomingBuffer[iOffset], m_acIncomingBuffer + iOffset + 1 ); bRedraw = true; break;
case 'J':
case 'L':
case 'N':
case 'Y':
case 'W':
case 'C':
ReceiveUser( m_acIncomingBuffer[iOffset], m_acIncomingBuffer + iOffset + 1 ); bRedraw = true; break;
}
CHECKCONNECTION;
iOffset = pcLineEnd - m_acIncomingBuffer + 1;
}
// 4. MOVE LEFTOVER DATA TO THE BEGINNING OF THE INCOMING BUFFER
// The leftover data starts at iOffset, and is (m_iIncomingBufferSize-iOffset) long.
memmove( m_acIncomingBuffer, m_acIncomingBuffer + iOffset, m_iIncomingBufferSize-iOffset );
m_iIncomingBufferSize -= iOffset;
if ( bRedraw && m_poTextArea )
{
Audio->PlaySample( "pop.wav" );
m_poTextArea->Redraw();
}
}
/*************************************************************************
INCOMING MESSAGES METHODS
*************************************************************************/
void COnlineChat::ReceiveMsg( char a_cID, char* a_pcData )
{
debug( "Received message %c, content is '%s'\n", a_cID, a_pcData );
if ( m_poTextArea )
{
m_poTextArea->AddString( a_pcData, a_cID == 'M' ? C_YELLOW : C_WHITE );
}
}
void COnlineChat::ReceiveUser( char a_cID, char* a_pcData )
{
debug( "Received user %c, content is '%s'\n", a_cID, a_pcData );
// Split up the data.
int iNumWords = 1;
char* pcFirstWord = a_pcData;
char* pcSecondWord = strchr( a_pcData, ' ' );
if ( pcSecondWord )
{
iNumWords = 2;
*pcSecondWord = 0;
++pcSecondWord;
}
int iColor = C_WHITE;
char acMsg[1024];
acMsg[0] = 0;
switch ( a_cID )
{
case 'J':
snprintf( acMsg, 1024, "*** %s has joined MortalChat from %s.", pcFirstWord, pcSecondWord );
if ( strcmp( pcFirstWord, g_oState.m_acNick ) != 0 )
{
m_asNicks[ pcFirstWord ] = pcSecondWord;
}
break;
case 'L':
{
snprintf( acMsg, 1024, "*** %s has left MortalChat.", pcFirstWord );
iColor = C_LIGHTRED;
m_asNicks.erase( pcFirstWord );
debug( "# of Nicks: %d\n", m_asNicks.size() );
break;
}
case 'N':
{
snprintf( acMsg, 1024, "%s is now known as %s", pcFirstWord, pcSecondWord );
iColor = C_LIGHTGRAY;
std::string sHost = m_asNicks[pcFirstWord];
m_asNicks.erase( pcFirstWord );
m_asNicks[ pcSecondWord ] = sHost;
break;
}
case 'Y':
snprintf( acMsg, 1024, "You are now known as %s", pcFirstWord );
iColor = C_LIGHTCYAN;
m_bMyNickIsOk = true;
m_asNicks.erase( g_oState.m_acNick );
m_asNicks[ pcFirstWord ] = "";
strncpy( g_oState.m_acNick, pcFirstWord, 127 );
g_oState.m_acNick[127] = 0;
break;
case 'W':
snprintf( acMsg, 1024, "%s is hailing from %s", pcFirstWord, pcSecondWord );
iColor = C_LIGHTGRAY;
m_asNicks[ pcFirstWord ] = pcSecondWord;
break;
case 'C':
CChallengeMenu oMenu( pcFirstWord );
DoMenu( oMenu );
if ( oMenu.GetAccepted() )
{
MortalNetworkResetMessages( true );
Connect( m_asNicks[pcFirstWord].c_str() );
}
Redraw();
break;
}
if ( m_poTextArea && m_bMyNickIsOk )
{
m_poTextArea->AddString( acMsg, iColor );
DrawNickList();
}
}
/*************************************************************************
DRAWING THE SCREEN
*************************************************************************/
void COnlineChat::Redraw()
{
SDL_BlitSurface( m_poBackground, NULL, m_poScreen, NULL );
m_poReadline->Redraw();
m_poTextArea->Redraw();
DrawNickList();
SDL_Flip( m_poScreen );
}
void COnlineChat::DrawNickList()
{
SDL_Rect oNickListRect;
oNickListRect.x = NICKLIST_X;
oNickListRect.y = 10;
oNickListRect.w = gamescreen->w - oNickListRect.x - 10;
oNickListRect.h = READLINE_Y - oNickListRect.y - 10;
SDL_Rect oOldClipRect;
SDL_GetClipRect( m_poScreen, &oOldClipRect );
SDL_SetClipRect( m_poScreen, &oNickListRect );
SDL_BlitSurface( m_poBackground, &oNickListRect, m_poScreen, &oNickListRect );
int y = oNickListRect.y + sge_TTF_FontAscent( chatFont );
int yEnd = oNickListRect.y + oNickListRect.h - sge_TTF_FontDescent( chatFont );
TNickMap::const_iterator it;
for ( it = m_asNicks.begin();
it != m_asNicks.end() && y <= yEnd;
++it , y += sge_TTF_FontHeight( chatFont ) )
{
int iColor = (it->first) == g_oState.m_acNick ? C_LIGHTCYAN : C_WHITE;
sge_tt_textout( m_poScreen, chatFont, (it->first).c_str(), oNickListRect.x, y, iColor, C_BLACK, 255 );
}
SDL_UpdateRect( m_poScreen, oNickListRect.x, oNickListRect.y, oNickListRect.w, oNickListRect.h );
SDL_SetClipRect( m_poScreen, NULL );
}
extern int g_iMessageY;
void COnlineChat::DoOnlineChat()
{
if ( !Start() )
{
if ( !g_oState.m_bQuitFlag )
{
DrawTextMSZ( "Couldn't connect", inkFont, 320, g_iMessageY, AlignHCenter|UseShadow, C_LIGHTRED, gamescreen );
DrawTextMSZ( m_sLastError.c_str(), impactFont, 320, g_iMessageY + 40, AlignHCenter|UseShadow, C_LIGHTRED, gamescreen, false );
- GetKey();
+ GetKey( true );
}
return;
}
// CREATE USER INTERFACE ELEMENTS
char acMsg[256];
SDL_Event event;
SDL_BlitSurface( m_poBackground, NULL, m_poScreen, NULL );
SDL_Flip( m_poScreen );
m_poTextArea = new CTextArea( m_poScreen, chatFont, 10, 10, NICKLIST_X-20, READLINE_Y-20 );
m_poTextArea->TintBackground( C_DARKGRAY, 128 );
m_poReadline = new CReadline( m_poScreen, chatFont,
acMsg, 0, 255,
10, READLINE_Y + sge_TTF_FontAscent(chatFont), 620, C_LIGHTCYAN, C_BLACK, 255 );
while (1)
{
if ( g_oState.m_enGameMode != SState::IN_CHAT ) break;
if ( NULL == m_poSocket ) break;
Update();
if ( NULL == m_poSocket ) break;
SDL_Delay( 100 );
if ( g_oState.m_bQuitFlag ) break;
while (SDL_PollEvent(&event))
{
- if ( SDL_QUIT == event.type )
+ if ( SDL_KEYDOWN != event.type )
{
- g_oState.m_bQuitFlag = true;
- break;
+ SMortalEvent oEvent;
+ TranslateEvent( &event, &oEvent );
+ switch (oEvent.m_enType)
+ {
+ case Me_MENU:
+ Menu();
+ break;
+
+ case Me_QUIT:
+ g_oState.m_bQuitFlag = true;
+ break;
+
+ default:
+ break;
+ }
+ continue;
}
-
+
// HANDLE SCROLLING THE TEXT AREA
-
+
if ( event.type == SDL_KEYDOWN )
{
SDLKey enKey = event.key.keysym.sym;
if ( enKey == SDLK_PAGEUP || enKey == SDLK_KP9 )
{
m_poTextArea->ScrollUp();
continue;
}
if ( enKey == SDLK_PAGEDOWN || enKey == SDLK_KP3 )
{
m_poTextArea->ScrollDown();
continue;
}
if ( enKey == SDLK_ESCAPE )
{
- CChatMenu oMenu( m_asNicks );
- DoMenu( oMenu );
- if ( !g_oState.m_bQuitFlag )
- {
- if ( oMenu.GetNick() != g_oState.m_acNick )
- {
- SendRawData( 'N', oMenu.GetNick() );
- }
- if ( oMenu.GetChallengedNick().length() )
- {
- SendRawData( 'C', oMenu.GetChallengedNick() );
- MortalNetworkResetMessages( true );
- Connect( NULL );
- }
-
- Redraw();
- }
+ Menu();
continue;
}
}
m_poReadline->HandleKeyEvent( event );
int iResult = m_poReadline->GetResult();
if ( iResult > 0 )
{
if ( strlen( acMsg ) )
{
SendRawData( 'M', acMsg );
std::string sMsg = std::string("<") + g_oState.m_acNick + "> " + acMsg;
m_poTextArea->AddString( sMsg.c_str(), C_LIGHTCYAN );
m_poTextArea->Redraw();
}
m_poReadline->Clear();
acMsg[0] = 0;
m_poReadline->Restart( acMsg, strlen(acMsg), 256, C_LIGHTCYAN, C_BLACK, 255 );
}
}
}
if ( NULL == m_poSocket
&& !g_oState.m_bQuitFlag )
{
DrawTextMSZ( "Connection closed.", inkFont, 320, 210, AlignHCenter | UseShadow, C_WHITE, m_poScreen );
DrawTextMSZ( m_sLastError.c_str(), impactFont, 320, 250, AlignHCenter | UseShadow, C_WHITE, m_poScreen );
- GetKey();
+ SDL_Delay( 1000 );
+ GetKey( true );
}
delete m_poReadline;
m_poReadline = NULL;
delete m_poTextArea;
m_poTextArea = NULL;
Stop();
}
+void COnlineChat::Menu()
+{
+ CChatMenu oMenu( m_asNicks );
+ DoMenu( oMenu );
+ if ( !g_oState.m_bQuitFlag )
+ {
+ if ( oMenu.GetNick() != g_oState.m_acNick )
+ {
+ SendRawData( 'N', oMenu.GetNick() );
+ }
+ if ( oMenu.GetChallengedNick().length() )
+ {
+ SendRawData( 'C', oMenu.GetChallengedNick() );
+ MortalNetworkResetMessages( true );
+ Connect( NULL );
+ }
+
+ Redraw();
+ }
+}
+
+
/** Static global entry point for chatting. */
void DoOnlineChat()
{
g_oState.m_enGameMode = SState::IN_CHAT;
COnlineChat oChat;
oChat.DoOnlineChat();
}
diff --git a/src/OnlineChat.h b/src/OnlineChat.h
index 15a3843..68a4552 100644
--- a/src/OnlineChat.h
+++ b/src/OnlineChat.h
@@ -1,91 +1,92 @@
/***************************************************************************
OnlineChat.h - description
-------------------
begin : Thu Jan 29 2004
copyright : (C) 2004 by upi
email : upi@feel
***************************************************************************/
#ifndef ONLINECHAT_H
#define ONLINECHAT_H
/** The "mortal.net" chat protocoll should be simple enough...
[LOGGING IN]
Server: <greeting msg>
Client: N <version> <nickname>
Server: OK <actual nickname>
[CHATTING]
Server: J <user> <IP> - User joins.
Server: L <user> - User leaves.
Server: N <user> <newnick> - Nick change.
Server: W <user> <IP> - Whois response
Server: Y <num> - You are now known as...
Server: C <user> - Someone has challenged you!
Server: M <user> <text> - Public message.
Server: S <text> - Server message.
Client: M <text> - Send message.
Client: W <user> - WHOIS query
Client: L - Quit
Client: C <user> - Challenge a user
*/
#include "SDL_net.h"
#include <string>
#include <map>
class CReadline;
class CTextArea;
struct SDL_Surface;
typedef std::map<std::string,std::string> TNickMap;
class COnlineChat
{
public:
COnlineChat();
~COnlineChat();
bool Start();
void Stop();
void DoOnlineChat();
protected:
void Redraw();
void Update(); // Read network traffic. Might get disconnected...
void SendRawData( char a_cID, const std::string& a_rsData );
void ReceiveMsg( char a_cID, char* a_pcData );
void ReceiveUser( char a_cID, char* a_pcData );
void DrawNickList();
+ void Menu();
protected:
TCPsocket m_poSocket; ///< The TCP/IP network socket.
SDLNet_SocketSet m_poSocketSet; ///< SDLNet construct for watching the socket.
char m_acIncomingBuffer[4096]; ///< Received data goes here.
int m_iIncomingBufferSize; ///< How much of the buffer is filled?
std::string m_sLastError; ///< The last error message from SDLNet
SDL_Surface* m_poScreen;
SDL_Surface* m_poBackground;
CReadline* m_poReadline;
CTextArea* m_poTextArea;
bool m_bMyNickIsOk;
TNickMap m_asNicks;
};
#endif // ONLINECHAT_H
diff --git a/src/PlayerSelect.cpp b/src/PlayerSelect.cpp
index 9a99198..fa1d015 100644
--- a/src/PlayerSelect.cpp
+++ b/src/PlayerSelect.cpp
@@ -1,736 +1,737 @@
/***************************************************************************
PlayerSelect.cpp - description
-------------------
begin : Sun Dec 8 2002
copyright : (C) 2002 by upi
email : upi@apocalypse.rulez.org
***************************************************************************/
#include <stdio.h>
#include "PlayerSelect.h"
#include "SDL.h"
#include "SDL_video.h"
#include "SDL_image.h"
#include "sge_primitives.h"
#include "sge_surface.h"
#include "common.h"
#include "Audio.h"
#include "sge_bm_text.h"
#include "gfx.h"
#include "RlePack.h"
#include "Backend.h"
#include "State.h"
#include "MortalNetwork.h"
#include "Chooser.h"
#include "sge_tt_text.h"
#include "TextArea.h"
+#include "Event.h"
#ifndef NULL
#define NULL 0
#endif
/***************************************************************************
PUBLIC EXPORTED VARIABLES
***************************************************************************/
PlayerSelect g_oPlayerSelect;
/***************************************************************************
PRIVATE VARIABLES (perl variable space)
***************************************************************************/
FighterEnum ChooserCells[5][4] = {
{ ZOLI, UPI, CUMI, SIRPI },
{ ULMAR, MACI, GRIZLI, DESCANT },
{ DANI, AMBRUS, BENCE, SURBA },
{ (FighterEnum)100, (FighterEnum)101, (FighterEnum)102, (FighterEnum)103 },
{ (FighterEnum)104, (FighterEnum)105, KINGA, MISI }
};
FighterEnum ChooserCellsChat[4][5] = {
{ ZOLI, UPI, CUMI, SIRPI, ULMAR },
{ MACI, BENCE, GRIZLI, DESCANT, SURBA },
{ DANI, AMBRUS, (FighterEnum)100, (FighterEnum)102, KINGA },
{ (FighterEnum)104, (FighterEnum)105, (FighterEnum)103, (FighterEnum)101, MISI },
};
PlayerSelect::PlayerSelect()
{
for ( int i=0; i<2; ++i )
{
m_aoPlayers[i].m_enFighter = UNKNOWN;
m_aoPlayers[i].m_enTint = NO_TINT;
m_aoPlayers[i].m_poPack = NULL;
}
m_iP1 = 0;
m_iP2 = 3;
}
const PlayerInfo& PlayerSelect::GetPlayerInfo( int a_iPlayer )
{
return m_aoPlayers[ a_iPlayer ? 1 : 0 ];
}
const char* PlayerSelect::GetFighterName( int a_iPlayer )
{
return m_aoPlayers[ a_iPlayer ? 1 : 0 ].m_sFighterName.c_str();
}
int PlayerSelect::GetFighterNameWidth( int a_iPlayer )
{
return m_aiFighterNameWidth[ a_iPlayer ? 1 : 0 ];
}
bool PlayerSelect::IsFighterAvailable( FighterEnum a_enFighter )
{
if ( a_enFighter <= UNKNOWN )
{
return false;
}
bool bLocalAvailable = IsLocalFighterAvailable( a_enFighter );
if ( !IsNetworkGame() || !bLocalAvailable )
{
return bLocalAvailable;
}
// Check the remote site
return g_poNetwork->IsRemoteFighterAvailable( a_enFighter );
}
bool PlayerSelect::IsLocalFighterAvailable( FighterEnum a_enFighter )
{
if ( a_enFighter <= UNKNOWN )
{
return false;
}
g_oBackend.PerlEvalF("GetFighterStats(%d);", a_enFighter);
const char* pcDatafile = g_oBackend.GetPerlString("Datafile");
return pcDatafile && *pcDatafile;
}
/** LoadFighter simply looks up the filename associated with the given
fighter, loads it, and returns the RlePack.
\return The freshly loaded RlePack, or NULL if it could not be loaded.
*/
RlePack* PlayerSelect::LoadFighter( FighterEnum m_enFighter ) // static
{
char a_pcFilename[FILENAME_MAX+1];
const char* s;
g_oBackend.PerlEvalF( "GetFighterStats(%d);", m_enFighter );
s = g_oBackend.GetPerlString( "Datafile" );
strcpy( a_pcFilename, DATADIR );
strcat( a_pcFilename, "/characters/" );
strcat( a_pcFilename, s );
RlePack* pack = new RlePack( a_pcFilename, COLORSPERPLAYER );
if ( pack->Count() <= 0 )
{
debug( "Couldn't load RlePack: '%s'\n", a_pcFilename );
delete pack;
return NULL;
}
return pack;
}
/** SetPlayer loads the given fighter for the given player.
The RlePack is loaded first. If that succeeds, then the perl backend is
set too. The tint and palette of both players are set. */
void PlayerSelect::SetPlayer( int a_iPlayer, FighterEnum a_enFighter )
{
if ( a_iPlayer ) a_iPlayer = 1; // It's 0 or 1.
if ( m_aoPlayers[a_iPlayer].m_enFighter == a_enFighter )
{
if ( m_aoPlayers[a_iPlayer].m_poPack )
{
m_aoPlayers[a_iPlayer].m_poPack->ApplyPalette();
}
return;
}
if ( !IsFighterAvailable( a_enFighter ) )
{
return;
}
int iOffset = a_iPlayer ? COLOROFFSETPLAYER2 : COLOROFFSETPLAYER1;
RlePack* poPack = LoadFighter( a_enFighter );
poPack->OffsetSprites( iOffset );
if ( NULL == poPack )
{
debug( "SetPlayer(%d,%d): Couldn't load RlePack\n", a_iPlayer, a_enFighter );
return;
}
delete m_aoPlayers[a_iPlayer].m_poPack;
m_aoPlayers[a_iPlayer].m_poPack = poPack;
m_aoPlayers[a_iPlayer].m_enFighter = a_enFighter;
g_oBackend.PerlEvalF( "SetPlayerNumber(%d,%d);", a_iPlayer, a_enFighter );
m_aoPlayers[a_iPlayer].m_sFighterName = g_oBackend.GetPerlString( "PlayerName" );
m_aiFighterNameWidth[a_iPlayer] = sge_BF_TextSize( fastFont, GetFighterName(a_iPlayer) ).w;
TintEnum enTint = NO_TINT;
if ( m_aoPlayers[0].m_enFighter == m_aoPlayers[1].m_enFighter )
{
enTint = TintEnum( (rand() % 4) + 1 );
}
SetTint( 1, enTint );
m_aoPlayers[a_iPlayer].m_poPack->ApplyPalette();
}
void PlayerSelect::SetTint( int a_iPlayer, TintEnum a_enTint )
{
m_aoPlayers[a_iPlayer].m_enTint = a_enTint;
if ( m_aoPlayers[a_iPlayer].m_poPack )
{
m_aoPlayers[a_iPlayer].m_poPack->SetTint( a_enTint );
m_aoPlayers[a_iPlayer].m_poPack->ApplyPalette();
}
}
bool PlayerSelect::IsNetworkGame()
{
return SState::IN_NETWORK == g_oState.m_enGameMode;
}
FighterEnum PlayerSelect::GetFighterCell( int a_iIndex )
{
if ( IsNetworkGame() )
{
return ChooserCellsChat[a_iIndex/m_iChooserCols][a_iIndex%m_iChooserCols];
}
else
{
return ChooserCells[a_iIndex/m_iChooserCols][a_iIndex%m_iChooserCols];
}
}
void PlayerSelect::HandleKey( int a_iPlayer, int a_iKey )
{
// If we are in network mode, all keys count as the local player's...
if ( IsNetworkGame() )
{
a_iPlayer = g_poNetwork->IsMaster() ? 0 : 1;
}
int& riP = a_iPlayer ? m_iP2 : m_iP1;
int iOldP = riP;
bool& rbDone = a_iPlayer ? m_bDone2 : m_bDone1;
if ( rbDone )
{
return;
}
switch ( a_iKey )
{
case 0: // up
if ( riP >= m_iChooserCols ) riP -= m_iChooserCols;
break;
case 1: // down
if ( (riP/m_iChooserCols) < (m_iChooserRows-1) ) riP += m_iChooserCols;
break;
case 2: // left
if ( (riP % m_iChooserCols) > 0 ) riP--;
break;
case 3: // right
if ( (riP % m_iChooserCols) < (m_iChooserCols-1) ) riP++;
break;
default:
if ( IsFighterAvailable( GetFighterCell(riP) ) )
{
Audio->PlaySample("magic.voc");
rbDone = true;
g_oBackend.PerlEvalF( "PlayerSelected(%d);", a_iPlayer );
if ( IsNetworkGame() )
{
g_poNetwork->SendFighter( GetFighterCell(riP) );
g_poNetwork->SendReady();
}
return;
}
}
if ( iOldP != riP )
{
Audio->PlaySample("strange_quack.voc");
if ( IsFighterAvailable( GetFighterCell(riP) ) )
{
if ( IsNetworkGame() )
{
g_poNetwork->SendFighter( GetFighterCell(riP) );
}
SetPlayer( a_iPlayer, GetFighterCell(riP) );
}
}
}
void PlayerSelect::HandleNetwork()
{
g_poNetwork->Update();
bool bUpdateText = false;
while ( g_poNetwork->IsMsgAvailable() )
{
const char* pcMsg = g_poNetwork->GetMsg();
int iColor = C_YELLOW;
if ( pcMsg[0] == '*' && pcMsg[1] == '*' && pcMsg[2] == '*' ) iColor = C_WHITE;
m_poTextArea->AddString( pcMsg, iColor );
bUpdateText = true;
}
if ( bUpdateText )
{
Audio->PlaySample("pop.wav");
m_poTextArea->Redraw();
}
bool bMaster = g_poNetwork->IsMaster();
int iPlayer = bMaster ? 1 : 0;
int& riP = bMaster ? m_iP2 : m_iP1;
bool& rbDone = bMaster ? m_bDone2 : m_bDone1;
if ( rbDone )
{
return;
}
int iOldP = riP;
FighterEnum enOldFighter = GetFighterCell(iOldP);
FighterEnum enRemoteFighter = g_poNetwork->GetRemoteFighter();
if ( enOldFighter != enRemoteFighter
&& enRemoteFighter != UNKNOWN )
{
Audio->PlaySample("strange_quack.voc");
SetPlayer( iPlayer, enRemoteFighter );
int i, j;
for ( i=0; i<m_iChooserRows; ++i )
{
for ( int j=0; j<m_iChooserCols; ++j )
{
if ( ChooserCellsChat[i][j] == enRemoteFighter )
{
riP = i * m_iChooserCols + j;
break;
}
}
}
}
bool bDone = g_poNetwork->IsRemoteSideReady();
if ( bDone )
{
rbDone = true;
Audio->PlaySample("magic.voc");
g_oBackend.PerlEvalF( "PlayerSelected(%d);", iPlayer );
}
}
void PlayerSelect::DrawRect( int a_iPos, int a_iColor )
{
int iRow = a_iPos / m_iChooserCols;
int iCol = a_iPos % m_iChooserCols;
SDL_Rect r, r1;
r.x = m_iChooserLeft + iCol * m_iChooserWidth;
r.y = m_iChooserTop + iRow * m_iChooserHeight;
r.w = m_iChooserWidth + 5;
r.h = 5;
r1 = r;
SDL_FillRect( gamescreen, &r1, a_iColor );
r.y += m_iChooserHeight;
r1 = r;
SDL_FillRect( gamescreen, &r1, a_iColor );
r.y -= m_iChooserHeight;
r.w = 5;
r.h = m_iChooserHeight + 5;
r1 = r;
SDL_FillRect( gamescreen, &r1, a_iColor );
r.x += m_iChooserWidth;
r1 = r;
SDL_FillRect( gamescreen, &r1, a_iColor );
}
void PlayerSelect::CheckPlayer( SDL_Surface* a_poBackground, int a_iRow, int a_iCol, int a_iColor )
{
int x1, y1;
x1 = m_iChooserLeft + a_iCol * m_iChooserWidth +5;
y1 = m_iChooserTop + a_iRow * m_iChooserHeight +5;
sge_Line(a_poBackground, x1+5, y1+5, x1 + m_iChooserWidth-10, y1 + m_iChooserHeight-10, a_iColor);
sge_Line(a_poBackground, x1 + m_iChooserWidth-10, y1+5, x1+5, y1 + m_iChooserHeight-10, a_iColor);
x1++;
sge_Line(a_poBackground, x1+5, y1+5, x1 + m_iChooserWidth-10, y1 + m_iChooserHeight-10, a_iColor);
sge_Line(a_poBackground, x1 + m_iChooserWidth-10, y1+5, x1+5, y1 + m_iChooserHeight-10, a_iColor);
y1++;
sge_Line(a_poBackground, x1+5, y1+5, x1 + m_iChooserWidth-10, y1 + m_iChooserHeight-10, a_iColor);
sge_Line(a_poBackground, x1 + m_iChooserWidth-10, y1+5, x1+5, y1 + m_iChooserHeight-10, a_iColor);
x1--;
sge_Line(a_poBackground, x1+5, y1+5, x1 + m_iChooserWidth-10, y1 + m_iChooserHeight-10, a_iColor);
sge_Line(a_poBackground, x1 + m_iChooserWidth-10, y1+5, x1+5, y1 + m_iChooserHeight-10, a_iColor);
}
void PlayerSelect::DoPlayerSelect()
{
// 1. Set up: Load background, mark unavailable fighters
bool bNetworkMode = IsNetworkGame();
if ( bNetworkMode )
{
m_iChooserLeft = 158;
m_iChooserTop = 26;
m_iChooserHeight = 64;
m_iChooserWidth = 64;
m_iChooserRows = 4;
m_iChooserCols = 5;
}
else
{
m_iChooserLeft = 158;
m_iChooserTop = 74;
m_iChooserHeight = 80;
m_iChooserWidth = 80;
m_iChooserRows = 5;
m_iChooserCols = 4;
}
SDL_FillRect( gamescreen, NULL, C_BLACK );
SDL_Flip( gamescreen );
SDL_Surface* poBackground = LoadBackground( bNetworkMode ? "PlayerSelect_chat.png" : "PlayerSelect.png", 111 );
if ( !bNetworkMode )
{
DrawGradientText( "Choose A Fighter Dammit", titleFont, 10, poBackground );
}
//g_oChooser.Draw( poBackground );
int i, j;
for ( i=0; i<m_iChooserRows; ++i )
{
for ( int j=0; j<m_iChooserCols; ++j )
{
if ( bNetworkMode )
{
if ( !IsLocalFighterAvailable(ChooserCellsChat[i][j]) &&
UNKNOWN != ChooserCellsChat[i][j] )
{
CheckPlayer( poBackground, i, j, C_LIGHTRED );
}
else if ( !IsFighterAvailable(ChooserCellsChat[i][j]) &&
UNKNOWN != ChooserCellsChat[i][j] )
{
CheckPlayer( poBackground, i, j, C_LIGHTBLUE );
}
}
else
{
if ( !IsFighterAvailable(ChooserCells[i][j]) &&
UNKNOWN != ChooserCells[i][j] )
{
CheckPlayer( poBackground, i, j, C_LIGHTRED );
}
}
}
}
for ( i=0; i<2; ++i )
{
if ( m_aoPlayers[i].m_poPack ) m_aoPlayers[i].m_poPack->ApplyPalette();
}
SetPlayer( 0, GetFighterCell(m_iP1) );
SetPlayer( 1, GetFighterCell(m_iP2) );
if ( bNetworkMode && g_poNetwork->IsMaster() )
{
g_poNetwork->SendGameParams( g_oState.m_iGameSpeed, g_oState.m_iGameTime, g_oState.m_iHitPoints );
}
// 2. Run selection screen
g_oBackend.PerlEvalF( "SelectStart();" );
m_bDone1 = m_bDone2 = false;
int thisTick, lastTick, gameSpeed;
gameSpeed = 12 ;
thisTick = SDL_GetTicks() / gameSpeed;
lastTick = thisTick - 1;
i = 0;
int over = 0;
int iCourtain = 0;
int iCourtainSpeed = 0;
int iCourtainTime = 80;
SDL_Event event;
// Chat is 165:318 - 470:470
char acMsg[256];
sprintf( acMsg, "Press Enter to chat, Page Up/Page Down to scroll..." );
bool bDoingChat = false;
if ( bNetworkMode )
{
m_poReadline = new CReadline( IsNetworkGame() ? poBackground : NULL, chatFont,
acMsg, strlen(acMsg), 256, 15, 465, 610, C_LIGHTCYAN, C_BLACK, 255 );
m_poTextArea = new CTextArea( poBackground, chatFont, 15, 313, 610, 32*4 );
}
else
{
m_poReadline = NULL;
m_poTextArea = NULL;
}
while (1)
{
// 1. Wait for the next tick (on extremely fast machines..)
while (1)
{
thisTick = SDL_GetTicks() / gameSpeed;
if ( thisTick==lastTick )
{
SDL_Delay(1);
}
else
{
break;
}
}
// 2. Advance as many ticks as necessary..
if ( iCourtainTime > 0 )
{
int iAdvance = thisTick - lastTick;
if ( iAdvance > 5 ) iAdvance = 5;
if ( iCourtain + iCourtainSpeed * iCourtainTime /2 < 320 * 4 )
iCourtainSpeed += iAdvance;
else
iCourtainSpeed -= iAdvance;
iCourtain += iCourtainSpeed * iAdvance;
iCourtainTime -= iAdvance;
if ( iCourtainTime > 0 )
{
SDL_Rect oRect;
oRect.x = 320 - iCourtain/4; oRect.y = 0;
oRect.w = iCourtain / 2; oRect.h = gamescreen->h;
if ( oRect.x < 0 ) oRect.x = 0;
if ( oRect.w > gamescreen->w ) oRect.w = gamescreen->w;
SDL_SetClipRect( gamescreen, &oRect );
}
else
{
SDL_SetClipRect( gamescreen, NULL );
}
}
int iNumFrames = thisTick - lastTick;
if ( iNumFrames>5 ) iNumFrames = 5;
for ( i=0; i<iNumFrames; ++i )
{
g_oBackend.AdvancePerl();
}
lastTick = thisTick;
while (SDL_PollEvent(&event))
{
if ( SDL_QUIT == event.type )
{
g_oState.m_bQuitFlag = true;
break;
}
// HANDLE SCROLLING THE TEXT AREA
- if ( event.type == SDL_KEYDOWN )
+ if ( event.type == SDL_KEYDOWN && IsNetworkGame() )
{
SDLKey enKey = event.key.keysym.sym;
- if ( IsNetworkGame() )
+ if ( enKey == SDLK_PAGEUP || enKey == SDLK_KP9 )
{
- if ( enKey == SDLK_PAGEUP || enKey == SDLK_KP9 )
- {
- m_poTextArea->ScrollUp();
- continue;
- }
- if ( enKey == SDLK_PAGEDOWN || enKey == SDLK_KP3 )
- {
- m_poTextArea->ScrollDown();
- continue;
- }
+ m_poTextArea->ScrollUp();
+ continue;
+ }
+ if ( enKey == SDLK_PAGEDOWN || enKey == SDLK_KP3 )
+ {
+ m_poTextArea->ScrollDown();
+ continue;
}
}
// HANDLE CHATTING
- if ( bDoingChat )
+ if ( bDoingChat && SDL_KEYDOWN==event.type )
{
// The chat thingy will handle this event.
m_poReadline->HandleKeyEvent( event );
int iResult = m_poReadline->GetResult();
if ( iResult < 0 )
{
// Escape was pressed?
m_poReadline->Clear();
bDoingChat = false;
}
if ( iResult > 0 )
{
if ( strlen( acMsg ) )
{
g_poNetwork->SendMsg( acMsg );
std::string sMsg = std::string("<") + g_oState.m_acNick + "> " + acMsg;
m_poTextArea->AddString( sMsg.c_str(), C_LIGHTCYAN );
m_poTextArea->Redraw();
m_poReadline->Clear();
acMsg[0] = 0;
m_poReadline->Restart( acMsg, strlen(acMsg), 256, C_LIGHTCYAN, C_BLACK, 255 );
}
else
{
m_poReadline->Clear();
bDoingChat = false;
}
}
continue;
}
- // HANDLE OTHER TYPES OF KEYBOARD EVENTS
+ // HANDLE OTHER TYPES OF EVENTS
+
+ if ( IsNetworkGame() && bDoingChat == false &&
+ SDL_KEYDOWN == event.type &&
+ (event.key.keysym.sym == SDLK_RETURN || event.key.keysym.sym==SDLK_KP_ENTER) )
+ {
+ bDoingChat = true;
+ acMsg[0] = 0;
+ m_poReadline->Clear();
+ m_poReadline->Restart( acMsg, strlen(acMsg), 256, C_LIGHTCYAN, C_BLACK, 255 );
+ break;
+ }
+
+ SMortalEvent oEvent;
+ TranslateEvent( &event, &oEvent );
- if ( event.type == SDL_KEYDOWN )
+ switch ( oEvent.m_enType )
{
- SDLKey enKey = event.key.keysym.sym;
+ case Me_QUIT:
+ g_oState.m_bQuitFlag = true;
+ break;
- if ( enKey == SDLK_ESCAPE )
- {
+ case Me_MENU:
DoMenu();
if ( IsNetworkGame() && g_poNetwork->IsMaster() )
{
g_poNetwork->SendGameParams( g_oState.m_iGameSpeed, g_oState.m_iGameTime, g_oState.m_iHitPoints );
}
break;
- }
- if ( IsNetworkGame() && bDoingChat == false &&
- (event.key.keysym.sym == SDLK_RETURN
- || event.key.keysym.sym==SDLK_KP_ENTER) )
- {
- bDoingChat = true;
- acMsg[0] = 0;
- m_poReadline->Clear();
- m_poReadline->Restart( acMsg, strlen(acMsg), 256, C_LIGHTCYAN, C_BLACK, 255 );
+
+ case Me_PLAYERKEYDOWN:
+ DrawRect( m_iP1, 240 );
+ DrawRect( m_iP2, 240 );
+ HandleKey( oEvent.m_iPlayer, oEvent.m_iKey );
break;
- }
- for ( i=0; i<2; i++ )
- {
- for ( j=0; j<9; j++ )
- {
- if (g_oState.m_aiPlayerKeys[i][j] == event.key.keysym.sym)
- {
- DrawRect( m_iP1, 240 );
- DrawRect( m_iP2, 240 );
- HandleKey( i, j );
- }
- }
- }
- }
+
+ case Me_NOTHING:
+ case Me_SKIP:
+ case Me_PLAYERKEYUP:
+ break;
+ } // end of switch statement
} // Polling events
if ( IsNetworkGame() )
{
HandleNetwork();
}
g_oBackend.ReadFromPerl();
over = g_oBackend.m_iGameOver;
SDL_BlitSurface( poBackground, NULL, gamescreen, NULL );
if ( !m_bDone1) DrawRect( m_iP1, 250 );
if ( !m_bDone2) DrawRect( m_iP2, 253 );
for ( i=0; i<2; ++i )
{
int iYOffset = bNetworkMode ? -130 : 0;
if ( g_oBackend.m_aoPlayers[i].m_iFrame )
{
m_aoPlayers[i].m_poPack->Draw(
ABS(g_oBackend.m_aoPlayers[i].m_iFrame)-1,
g_oBackend.m_aoPlayers[i].m_iX, g_oBackend.m_aoPlayers[i].m_iY + iYOffset,
g_oBackend.m_aoPlayers[i].m_iFrame < 0 );
}
int x = ( m_iChooserLeft - m_aiFighterNameWidth[i] ) / 2;
if ( x<10 ) x = 10;
if ( i ) x = gamescreen->w - x - m_aiFighterNameWidth[i];
sge_BF_textout( gamescreen, fastFont, GetFighterName(i),
x, gamescreen->h - 30 + iYOffset - (bNetworkMode ? 40 : 0) );
}
SDL_Flip( gamescreen );
if (over || g_oState.m_bQuitFlag || SState::IN_DEMO == g_oState.m_enGameMode) break;
}
delete m_poReadline;
delete m_poTextArea;
SDL_FreeSurface( poBackground );
SDL_SetClipRect( gamescreen, NULL );
return;
}
diff --git a/src/common.cpp b/src/common.cpp
index 7459317..4d5125d 100644
--- a/src/common.cpp
+++ b/src/common.cpp
@@ -1,121 +1,177 @@
/***************************************************************************
common.cpp - description
-------------------
begin : Fri Aug 24 2001
copyright : (C) 2001 by upi
email : upi@apocalypse.rulez.org
***************************************************************************/
#include <stdio.h>
#include <stdarg.h>
#include "common.h"
#include "State.h"
#include "Joystick.h"
#include "SDL/SDL.h"
#include "Event.h"
SDL_Surface* gamescreen = NULL;
void debug( const char* format, ... )
{
va_list ap;
va_start( ap, format );
vfprintf( stderr, format, ap );
va_end( ap );
}
bool FindPlayerKey( SDLKey a_enKey, int& a_riOutPlayer, int& a_riOutKey )
{
for (int i=0; i<2; i++)
{
for (int j=0; j<9; j++ )
{
if (g_oState.m_aiPlayerKeys[i][j] == a_enKey )
{
a_riOutPlayer = i;
a_riOutKey = j;
return true;
}
}
}
return false;
}
+/**
+TranslateEvent is an important function in the OpenMortal event processing
+chain. It takes an SDL_Event and converts it to a game related event. This
+allows for the "transparent" handling of joysticks and such.
+
+\param a_poInEvent The SDL event which is to be translated.
+\param a_poOutEvent The output event.
+
+\returns true if the event could be translated (it was relevant for the game),
+or false if it couldn't (a_poOutEvent will be set to Me_NOTHING).
+*/
+
bool TranslateEvent( const SDL_Event* a_poInEvent, SMortalEvent* a_poOutEvent )
{
a_poOutEvent->m_enType = Me_NOTHING;
switch ( a_poInEvent->type )
{
case SDL_QUIT:
a_poOutEvent->m_enType = Me_QUIT;
g_oState.m_bQuitFlag = true;
return true;
case SDL_KEYDOWN:
{
SDLKey enKey = a_poInEvent->key.keysym.sym;
if ( enKey == SDLK_ESCAPE )
{
a_poOutEvent->m_enType = Me_MENU;
return true;
}
if ( enKey == SDLK_F1 )
{
a_poOutEvent->m_enType = Me_SKIP;
return true;
}
// Check the player keys
int iPlayer;
int iKey;
bool bFound = FindPlayerKey( enKey, iPlayer, iKey );
if ( bFound )
{
a_poOutEvent->m_enType = Me_PLAYERKEYDOWN;
a_poOutEvent->m_iPlayer = iPlayer;
a_poOutEvent->m_iKey = iKey;
return true;
}
break;
}
case SDL_KEYUP:
{
SDLKey enKey = a_poInEvent->key.keysym.sym;
int iPlayer;
int iKey;
bool bFound = FindPlayerKey( enKey, iPlayer, iKey );
if ( bFound )
{
a_poOutEvent->m_enType = Me_PLAYERKEYUP;
a_poOutEvent->m_iPlayer = iPlayer;
a_poOutEvent->m_iKey = iKey;
return true;
}
break;
}
case SDL_JOYAXISMOTION:
case SDL_JOYBALLMOTION:
case SDL_JOYHATMOTION:
case SDL_JOYBUTTONDOWN:
case SDL_JOYBUTTONUP:
{
return g_oJoystick.TranslateEvent( a_poInEvent, a_poOutEvent );
}
} // switch
return false;
}
+
+
+/** MortalPollEvent works like SDL_PollEvent, except that it
+returns an SMortalEvent.
+*/
+
+bool MortalPollEvent( SMortalEvent& a_roOutEvent )
+{
+ SDL_Event oEvent;
+
+ while ( SDL_PollEvent( &oEvent ) )
+ {
+ if ( TranslateEvent( &oEvent, &a_roOutEvent ) )
+ {
+ return true;
+ }
+ }
+
+ a_roOutEvent.m_enType = Me_NOTHING;
+ return false;
+}
+
+
+/** MortalWaitEvent works like SDL_WaitEvent, except that it
+returns an SMortalEvent.
+*/
+
+void MortalWaitEvent( SMortalEvent& a_roOutEvent )
+{
+ SDL_Event oEvent;
+
+ if ( SDL_WaitEvent( &oEvent ) )
+ {
+ if ( TranslateEvent( &oEvent, &a_roOutEvent ) )
+ {
+ return;
+ }
+ }
+
+ a_roOutEvent.m_enType = Me_NOTHING;
+ return;
+}
+
+
diff --git a/src/gfx.cpp b/src/gfx.cpp
index b3f538f..cdd1039 100644
--- a/src/gfx.cpp
+++ b/src/gfx.cpp
@@ -1,323 +1,362 @@
/***************************************************************************
gfx.cpp - description
-------------------
begin : Tue Apr 10 2001
copyright : (C) 2001 by UPi
email : upi@apocalypse.rulez.org
***************************************************************************/
#include <string.h>
#include <malloc.h>
#include "SDL.h"
#include "SDL_video.h"
#include "SDL_image.h"
+
#include "sge_tt_text.h"
#include "sge_surface.h"
#ifndef __COMMON_H
#include "common.h"
#endif
#ifndef _GFX_H
#include "gfx.h"
#endif
#include "State.h"
+#include "Event.h"
Uint16 *UTF8_to_UNICODE(Uint16 *unicode, const char *utf8, int len);
void sge_TTF_SizeText( _sge_TTFont*font, const char* text, int* x, int* y )
{
#ifdef MSZ_USES_UTF8
Uint16 *unicode_text;
int unicode_len;
/* Copy the UTF-8 text to a UNICODE text buffer */
unicode_len = strlen(text);
unicode_text = (Uint16 *)malloc( (unicode_len+1) * sizeof (Uint16) );
if ( unicode_text == NULL )
{
SDL_SetError("SGE - Out of memory");
*x = *y = 0;
return;
}
UTF8_to_UNICODE(unicode_text, text, unicode_len);
/* Render the new text */
SDL_Rect r = sge_TTF_TextSizeUNI(font, unicode_text);
/* Free the text buffer and return */
free(unicode_text);
#else
SDL_Rect r = sge_TTF_TextSize( font, text );
#endif
*x = r.w;
*y = r.h;
}
int DrawTextMSZ( const char* string, _sge_TTFont* font, int x, int y, int flags,
int fg, SDL_Surface* target, bool a_bTranslate )
{
int retval = 0;
if (!string || !*string) return retval;
if ( a_bTranslate )
{
string = Translate( string );
}
if (flags & UseTilde)
{
char *str2 = strdup( string );
char onechar[2];
char *c1, *c2, *c3;
int w = 0;
int i, j;
bool notend;
if (flags & AlignHCenter)
{
// Determine width of the string without the stupid tildes
c1 = c2 = str2;
notend = true;
while (notend)
{
c2 = c1; // c1: start of this run
while (*c2 && (*c2!='~')) c2++; // c2: end of this run
notend = *c2;
*c2 = 0;
sge_TTF_SizeText( font, c1, &i, &j);
w += i;
if (notend) { *c2='~'; c1=c2+1; } // next run..
}
x -= w/2;
}
flags &= ~(UseTilde | AlignHCenter);
c1 = str2;
onechar[1]=0;
notend = true;
while (1)
{
c2 = c1;
while (*c2 && (*c2!='~')) c2++; // c2: end of this run
notend = *c2;
*c2 = 0;
sge_TTF_SizeText( font, c1, &i, &j);
DrawTextMSZ( c1, font, x, y, flags, fg, target, false );
x += i;
// At this point, we're either at a ~ or end of the text (notend)
if (!notend) break;
onechar[0]= *++c2; // Could be 0, if ~ at end.
if (!onechar[0]) break;
sge_TTF_SizeText( font, onechar, &i, &j);
DrawTextMSZ( onechar, font, x, y, flags, C_LIGHTCYAN, target, false );
x += i;
retval += i;
c1 = c2+1;
if (!*c1) break; // ~X was end of string
}
delete( str2 );
return retval;
}
SDL_Rect dest;
int w, h;
sge_TTF_SizeText( font, string, &w, &h );
dest.w = retval = w;
dest.h = h;
dest.x = flags & AlignHCenter ? x-dest.w/2 : x;
dest.y = flags & AlignVCenter ? y-dest.h/2 : y;
//debug( "X: %d, Y: %d, W: %d, H: %d\n", dest.x, dest.y, dest.w, dest.h );
if ( flags & UseShadow )
{
#ifdef MSZ_USES_UTF8
sge_tt_textout_UTF8( target, font, string, dest.x+2, dest.y+2+sge_TTF_FontAscent(font), C_BLACK, C_BLACK, 255 );
#else
+
sge_tt_textout( target, font, string, dest.x+2, dest.y+2+sge_TTF_FontAscent(font), C_BLACK, C_BLACK, 255 );
#endif
}
sge_TTF_AAOn();
#ifdef MSZ_USES_UTF8
dest = sge_tt_textout_UTF8( target, font, string, dest.x, dest.y+sge_TTF_FontAscent(font), fg, C_BLACK, 255 );
#else
dest = sge_tt_textout( target, font, string, dest.x, dest.y+sge_TTF_FontAscent(font), fg, C_BLACK, 255 );
#endif
sge_TTF_AAOff();
return dest.w;
}
void DrawGradientText( const char* text, _sge_TTFont* font, int y, SDL_Surface* target, bool a_bTranslate )
{
int i, j;
if ( a_bTranslate )
{
text = Translate( text );
}
// 1. CREATE OFFSCREEN SURFACE
SDL_Rect size = sge_TTF_TextSize( font, (char*)text );
size.w += 2;
size.h += 2;
size.x = 320 - size.w / 2;
if ( size.x < 0 ) size.x = 0;
size.y = y;
SDL_Surface* surface = SDL_CreateRGBSurface( SDL_SRCCOLORKEY, size.w, size.h, 8, 0,0,0,0 );
if ( NULL == surface )
{
debug( "DrawGradientText: Couldn't allocate %d by %d surface!\n", size.w, size.h );
return;
}
// 2. SET OFFSCREEN SURFACE COLORS
SDL_SetColorKey( surface, SDL_SRCCOLORKEY, 0 );
SDL_Color colors[256];
colors[0].r = colors[0].g = colors[0].b = 0;
colors[1] = colors[0];
// The rest is red->yellow gradient.
for ( i=2; i<255; ++i )
{
int j = i > 25 ? i-25 : 0;
colors[i].r = 255;
colors[i].g = 255-j;
colors[i].b = 0;
}
SDL_SetColors( surface, colors, 0, 256 );
// 3. DRAW TEXT, APPLY BORDER, APPLY GRADIENT.
int y1 = sge_TTF_FontAscent(font);
sge_tt_textout( surface, font, text,
1, y1, 255, 0, 255);
for ( y=1; y<size.h-1; ++y )
{
int color = 254 * y / (size.h-1) + 1;
unsigned char *p0, *p1, *p2;
p1 = (unsigned char*) surface->pixels;
p1 += surface->pitch * y + 1;
p0 = p1 - surface->pitch;
p2 = p1 + surface->pitch;
for ( int x=1; x<size.w-1; ++x, ++p0, ++p1, ++p2 )
{
if ( *p1 > 2 )
{
*p1 = color;
}
else
{
if ( (*(p1-1) > 2) || (*(p1+1) > 2) || *p0 > 2 || *p2 > 2 )
{
*p1 = 1;
}
}
}
}
// 4. FINALLY
SDL_BlitSurface( surface, NULL, target, &size );
SDL_FreeSurface( surface );
SDL_UpdateRect( target, size.x, size.y, size.w, size.h );
}
SDL_Color MakeColor( Uint8 r, Uint8 g, Uint8 b )
{
SDL_Color color;
color.r = r; color.g = g; color.b = b; color.unused = 0;
return color;
}
-SDLKey GetKey()
-{
- SDL_Event event;
+/**
+Waits for a key event and returns it.
+\param a_bTranslate If this is true, then keypad events will also be
+read and processed info keys (cursor, return and escape).
+*/
+
+SDLKey GetKey( bool a_bTranslate )
+{
+ SDL_Event oSdlEvent;
+ SMortalEvent oEvent;
- while (SDL_WaitEvent(&event))
+ while (SDL_WaitEvent(&oSdlEvent))
{
- switch (event.type)
+ if ( SDL_KEYDOWN == oSdlEvent.type )
+ {
+ return oSdlEvent.key.keysym.sym;
+ }
+ if ( SDL_QUIT == oSdlEvent.type )
+ {
+ g_oState.m_bQuitFlag = true;
+ return SDLK_ESCAPE;
+ }
+
+ if ( ! a_bTranslate )
{
- case SDL_QUIT:
+ continue;
+ }
+
+ // Handle gamepad and others
+ TranslateEvent( &oSdlEvent, &oEvent );
+
+ switch (oEvent.m_enType)
+ {
+ case Me_QUIT:
g_oState.m_bQuitFlag = true;
return SDLK_ESCAPE;
- case SDL_KEYDOWN:
- {
- return event.key.keysym.sym;
- }
- break;
+ case Me_PLAYERKEYDOWN:
+ switch ( oEvent.m_iKey ) {
+ case Mk_UP: return SDLK_UP;
+ case Mk_DOWN: return SDLK_DOWN;
+ case Mk_LEFT: return SDLK_LEFT;
+ case Mk_RIGHT: return SDLK_RIGHT;
+ default: return SDLK_RETURN;
+ }
+ break;
+
+ case Me_MENU:
+ return SDLK_ESCAPE;
+
+ default:
+ break;
} // switch statement
} // Polling events
+ // Code will never reach this point, unless there's an error.
return SDLK_ESCAPE;
}
SDL_Surface* LoadBackground( const char* a_pcFilename, int a_iNumColors, int a_iPaletteOffset )
{
char filepath[FILENAME_MAX+1];
strcpy( filepath, DATADIR );
strcat( filepath, "/gfx/" );
strcat( filepath, a_pcFilename );
SDL_Surface* poBackground = IMG_Load( filepath );
if (!poBackground)
{
debug( "Can't load file: %s\n", filepath );
return NULL;
}
SDL_Palette* pal = poBackground->format->palette;
if ( pal )
{
int ncolors = pal->ncolors;
if (ncolors>a_iNumColors) ncolors = a_iNumColors;
if (ncolors+a_iPaletteOffset > 255) ncolors = 255 - a_iPaletteOffset;
SDL_SetColors( gamescreen, pal->colors, a_iPaletteOffset, ncolors );
}
SDL_Surface* poRetval = SDL_DisplayFormat( poBackground );
SDL_FreeSurface( poBackground );
return poRetval;
}
diff --git a/src/gfx.h b/src/gfx.h
index 60d768d..d62832f 100644
--- a/src/gfx.h
+++ b/src/gfx.h
@@ -1,51 +1,51 @@
/***************************************************************************
gfx.h - description
-------------------
begin : Tue Apr 10 2001
copyright : (C) 2001 by UPi
email : upi@apocalypse.rulez.org
***************************************************************************/
#ifndef _GFX_H
#define _GFX_H
struct _sge_TTFont;
enum GFX_Constants {
AlignHCenter = 1,
AlignVCenter = 2,
AlignCenter = 3,
UseTilde = 4,
UseShadow = 8,
};
int DrawTextMSZ( const char* text, _sge_TTFont* font, int x, int y,
int flags, int fg, SDL_Surface* target, bool a_bTranslate = true );
void DrawGradientText( const char* text, _sge_TTFont* font, int y,
SDL_Surface* target, bool a_bTranslate = true );
SDL_Color MakeColor( Uint8 r, Uint8 g, Uint8 b );
-SDLKey GetKey();
+SDLKey GetKey( bool a_bTranslate );
SDL_Surface* LoadBackground( const char* a_pcFilename, int a_iNumColors, int a_iPaletteOffset=0 );
extern _sge_TTFont* titleFont; // Largest font, for titles
extern _sge_TTFont* inkFont; // Medium-size front, headings
extern _sge_TTFont* impactFont; // Smallest font, for long descriptions
extern _sge_TTFont* chatFont; // small but legible.
#ifdef sge_bm_text_H
extern sge_bmpFont* fastFont; // In-game text, e.g. combo text
extern sge_bmpFont* creditsFont;
extern sge_bmpFont* storyFont;
#endif
#endif
diff --git a/src/main.cpp b/src/main.cpp
index afb58ae..7b5b219 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,408 +1,413 @@
/***************************************************************************
main.cpp - description
-------------------
begin : Wed Aug 22 10:18:47 CEST 2001
copyright : (C) 2001 by upi
email : upi@apocalypse.rulez.org
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "PlayerSelect.h"
#include "SDL_video.h"
#include "sge_tt_text.h"
#include "sge_bm_text.h"
#include "sge_surface.h"
#include "SDL.h"
#include "SDL_image.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <string>
#include "common.h"
#include "gfx.h"
#include "Audio.h"
#include "RlePack.h"
#include "Backend.h"
#include "State.h"
#include "FighterStats.h"
#include "MortalNetwork.h"
#ifdef _WINDOWS
#undef DATADIR // GRRR.. windows keyword...
#include <windows.h>
#define DATADIR "../data"
#endif
_sge_TTFont* inkFont;
_sge_TTFont* impactFont;
_sge_TTFont* titleFont;
_sge_TTFont* chatFont;
sge_bmpFont* fastFont;
sge_bmpFont* creditsFont;
sge_bmpFont* storyFont;
SDL_Color Colors[] =
{
{ 0, 0, 0, 0 }, { 0, 0, 42, 0 }, { 0, 42, 0, 0 }, { 0, 42, 42, 0 },
{ 42, 0, 0, 0 }, { 42, 0, 42, 0 }, { 63, 42, 0, 0 }, { 42, 42, 42, 0 },
{ 21, 21, 21, 0 }, { 21, 21, 63, 0 }, { 21, 63, 21, 0 }, { 21, 63, 63, 0 },
{ 63, 21, 21, 0 }, { 63, 21, 63, 0 }, { 63, 63, 21, 0 }, { 63, 63, 63, 0 }
};
void Complain( const char* a_pcError )
{
#ifdef _WINDOWS
::MessageBoxA( 0, a_pcError, "OpenMortal", MB_ICONEXCLAMATION );
#else
fprintf( stderr, "%s", a_pcError );
#endif
}
_sge_TTFont* LoadTTF( const char* a_pcFilename, int a_iSize )
{
std::string sPath = std::string(DATADIR) + "/fonts/" + a_pcFilename;
_sge_TTFont* poFont = sge_TTF_OpenFont( sPath.c_str(), a_iSize );
if ( NULL == poFont )
{
Complain( ("Couldn't load font: " + sPath).c_str() );
}
return poFont;
}
sge_bmpFont* LoadBMPFont( const char* a_pcFilename )
{
std::string sPath = std::string(DATADIR) + "/fonts/" + a_pcFilename;
sge_bmpFont* poFont = sge_BF_OpenFont( sPath.c_str(), SGE_BFSFONT | SGE_BFTRANSP );
if ( NULL == poFont )
{
Complain( ("Couldn't load font: " + sPath).c_str() );
}
return poFont;
}
int init( int iFlags )
{
if (SDL_Init(SDL_INIT_VIDEO /*| SDL_INIT_AUDIO*/) < 0)
{
fprintf(stderr, "Failed to initialize SDL: %s\n", SDL_GetError());
return -1;
}
atexit(SDL_Quit);
int d = SDL_VideoModeOK(640, 480, 8, iFlags);
if (d == 0)
{
fprintf(stderr, "requested video mode not available\n");
// return -1;
}
gamescreen = SDL_SetVideoMode(640, 480, 8, iFlags);
if (gamescreen == NULL)
{
fprintf(stderr, "failed to set video mode: %s\n", SDL_GetError());
return -1;
}
SDL_WM_SetCaption( "OpenMortal", "OpenMortal" );
std::string sPath = std::string(DATADIR) + "/gfx/icon.png";
SDL_WM_SetIcon(IMG_Load(sPath.c_str()), NULL);
SDL_ShowCursor( SDL_DISABLE );
for ( int i=0; i<16; ++i ) { Colors[i].r *=4; Colors[i].g *=4; Colors[i].b *=4; }
SDL_SetColors( gamescreen, Colors, 256-16, 16 );
if ( sge_TTF_Init() )
{
fprintf(stderr, "couldn't start ttf engine: %s\n", SDL_GetError());
return -1;
}
sge_TTF_AAOff();
inkFont = LoadTTF( "aardvark.ttf", 20 );
if ( !inkFont ) return -1;
impactFont = LoadTTF( "bradybun.ttf", 20 ); // gooddogc.ttf, 20
if ( !impactFont ) return -1;
titleFont = LoadTTF( "deadgrit.ttf", 48 ); // deadgrit.ttf, 48
if ( !titleFont ) return -1;
chatFont = LoadTTF( "thin.ttf", 20 ); // deadgrit.ttf, 48
if ( !chatFont ) return -1;
fastFont = LoadBMPFont( "brandybun3.png" );
if ( !fastFont ) return -1;
creditsFont = LoadBMPFont( "CreditsFont2.png" );//"fangfont.png" );
if ( !creditsFont ) return -1;
storyFont = LoadBMPFont( "glossyfont.png" );
if ( !storyFont ) return -1;
return 0;
}
int init2()
{
if ( !g_oBackend.Construct() )
{
fprintf(stderr, "couldn't start backend.\n" );
return -1;
}
return 0;
}
int DrawMainScreen()
{
SDL_Surface* background = LoadBackground( "Mortal.png", 240 );
- DrawTextMSZ( VERSION, inkFont, 540, 430, UseShadow | AlignHCenter, C_WHITE, background, false );
+
+ DrawTextMSZ( "Version " VERSION " ゥ 2003-2004 by UPi", inkFont, 320, 430, UseShadow | AlignHCenter, C_WHITE, background, false );
SDL_Rect r;
r.x = r.y = 0;
std::string sStaffFilename = DATADIR;
sStaffFilename += "/characters/STAFF.DAT";
RlePack pack( sStaffFilename.c_str(), 240 );
pack.ApplyPalette();
//SDL_SetColors( gamescreen, pack.getPalette(), 0, 240 );
SDL_BlitSurface( background, NULL, gamescreen, &r );
SDL_Flip( gamescreen );
char* filename[15] = {
"Jacint.pl", "Jozsi.pl", "Agent.pl", "Mrsmith.pl",
"Sleepy.pl", "Tejszin.pl",
"UPi.pl", "Zoli.pl", "Ulmar.pl", "Bence.pl",
"Descant.pl", "Grizli.pl", "Sirpi.pl", "Macy.pl", "Cumi.pl" };
int x[14] = {
0, 26, 67, 125, 159, 209,
249, 289, 358, 397, 451, 489, 532, 161 };
int y[14] = {
5, 4, 5, 5, 5, 7,
4, 0, 7, 5, 5, 6, 5, 243 };
int i;
g_oBackend.PerlEvalF( "eval( \"require '%s/characters/Kinga.pl';\" )", DATADIR );
g_oBackend.PerlEvalF( "eval( \"require '%s/characters/Ambrus.pl';\" )", DATADIR );
g_oBackend.PerlEvalF( "eval( \"require '%s/characters/Dani.pl';\" )", DATADIR );
for ( i=0; i<15; ++i )
{
pack.Draw( i, x[i], y[i], false );
SDL_Flip( gamescreen );
if ( filename[i] != NULL )
{
debug( "Loading fighter %s", filename[i] );
g_oBackend.PerlEvalF( "eval( \"require '%s/characters/%s';\" )", DATADIR, filename[i] );
}
}
int retval = 0;
i = 0;
SDL_FreeSurface( background );
return retval;
}
int InitJoystick();
int main(int argc, char *argv[])
{
srand( (unsigned int)time(NULL) );
if ( 0 != init2() )
{
fprintf( stderr, "init2() failed." );
return -1;
}
g_oState.m_pcArgv0 = argv[0];
g_oState.Load();
CMortalNetwork::Create();
bool bDebug = false;
int iFlags = SDL_SWSURFACE | SDL_HWPALETTE;
+
if ( g_oState.m_bFullscreen )
{
iFlags |= SDL_FULLSCREEN;
}
int i;
for ( i=1; i<argc; ++i )
{
if ( !strcmp(argv[i], "-debug") )
{
bDebug = true;
}
else if ( !strcmp(argv[i], "-fullscreen") )
{
iFlags |= SDL_FULLSCREEN;
}
else if ( !strcmp(argv[i], "-hwsurface") )
{
iFlags |= SDL_HWSURFACE;
}
else if ( !strcmp(argv[i], "-doublebuf") )
{
iFlags |= SDL_DOUBLEBUF;
}
else if ( !strcmp(argv[i], "-anyformat") )
{
iFlags |= SDL_ANYFORMAT;
}
else
{
printf( "Usage: %s [-debug] [-fullscreen] [-hwsurface] [-doublebuf] [-anyformat]\n", argv[0] );
return 0;
}
}
if (init( iFlags )<0)
{
return -1;
}
- // InitJoystick();
+ InitJoystick();
g_oState.SetLanguage( g_oState.m_acLanguage );
new MszAudio;
// Audio->LoadMusic( "Last_Ninja_-_The_Wilderness.mid", "DemoMusic" );
Audio->LoadMusic( "ride.mod", "DemoMusic" );
Audio->PlayMusic( "DemoMusic" );
Audio->LoadMusic( "2nd_pm.s3m", "GameMusic" );
DrawMainScreen();
g_oPlayerSelect.SetPlayer( 0, ZOLI );
g_oPlayerSelect.SetPlayer( 1, SIRPI );
/*
int nextFighter = 0;
int describeOrder[ (int)LASTFIGHTER ];
for ( i=0; i<(int)LASTFIGHTER; ++i ) describeOrder[i] = i;
for ( i=0; i<100; ++i )
{
int j = rand() % (int)LASTFIGHTER;
int k = rand() % (int)LASTFIGHTER;
int l;
l = describeOrder[j];
describeOrder[j] = describeOrder[k];
describeOrder[k] = l;
}
*/
/*
{
int iGameNumber=0;
char acReplayFile[1024];
for ( i=0; i<15; ++i )
{
sprintf( acReplayFile, DATADIR "/msz%i.replay", i );
DrawTextMSZ( acReplayFile, impactFont, 10, 10, 0, C_WHITE, gamescreen );
SDL_Delay(5000 );
DoGame( acReplayFile, true, bDebug );
}
}
*/
bool bNetworkGame = false;
while ( 1 )
{
if ( g_oState.m_bQuitFlag ) break;
switch ( g_oState.m_enGameMode )
{
case SState::IN_DEMO:
DoDemos();
continue;
case SState::IN_CHAT:
DoOnlineChat();
+
continue;
default:
break; // Handled below.
}
// Remaining are game modes: IN_SINGLE, IN_MULTI, IN_NETWORK
Audio->PlaySample( "car_start.voc" );
Audio->PlayMusic( "GameMusic" );
bNetworkGame = false;
while ( g_oState.m_enGameMode != SState::IN_DEMO
&& g_oState.m_enGameMode != SState::IN_CHAT
&& !g_oState.m_bQuitFlag )
{
bNetworkGame = SState::IN_NETWORK == g_oState.m_enGameMode;
g_oPlayerSelect.DoPlayerSelect();
if ( g_oState.m_bQuitFlag || g_oState.m_enGameMode == SState::IN_DEMO ) break;
//sprintf( acReplayFile, "/tmp/msz%d.replay", ++iGameNumber );
int iGameResult = DoGame( NULL, false, bDebug );
//int iGameResult = DoGame( acReplayFile, false, bDebug );
//DoGame( acReplayFile, true, bDebug );
if ( g_oState.m_bQuitFlag || g_oState.m_enGameMode == SState::IN_DEMO ) break;
debug ( "iGameResult = %d\n", iGameResult );
if ( iGameResult >= 0 && !bNetworkGame )
{
GameOver( iGameResult );
+
FighterStatsDemo oDemo( g_oPlayerSelect.GetPlayerInfo( iGameResult ).m_enFighter );
oDemo.Run();
}
if ( g_oState.m_bQuitFlag || g_oState.m_enGameMode == SState::IN_DEMO ) break;
}
if ( bNetworkGame && !g_oState.m_bQuitFlag )
{
DrawTextMSZ( "Connection closed.", inkFont, 320, 210, AlignHCenter | UseShadow, C_WHITE, gamescreen );
DrawTextMSZ( g_poNetwork->GetLastError(), impactFont, 320, 250, AlignHCenter | UseShadow, C_WHITE, gamescreen );
- GetKey();
+ SDL_Delay( 1000 );
+ GetKey( true );
}
if ( g_oState.m_bQuitFlag ) break;
Audio->PlayMusic( "DemoMusic" );
}
g_oState.Save();
SDL_Quit();
return EXIT_SUCCESS;
}
diff --git a/src/menu.cpp b/src/menu.cpp
index 6777bc8..81d77e9 100644
--- a/src/menu.cpp
+++ b/src/menu.cpp
@@ -1,1248 +1,1216 @@
/***************************************************************************
menu.cpp - description
-------------------
begin : Sun Aug 3 2003
copyright : (C) 2003 by upi
email : upi@apocalypse.rulez.org
***************************************************************************/
#include "SDL.h"
#include "SDL_video.h"
#include "menu.h"
#include "gfx.h"
#include "State.h"
#include "common.h"
#include "Audio.h"
#include "Backend.h"
#include "sge_tt_text.h"
#include "sge_surface.h"
#include "MortalNetwork.h"
+#include "Joystick.h"
#include <stdarg.h>
-enum
-{
-/* Master menu structure:
-MAIN MENU
-*/
-MENU_UNKNOWN,
- MENU_SURRENDER,
- MENU_SINGLE_PLAYER,
- MENU_EASY,
- MENU_MEDIUM,
- MENU_HARD,
- MENU_MULTI_PLAYER,
- MENU_NETWORK_GAME,
- MENU_SERVER,
- MENU_HOSTNAME,
- MENU_NICK,
- MENU_CONNECT,
- MENU_MORTALNET,
- MENU_CANCEL,
- MENU_OPTIONS,
- MENU_GAME_SPEED,
- MENU_GAME_TIME, // ( :30 - 5:00 )
- MENU_TOTAL_HIT_POINTS, // ( 25 - 1000 )
- MENU_SOUND,
- MENU_CHANNELS, // MONO / STEREO
-
- MENU_MIXING_RATE, // 11kHz / 22kHz / 44.1 kHz
- MENU_BITS, // 8 bit / 16 bit
- MENU_MUSIC_VOLUME, // (0% - 100%)
- MENU_SOUND_VOLUME, // (0% - 100%)
- MENU_SOUND_OK,
- MENU_FULLSCREEN,
- MENU_KEYS_RIGHT,
- MENU_KEYS_LEFT,
- MENU_OPTIONS_OK,
- MENU_LANGUAGE,
- MENU_INFO,
- MENU_QUIT, // (confirm)
-};
const char* g_ppcGameTime[] = { "0:30", "0:45", "1:00", "1:15", "1:30", "1:45", "2:00", "3:00", "5:00", NULL };
const int g_piGameTime[] = { 30, 45, 60, 75, 90, 105, 120, 180, 300 };
const char* g_ppcHitPoints[] = { "BABY", "VERY LOW", "LOW", "NORMAL", "HIGH", "VERY HIGH", "NEAR IMMORTAL", NULL };
const int g_piHitPoints[] = { 1, 10, 50, 100, 150, 200, 500 };
const char* g_ppcGameSpeed[] = { "SNAIL RACE", "SLOW", "NORMAL", "TURBO", "KUNG-FU MOVIE", NULL };
const int g_piGameSpeed[] = { 16, 14, 12, 10, 8 };
const char* g_ppcChannels[] = { "MONO", "STEREO", NULL };
const int g_piChannels[] = { 1, 2 };
const char* g_ppcMixingRate[] = { "LOW", "MEDIUM", "HIGH", NULL };
const int g_piMixingRate[] = { 1, 2, 3 };
const char* g_ppcMixingBits[] = { "8 bit", "16 bit", NULL };
const int g_piMixingBits[] = { 1, 2 };
const char* g_ppcVolume[] = { "OFF", "10%", "20%", "30%", "40%", "50%", "60%", "70%", "80%", "90%", "100%", NULL };
const int g_piVolume[] = { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };
const char* g_ppcLanguage[] = { "English", "Spanish", "Francais", "Magyar", "Portugues", NULL };
const int g_piLanguage[] = { 0, 1, 2, 3, 4 };
const char* g_ppcLanguageCodes[] = { "en", "es", "fr", "hu", "pt" };
const char* g_ppcServer[] = { "Connect to game", "Create game", NULL };
int g_piServer[] = { 0, 1 };
SDL_Surface* poBackground = NULL;
void InputKeys( int a_iPlayerNumber )
{
SDL_BlitSurface( poBackground, NULL, gamescreen, NULL );
DrawGradientText( "Input keys", titleFont, 10, gamescreen );
SDL_Flip( gamescreen );
static const char* apcKeyNames[9] = { "up", "down", "left", "right", "block",
"low punch", "high punch", "low kick", "high kick" };
char acBuffer[1024];
char acSide[128];
char acFormat[128];
int iY = 75;
int iYIncrement = 35;
SDLKey enKey;
+
+ const char* pcJoyName = g_oJoystick.GetJoystickName( a_iPlayerNumber );
+ if ( NULL != pcJoyName )
+ {
+ DrawTextMSZ( pcJoyName, inkFont, 320, iY, AlignHCenter|UseShadow, C_LIGHTCYAN, gamescreen );
+ iY += iYIncrement + 10;
+ }
- DrawTextMSZ( "Press Escape to abort", inkFont, 320, iY, AlignHCenter|UseShadow, C_LIGHTGRAY, gamescreen );
- iY += iYIncrement + 10;
+ DrawTextMSZ( "Press Escape to abort", inkFont, 320, 470-iYIncrement, AlignHCenter|UseShadow, C_LIGHTGRAY, gamescreen );
strcpy( acSide, Translate(a_iPlayerNumber ? "Left" : "Right") );
strcpy( acFormat, Translate("%s player-'%s'?") );
for ( int i=0; i<9; ++i )
{
// 1. PRINT THE FONT AND THE CURRENT KEYSYM
sprintf( acBuffer, acFormat, acSide, Translate(apcKeyNames[i]) );
int w = DrawTextMSZ( acBuffer, inkFont, 10, iY, UseShadow, C_WHITE, gamescreen );
enKey = (SDLKey) g_oState.m_aiPlayerKeys[a_iPlayerNumber][i];
g_oBackend.PerlEvalF( "GetKeysym(%d);", enKey );
DrawTextMSZ( g_oBackend.GetPerlString("keysym"), inkFont, w+30, iY, UseShadow, C_LIGHTCYAN, gamescreen );
// 2. INPUT THE NEW KEY
- enKey = GetKey();
+ enKey = GetKey( false );
if ( SDLK_ESCAPE == enKey )
{
SDL_BlitSurface( poBackground, NULL, gamescreen, NULL );
SDL_Flip( gamescreen );
return;
}
// 3. PRINT THE NEW KEY
g_oState.m_aiPlayerKeys[a_iPlayerNumber][i] = enKey;
g_oBackend.PerlEvalF( "GetKeysym(%d);", enKey );
sge_Blit( poBackground, gamescreen, w+10, iY, w+10, iY, 640, 50 );
DrawTextMSZ( g_oBackend.GetPerlString("keysym"), inkFont, w+30, iY, UseShadow, C_WHITE, gamescreen );
sge_UpdateRect( gamescreen, w+10, iY, 640, 50 );
iY += iYIncrement;
}
+ sge_Blit( poBackground, gamescreen, 0, 470-iYIncrement, 0, 470-iYIncrement, 640, 480 );
+ sge_UpdateRect( gamescreen, 0, 470-iYIncrement, 640, 480 );
DrawTextMSZ( "Thanks!", inkFont, 320, iY + 20, UseShadow | AlignCenter, C_WHITE, gamescreen );
- GetKey();
+ GetKey( true );
SDL_BlitSurface( poBackground, NULL, gamescreen, NULL );
SDL_Flip( gamescreen );
}
/***************************************************************************
NETWORK MENU DEFINITION
***************************************************************************/
int g_iMessageY;
static char g_acMessageBuffer[1024];
void MortalNetworkResetMessages( bool a_bClear )
{
if ( a_bClear )
{
SDL_FillRect( gamescreen, NULL, C_BLACK );
SDL_Flip( gamescreen );
g_iMessageY = 185;
}
else
{
g_iMessageY = 185;
}
}
void MortalNetworkMessage( const char* format, ... )
{
char acBuffer[1024];
va_list ap;
va_start( ap, format );
vsnprintf( acBuffer, 1023, format, ap );
va_end( ap );
DrawTextMSZ( acBuffer, impactFont, 20, g_iMessageY, 0, C_LIGHTGRAY, gamescreen );
g_iMessageY += 25;
}
bool MortalNetworkCheckKey()
{
SDL_Event event;
while (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_QUIT:
g_oState.m_bQuitFlag = true;
return true;
case SDL_KEYDOWN:
- {
+ case SDL_JOYBUTTONDOWN:
return true;
- }
- break;
+
} // switch statement
} // Polling events
return false;
}
bool Connect( const char* a_pcHostname )
{
MortalNetworkResetMessages( false );
bool bOK = g_poNetwork->Start( a_pcHostname );
if ( bOK )
{
// Store these settings as they are pretty good.
g_oState.SetServer( a_pcHostname );
g_oState.m_enGameMode = SState::IN_NETWORK;
}
else
{
// Print error message
const char* acError = g_poNetwork->GetLastError();
DrawTextMSZ( "Couldn't connect", inkFont, 320, g_iMessageY, AlignHCenter|UseShadow, C_LIGHTRED, gamescreen );
DrawTextMSZ( acError, impactFont, 320, g_iMessageY + 40, AlignHCenter|UseShadow, C_LIGHTRED, gamescreen, false );
}
// Wait for a key, unless Quit was issued.
if ( !g_oState.m_bQuitFlag )
{
if ( bOK )
{
// Wait for 1 sec, or keystroke.
for ( int i=0; i<10; ++i )
{
if ( MortalNetworkCheckKey() ) break;
SDL_Delay( 100 );
}
}
else
{
- GetKey();
+ GetKey( true );
}
}
if ( g_oState.m_bQuitFlag )
{
bOK = false;
}
return bOK;
}
const char* FindString( const char* a_ppcNames[], const int a_piValues[], int a_iValue )
{
for ( int i=0; NULL != a_ppcNames[i]; ++i )
{
if ( a_iValue == a_piValues[i] )
{
return a_ppcNames[i];
}
}
return "(unknown)";
}
const char* GetGameTimeString( int a_iValue )
{
strcpy( g_acMessageBuffer, Translate("GAME TIME: ") );
strcat( g_acMessageBuffer, Translate(FindString( g_ppcGameTime, g_piGameTime, a_iValue)) );
return g_acMessageBuffer;
}
const char* GetGameSpeedString( int a_iValue )
{
strcpy( g_acMessageBuffer, Translate("GAME SPEED: ") );
strcat( g_acMessageBuffer, Translate(FindString( g_ppcGameSpeed, g_piGameSpeed, a_iValue)) );
return g_acMessageBuffer;
}
const char* GetHitPointsString( int a_iValue )
{
strcpy( g_acMessageBuffer, Translate("STAMINA: ") );
strcat( g_acMessageBuffer, Translate(FindString( g_ppcHitPoints, g_piHitPoints, a_iValue) ) );
return g_acMessageBuffer;
}
CNetworkMenu::CNetworkMenu(): Menu( "Network Play Setup" )
{
m_bOK = false;
m_bServer = g_oState.m_bServer;
m_sHostname = g_oState.m_acLatestServer;
m_sNick = g_oState.m_acNick;
AddMenuItem( "Find an opponent on MortalNet", SDLK_UNKNOWN, MENU_MORTALNET );
AddMenuItem( "START NETWORK GAME!", SDLK_UNKNOWN, MENU_CONNECT );
m_poNickMenuItem = AddTextMenuItem( "Nickname: ", m_sNick.c_str(), MENU_NICK );
AddEnumMenuItem( "Network mode: ", m_bServer ? 1 : 0, g_ppcServer, g_piServer, MENU_SERVER );
m_poServerMenuItem = AddTextMenuItem( "Connect to: ", m_sHostname.c_str(), MENU_HOSTNAME );
m_poServerMenuItem->SetEnabled(!m_bServer);
MenuItem* poItem = AddMenuItem( "Cancel", SDLK_UNKNOWN, MENU_CANCEL );
SDL_Rect oRect;
oRect.x = gamescreen->w - 150; oRect.w = 150;
oRect.y = gamescreen->h - 50; oRect.h = 30;
poItem->SetPosition( oRect );
}
CNetworkMenu::~CNetworkMenu() {}
void CNetworkMenu::Connect()
{
Clear();
SDL_Flip( gamescreen );
m_bOK = ::Connect( m_bServer ? NULL : m_sHostname.c_str() );
if ( g_oState.m_bQuitFlag || m_bOK )
{
m_bDone = true;
m_iReturnCode = 100;
}
Clear();
Draw();
}
void Menu::EnterName( const char* a_pcTitle, std::string& a_rsTarget, TextMenuItem* a_poMenuItem, int a_iMaxlen )
{
Clear();
Draw();
if ( a_iMaxlen > 255 ) a_iMaxlen = 255;
char acBuffer[256];
strncpy( acBuffer, a_rsTarget.c_str(), 255 );
acBuffer[255] = 0;
int y = m_oItems.size() * 40 + 100;
int x = DrawTextMSZ( a_pcTitle, impactFont, 20, y, 0, C_WHITE, gamescreen );
int iRetval;
{
CReadline oReadline( gamescreen, impactFont, acBuffer, strlen(acBuffer), a_iMaxlen,
20+x, y + sge_TTF_FontAscent(impactFont), 600, C_LIGHTCYAN, C_BLACK, 255 );
iRetval = oReadline.Execute();
}
if ( iRetval == -1 )
{
m_bDone = true;
m_iReturnCode = 100;
g_oState.m_bQuitFlag = true;
}
if ( iRetval > 0 )
{
a_rsTarget = acBuffer;
a_poMenuItem->SetValue( acBuffer );
}
Clear();
Draw();
}
void CNetworkMenu::ItemActivated( int a_iItemCode, MenuItem* a_poMenuItem )
{
switch ( a_iItemCode )
{
case MENU_SERVER:
{
EnumMenuItem* poItem = (EnumMenuItem*) a_poMenuItem;
if ( m_bServer )
{
poItem->Decrement();
}
else
{
poItem->Increment();
}
break;
}
case MENU_CONNECT:
strcpy( g_oState.m_acNick, m_sNick.c_str() );
Connect();
break;
case MENU_CANCEL:
m_bOK = false;
m_bDone = true;
m_iReturnCode = -1;
break;
case MENU_HOSTNAME:
EnterName( "Server name: ", m_sHostname, m_poServerMenuItem,128 );
break;
case MENU_NICK:
EnterName( "Nickname: ", m_sNick, m_poNickMenuItem, 12 );
strcpy( g_oState.m_acNick, m_sNick.c_str() );
break;
case MENU_MORTALNET:
g_oState.m_enGameMode = SState::IN_CHAT;
m_bOK = false;
m_bDone = true;
m_iReturnCode = 100;
break;
}
}
void CNetworkMenu::ItemChanged( int a_iItemCode, int a_iValue, MenuItem* a_poMenuItem )
{
switch ( a_iItemCode )
{
case MENU_SERVER:
m_bServer = a_iValue;
m_poServerMenuItem->SetEnabled(!m_bServer);
break;
}
}
/***************************************************************************
MENUITEM DEFINITION
***************************************************************************/
MenuItem::MenuItem( Menu* a_poMenu, const char* a_pcUtf8Text, int a_iCode )
: m_sUtf8Text( a_pcUtf8Text )
{
m_poMenu = a_poMenu;
m_iCode = a_iCode;
m_oPosition.x = m_oPosition.y = 100;
m_oPosition.w = m_oPosition.h = 100;
m_bCenter = true;
m_iHighColor = C_WHITE;
m_iLowColor = C_LIGHTGRAY;
m_iInactiveColor = C_DARKGRAY;
m_iBackgroundColor = C_BLACK;
m_bActive = false;
m_bEnabled = true;
}
MenuItem::~MenuItem()
{
}
void MenuItem::Draw()
{
if ( NULL != poBackground )
{
SDL_BlitSurface( poBackground, &m_oPosition, gamescreen, &m_oPosition );
}
else
{
SDL_FillRect( gamescreen, &m_oPosition, 0 );
}
int iX = m_oPosition.x;
int iY = m_oPosition.y;
if ( m_bCenter )
{
iX += m_oPosition.w / 2;
}
DrawTextMSZ( m_sUtf8Text.c_str(), inkFont, iX, iY,
UseTilde | UseShadow | (m_bCenter ? AlignHCenter : 0),
m_bEnabled ? (m_bActive ? m_iHighColor : m_iLowColor) : m_iInactiveColor,
gamescreen );
SDL_UpdateRect( gamescreen, m_oPosition.x, m_oPosition.y, m_oPosition.w, m_oPosition.h );
}
void MenuItem::Clear()
{
// debug( "Clear: %d:%d %dx%d\n", m_oPosition.x, m_oPosition.y, m_oPosition.w, m_oPosition.h );
if (poBackground )
{
SDL_Rect oDest = m_oPosition;
SDL_BlitSurface( poBackground, &m_oPosition, gamescreen, &oDest );
}
else
{
SDL_FillRect( gamescreen, &m_oPosition, C_WHITE );
}
SDL_UpdateRect( gamescreen, m_oPosition.x, m_oPosition.y, m_oPosition.w, m_oPosition.h );
}
void MenuItem::Activate()
{
if ( m_poMenu )
{
m_poMenu->ItemActivated( m_iCode, this );
}
}
void MenuItem::SetText( const char* a_pcUtf8Text, bool a_bCenter )
{
m_sUtf8Text = a_pcUtf8Text;
m_bCenter = a_bCenter;
Draw();
}
void MenuItem::SetPosition( const SDL_Rect& a_roPosition )
{
m_oPosition = a_roPosition;
}
void MenuItem::SetActive( bool a_bActive )
{
if ( m_bActive == a_bActive )
{
return;
}
m_bActive = a_bActive;
Draw();
}
void MenuItem::SetEnabled( bool a_bEnabled )
{
if ( m_bEnabled == a_bEnabled )
{
return;
}
m_bEnabled = a_bEnabled;
Draw();
}
/***************************************************************************
ENUMMENUITEM DEFINITION
***************************************************************************/
EnumMenuItem::EnumMenuItem( Menu* a_poMenu, int a_iInitialValue, const char* a_pcUtf8Text, int a_iCode )
: MenuItem( a_poMenu, a_pcUtf8Text, a_iCode )
{
m_sUtf8Title = a_pcUtf8Text;
m_iMax = -1;
m_iValue = a_iInitialValue;
}
EnumMenuItem::~EnumMenuItem()
{
}
int EnumMenuItem::GetCurrentValue()
{
return m_iValue <= m_iMax ? m_piValues[m_iValue] : 0;
}
const char* EnumMenuItem::GetCurrentText()
{
return m_iValue <= m_iMax ? m_ppcNames[m_iValue] : "";
}
void EnumMenuItem::Draw()
{
m_sUtf8Text = Translate( m_sUtf8Title.c_str() );
if ( m_iValue <= m_iMax )
{
m_sUtf8Text += Translate(m_ppcNames[m_iValue]);
}
if ( m_iValue > 0 )
{
m_sUtf8Text = "< " + m_sUtf8Text;
}
if ( m_iValue < m_iMax )
{
m_sUtf8Text += " >";
}
MenuItem::Draw();
}
void EnumMenuItem::Increment()
{
if ( m_iValue < m_iMax )
{
++m_iValue;
Draw();
m_poMenu->ItemChanged( m_iCode, m_piValues[m_iValue], this );
Audio->PlaySample( "ding.voc" );
}
}
void EnumMenuItem::Decrement()
{
if ( m_iValue > 0 )
{
--m_iValue;
Draw();
m_poMenu->ItemChanged( m_iCode, m_piValues[m_iValue], this );
Audio->PlaySample( "ding.voc" );
}
}
void EnumMenuItem::SetEnumValues( const char ** a_ppcNames, const int * a_piValues )
{
m_ppcNames = a_ppcNames;
m_piValues = a_piValues;
int i;
bool bFoundValue = false;
for ( i=0; NULL != a_ppcNames[i]; ++i )
{
if ( !bFoundValue &&
m_iValue == a_piValues[i] )
{
bFoundValue = true;
m_iValue = i;
}
}
if ( !bFoundValue )
{
m_iValue = 0;
}
m_iMax = i-1;
}
/***************************************************************************
TextMenuItem DEFINITION
***************************************************************************/
TextMenuItem::TextMenuItem( Menu* a_poMenu, const char* a_pcInitialValue, const char* a_pcUtf8Title, int a_iCode )
: MenuItem( a_poMenu, a_pcUtf8Title, a_iCode )
{
m_sTitle = a_pcUtf8Title;
m_sValue = a_pcInitialValue;
}
TextMenuItem::~TextMenuItem()
{
}
void TextMenuItem::Draw()
{
m_sUtf8Text = Translate( m_sTitle.c_str() );
m_sUtf8Text += m_sValue;
MenuItem::Draw();
}
void TextMenuItem::SetValue( const char* a_pcValue )
{
m_sValue = a_pcValue;
Draw();
}
/***************************************************************************
MENU DEFINITION
***************************************************************************/
Menu::Menu( const char* a_pcTitle )
: m_sTitle( a_pcTitle )
{
m_iCurrentItem = 0;
m_iReturnCode = -1;
m_bDone = false;
}
Menu::~Menu()
{
ItemIterator it;
for ( it = m_oItems.begin(); it != m_oItems.end(); ++it )
{
delete *it;
}
}
MenuItem* Menu::AddMenuItem( const char* a_pcUtf8Text, SDLKey a_tShortcut, int a_iCode )
{
MenuItem* poItem = new MenuItem( this, a_pcUtf8Text, a_iCode );
return AddMenuItem( poItem );
}
EnumMenuItem* Menu::AddEnumMenuItem( const char* a_pcUtf8Text, int a_iInitialValue,
const char** a_ppcNames, const int* a_piValues, int a_iCode )
{
EnumMenuItem* poItem = new EnumMenuItem( this, a_iInitialValue, a_pcUtf8Text, a_iCode );
poItem->SetEnumValues( a_ppcNames, a_piValues );
AddMenuItem( poItem );
return poItem;
}
TextMenuItem* Menu::AddTextMenuItem( const char* a_pcTitle, const char* a_pcValue, int a_iCode )
{
TextMenuItem* poItem = new TextMenuItem( this, a_pcValue, a_pcTitle, a_iCode );
AddMenuItem( poItem );
return poItem;
}
MenuItem* Menu::AddMenuItem( MenuItem* a_poItem )
{
m_oItems.push_back( a_poItem );
SDL_Rect oRect;
oRect.x = 0; oRect.w = gamescreen->w;
oRect.y = m_oItems.size() * 40 + 100;
oRect.h = sge_TTF_FontHeight( inkFont );
a_poItem->SetPosition( oRect );
return a_poItem;
}
void Menu::AddOkCancel( int a_iOkCode )
{
SDL_Rect oRect;
oRect.x = 0; oRect.w = 150;
oRect.y = gamescreen->h - 50; oRect.h = sge_TTF_FontHeight( inkFont );
MenuItem* poItem = AddMenuItem( "~OK", SDLK_o, a_iOkCode );
poItem->SetPosition( oRect );
// poItem = AddMenuItem( "Cancel", SDLK_UNKNOWN, 0 );
oRect.x = gamescreen->w - 150;
poItem->SetPosition( oRect );
}
void Menu::InvokeSubmenu( Menu* a_poMenu )
{
Audio->PlaySample( "strange_button.voc" );
Clear();
m_iReturnCode = a_poMenu->Run();
if ( g_oState.m_bQuitFlag )
{
m_iReturnCode = 100;
m_bDone = true;
}
if ( m_iReturnCode < 0 )
{
Audio->PlaySample( "pop.voc" );
Draw();
}
else
{
m_iReturnCode --;
m_bDone = true;
}
}
void Menu::ItemActivated( int a_iItemCode, MenuItem* a_poMenuItem )
{
debug( "Menu::ItemActivated( %d )\n", a_iItemCode );
switch ( a_iItemCode )
{
case MENU_QUIT:
m_bDone = true;
m_iReturnCode = 100;
g_oState.m_bQuitFlag = true;
break;
case MENU_SURRENDER:
m_bDone = true;
m_iReturnCode = 100;
if ( SState::IN_NETWORK == g_oState.m_enGameMode )
{
g_poNetwork->Stop();
}
g_oState.m_enGameMode = SState::IN_DEMO;
break;
case MENU_NETWORK_GAME:
{
Menu* poMenu = new CNetworkMenu();
InvokeSubmenu( poMenu );
delete poMenu;
break;
}
case MENU_MULTI_PLAYER:
m_bDone = true;
m_iReturnCode = 100;
g_oState.m_enGameMode = SState::IN_MULTI;
break;
case MENU_FULLSCREEN:
Audio->PlaySample( "strange_button.voc" );
g_oState.ToggleFullscreen();
if ( NULL != poBackground )
{
SDL_BlitSurface( poBackground, NULL, gamescreen, NULL );
}
else
{
SDL_FillRect( gamescreen, NULL, 0 );
}
a_poMenuItem->SetText( g_oState.m_bFullscreen ? "~FULLSCREEN ON" : "~FULLSCREEN OFF", true );
Draw();
break;
case MENU_OPTIONS_OK:
m_bDone = true;
m_iReturnCode = -1;
break;
case MENU_OPTIONS:
{
Menu* poMenu = new Menu( "Options" );
if ( g_oState.m_enGameMode != SState::IN_NETWORK || g_poNetwork->IsMaster() )
{
poMenu->AddEnumMenuItem( "GAME SPEED: ", g_oState.m_iGameSpeed, g_ppcGameSpeed, g_piGameSpeed, MENU_GAME_SPEED );
poMenu->AddEnumMenuItem( "GAME TIME: ", g_oState.m_iGameTime, g_ppcGameTime, g_piGameTime, MENU_GAME_TIME );
poMenu->AddEnumMenuItem( "STAMINA: ", g_oState.m_iHitPoints, g_ppcHitPoints, g_piHitPoints, MENU_TOTAL_HIT_POINTS );
}
poMenu->AddMenuItem( "~SOUND", SDLK_s, MENU_SOUND );
poMenu->AddMenuItem( g_oState.m_bFullscreen ? "~FULLSCREEN ON" : "~FULLSCREEN OFF", SDLK_f, MENU_FULLSCREEN );
poMenu->AddMenuItem( "~RIGHT PLAYER KEYS", SDLK_r, MENU_KEYS_RIGHT );
poMenu->AddMenuItem( "~LEFT PLAYER KEYS", SDLK_l, MENU_KEYS_LEFT );
poMenu->AddOkCancel( MENU_OPTIONS_OK );
InvokeSubmenu( poMenu );
delete poMenu;
break;
}
case MENU_SOUND:
{
Menu* poMenu = new Menu( "Sound" );
poMenu->AddEnumMenuItem( "CHANNELS: ", 1, g_ppcChannels, g_piChannels, MENU_CHANNELS )->SetEnabled(false);
poMenu->AddEnumMenuItem( "SOUND QUALITY: ", 2, g_ppcMixingRate, g_piMixingRate, MENU_MIXING_RATE )->SetEnabled(false);
poMenu->AddEnumMenuItem( "SOUND FIDELITY: ", 2, g_ppcMixingBits, g_piMixingBits, MENU_BITS )->SetEnabled(false);
poMenu->AddEnumMenuItem( "MUSIC VOLUME: ", g_oState.m_iMusicVolume, g_ppcVolume, g_piVolume, MENU_MUSIC_VOLUME );
poMenu->AddEnumMenuItem( "EFFECTS VOLUME: ", g_oState.m_iSoundVolume, g_ppcVolume, g_piVolume, MENU_SOUND_VOLUME );
poMenu->AddOkCancel( MENU_SOUND_OK );
InvokeSubmenu( poMenu );
delete poMenu;
break;
}
case MENU_SOUND_OK:
m_bDone = true;
m_iReturnCode = -1;
break;
case MENU_KEYS_LEFT:
InputKeys(1);
Draw();
break;
case MENU_KEYS_RIGHT:
InputKeys(0);
Draw();
break;
default:
break;
}
}
void Menu::ItemChanged( int a_iItemCode, int a_iValue, MenuItem* a_poMenuItem )
{
debug( "Menu::ItemChanged( %d, %d )\n", a_iItemCode, a_iValue );
switch ( a_iItemCode )
{
case MENU_MUSIC_VOLUME:
g_oState.m_iMusicVolume = a_iValue;
Audio->SetMusicVolume( a_iValue );
break;
case MENU_SOUND_VOLUME:
g_oState.m_iSoundVolume = a_iValue;
break;
case MENU_GAME_TIME:
g_oState.m_iGameTime = a_iValue;
break;
case MENU_GAME_SPEED:
g_oState.m_iGameSpeed = a_iValue;
break;
case MENU_TOTAL_HIT_POINTS:
g_oState.m_iHitPoints = a_iValue;
break;
case MENU_LANGUAGE:
g_oState.SetLanguage( g_ppcLanguageCodes[ a_iValue ] );
Clear();
Draw();
break;
} // end of switch a_iItemCode
}
/** Run executes the menus, maybe invoking submenus as well. The
menus modify the global game state.
Returns 0, or the number of parent menus that should be cleared. */
int Menu::Run()
{
if ( m_oItems[m_iCurrentItem]->GetEnabled() )
{
m_oItems[m_iCurrentItem]->SetActive(true);
}
else
{
FocusNext();
}
Draw();
while ( !m_bDone )
{
if ( g_oState.m_bQuitFlag )
{
m_bDone = true;
m_iReturnCode = -1;
break;
}
- SDLKey enKey = GetKey();
+ SDLKey enKey = GetKey( true );
if ( g_oState.m_bQuitFlag ||
SDLK_ESCAPE == enKey )
-
{
m_bDone = true;
m_iReturnCode = -1;
break;
}
switch ( enKey )
{
case SDLK_UP:
{
FocusPrev();
break;
} // end of SDLK_UP
case SDLK_DOWN:
{
FocusNext();
break;
} // end of SDLK_DOWN
case SDLK_LEFT:
{
MenuItem* poItem = m_oItems[m_iCurrentItem];
poItem->Decrement();
break;
}
case SDLK_RIGHT:
{
MenuItem* poItem = m_oItems[m_iCurrentItem];
poItem->Increment();
break;
}
case SDLK_RETURN:
{
MenuItem* poItem = m_oItems[m_iCurrentItem];
if ( poItem->GetEnabled() )
{
poItem->Activate();
}
}
default:
break;
} // end of switch
}
Clear();
return m_iReturnCode;
}
void Menu::Draw()
{
DrawGradientText( m_sTitle.c_str(), titleFont, 20, gamescreen );
for ( ItemIterator it=m_oItems.begin(); it!=m_oItems.end(); ++it )
{
(*it)->Draw();
}
SDL_Flip( gamescreen );
}
void Menu::FocusNext()
{
MenuItem* poItem = NULL;
int iNextItem;
for ( iNextItem = m_iCurrentItem+1; iNextItem < (int) m_oItems.size(); ++iNextItem )
{
poItem = m_oItems[iNextItem];
if ( poItem->GetEnabled() )
{
break;
}
poItem = NULL;
}
if ( NULL != poItem )
{
Audio->PlaySample("strange_quack.voc");
m_oItems[m_iCurrentItem]->SetActive(false);
m_oItems[iNextItem]->SetActive(true);
m_iCurrentItem = iNextItem;
}
}
void Menu::FocusPrev()
{
MenuItem* poItem = NULL;
int iPrevItem;
for ( iPrevItem = m_iCurrentItem-1; iPrevItem >= 0; --iPrevItem )
{
poItem = m_oItems[iPrevItem];
if ( poItem->GetEnabled() )
{
break;
}
poItem = NULL;
}
if ( NULL != poItem )
{
Audio->PlaySample("strange_quack.voc");
m_oItems[m_iCurrentItem]->SetActive(false);
m_oItems[iPrevItem]->SetActive(true);
m_iCurrentItem = iPrevItem;
}
}
void Menu::Clear()
{
if (poBackground)
{
SDL_BlitSurface( poBackground, 0, gamescreen, 0 );
}
else
{
SDL_FillRect( gamescreen, NULL, 0 );
}
}
void MakeMenuBackground()
{
if ( poBackground != NULL )
{
return;
}
poBackground = SDL_ConvertSurface( gamescreen, gamescreen->format, SDL_SWSURFACE );
if ( NULL == poBackground )
{
debug( "DoMenu: Couldn't allocate background.\n" );
}
else
{
int i;
SDL_Rect oRect;
oRect.x = 0; oRect.w = poBackground->w; oRect.h = 1;
for ( i=0; i<poBackground->h; i += 2 )
{
oRect.y = i;
SDL_FillRect( poBackground, &oRect, C_BLACK );
}
oRect.w = 1; oRect.y = 0; oRect.h = poBackground->h;
for ( i=0; i<poBackground->w; i+=2 )
{
oRect.x = i;
SDL_FillRect(poBackground, &oRect, C_BLACK );
}
SDL_BlitSurface( poBackground, 0, gamescreen, 0 );
SDL_Flip( gamescreen );
}
}
void DoMenu( Menu& a_roMenu )
{
Audio->PlaySample( "crashhh.voc" );
MakeMenuBackground();
a_roMenu.Clear();
a_roMenu.Draw();
a_roMenu.Run();
if ( !g_oState.m_bQuitFlag )
{
Audio->PlaySample("shades_rollup.voc");
}
if ( NULL != poBackground )
{
SDL_FreeSurface( poBackground );
poBackground = NULL;
}
}
void DoMenu()
{
MakeMenuBackground();
Menu oMenu( "Main Menu" );
if ( SState::IN_DEMO == g_oState.m_enGameMode )
{
oMenu.AddMenuItem( "~SINGLE PLAYER GAME", SDLK_s, MENU_SINGLE_PLAYER )->SetEnabled(false);
oMenu.AddMenuItem( "~NETWORK GAME", SDLK_n, MENU_NETWORK_GAME );
oMenu.AddMenuItem( "~MULTI PLAYER GAME", SDLK_m, MENU_MULTI_PLAYER );
}
else
{
oMenu.AddMenuItem( "~SURRENDER GAME", SDLK_s, MENU_SURRENDER );
}
oMenu.AddEnumMenuItem( "~LANGUAGE: ", g_oState.m_iLanguageCode, g_ppcLanguage, g_piLanguage, MENU_LANGUAGE );
oMenu.AddMenuItem( "~OPTIONS", SDLK_o, MENU_OPTIONS );
oMenu.AddMenuItem( "~INFO", SDLK_i, MENU_INFO )->SetEnabled(false);
oMenu.AddMenuItem( "QUIT", SDLK_UNKNOWN, MENU_QUIT );
DoMenu( oMenu );
}
diff --git a/src/menu.h b/src/menu.h
index 5166d4a..4d3b7db 100644
--- a/src/menu.h
+++ b/src/menu.h
@@ -1,167 +1,210 @@
/***************************************************************************
menu.h - description
-------------------
begin : Sun Aug 3 2003
copyright : (C) 2003 by upi
email : upi@apocalypse.rulez.org
***************************************************************************/
#ifndef MENU_H
#define MENU_H
#include <string>
#include <vector>
class MenuItem;
class EnumMenuItem;
class TextMenuItem;
+
+enum
+{
+/* Master menu structure:
+MAIN MENU
+*/
+MENU_UNKNOWN,
+ MENU_SURRENDER,
+ MENU_SINGLE_PLAYER,
+ MENU_EASY,
+ MENU_MEDIUM,
+ MENU_HARD,
+ MENU_MULTI_PLAYER,
+ MENU_NETWORK_GAME,
+ MENU_SERVER,
+ MENU_HOSTNAME,
+ MENU_NICK,
+ MENU_CONNECT,
+ MENU_MORTALNET,
+ MENU_CANCEL,
+ MENU_OPTIONS,
+ MENU_GAME_SPEED,
+ MENU_GAME_TIME, // ( :30 - 5:00 )
+ MENU_TOTAL_HIT_POINTS, // ( 25 - 1000 )
+ MENU_SOUND,
+ MENU_CHANNELS, // MONO / STEREO
+
+ MENU_MIXING_RATE, // 11kHz / 22kHz / 44.1 kHz
+ MENU_BITS, // 8 bit / 16 bit
+ MENU_MUSIC_VOLUME, // (0% - 100%)
+ MENU_SOUND_VOLUME, // (0% - 100%)
+ MENU_SOUND_OK,
+ MENU_FULLSCREEN,
+ MENU_KEYS_RIGHT,
+ MENU_KEYS_LEFT,
+ MENU_OPTIONS_OK,
+ MENU_LANGUAGE,
+ MENU_INFO,
+ MENU_QUIT, // (confirm)
+};
+
+
class Menu
{
+
public:
Menu( const char* a_pcTitle );
virtual ~Menu();
virtual MenuItem* AddMenuItem( const char* a_pcUtf8Text, SDLKey a_tShortcut = SDLK_UNKNOWN, int a_iCode = 0 );
virtual EnumMenuItem* AddEnumMenuItem( const char* a_pcUtf8Text, int a_iInitialValue,
const char** a_ppcNames, const int* a_piValues, int a_iCode = 0 );
virtual TextMenuItem* AddTextMenuItem( const char* a_pcTitle, const char* a_pcValue, int a_iCode = 0 );
virtual MenuItem* AddMenuItem( MenuItem* a_poItem );
virtual void AddOkCancel( int a_iOkCode = 0 );
virtual void ItemActivated( int a_iItemCode, MenuItem* a_poMenuItem );
virtual void ItemChanged( int a_iItemCode, int a_iValue, MenuItem* a_poMenuItem );
virtual int Run();
virtual void Draw();
virtual void Clear();
virtual void EnterName( const char* a_pcTitle, std::string& a_rsTarget, TextMenuItem* a_poMenuItem, int a_iMaxlen );
protected:
virtual void FocusNext();
virtual void FocusPrev();
virtual void InvokeSubmenu( Menu* a_poSubmenu );
typedef std::vector<MenuItem*> ItemList;
typedef ItemList::iterator ItemIterator;
std::string m_sTitle;
ItemList m_oItems;
int m_iCurrentItem;
int m_iReturnCode;
bool m_bDone;
};
class MenuItem
{
public:
MenuItem( Menu* a_poMenu, const char* a_pcUtf8Text, int a_iCode = -1 );
virtual ~MenuItem();
virtual void Draw();
virtual void Clear();
virtual void Activate();
virtual void Increment() {};
virtual void Decrement() {};
virtual void SetText( const char* a_pcUtf8Text, bool a_bCenter );
virtual void SetPosition( const SDL_Rect& a_roPosition );
virtual void SetActive( bool a_bActive );
virtual void SetEnabled( bool a_bEnabled );
virtual bool GetEnabled() { return m_bEnabled; }
protected:
Menu* m_poMenu;
// appearance
std::string m_sUtf8Text;
SDL_Rect m_oPosition;
bool m_bCenter;
Uint32 m_iHighColor;
Uint32 m_iLowColor;
Uint32 m_iInactiveColor;
Uint32 m_iBackgroundColor;
// data content
int m_iCode;
bool m_bActive;
bool m_bEnabled;
};
class EnumMenuItem: public MenuItem
{
public:
EnumMenuItem( Menu* a_poMenu, int a_iInitialValue, const char* a_pcUtf8Text, int a_iCode = -1 );
virtual ~EnumMenuItem();
int GetCurrentValue();
const char* GetCurrentText();
virtual void Draw();
virtual void Increment();
virtual void Decrement();
virtual void SetEnumValues( const char ** a_ppcNames, const int * a_piValues );
protected:
int m_iValue;
int m_iMax;
std::string m_sUtf8Title;
const char** m_ppcNames;
const int* m_piValues;
};
class TextMenuItem: public MenuItem
{
public:
TextMenuItem( Menu* a_poMenu, const char* a_pcInitialValue, const char* a_pcUtf8Title, int a_iCode );
virtual ~TextMenuItem();
virtual void Draw();
virtual void SetValue( const char* a_pcValue );
protected:
std::string m_sTitle;
std::string m_sValue;
};
class CNetworkMenu: public Menu
{
public:
CNetworkMenu();
~CNetworkMenu();
void Connect();
void ItemActivated( int a_iItemCode, MenuItem* a_poMenuItem );
void ItemChanged( int a_iItemCode, int a_iValue, MenuItem* a_poMenuItem );
protected:
bool m_bOK;
bool m_bServer;
std::string m_sHostname;
std::string m_sNick;
TextMenuItem* m_poServerMenuItem;
TextMenuItem* m_poNickMenuItem;
};
void DoMenu();
void DoMenu( Menu& a_roMenu );
#endif

File Metadata

Mime Type
text/x-diff
Expires
Wed, Jun 17, 10:20 PM (1 w, 4 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
70625
Default Alt Text
(143 KB)

Event Timeline