Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
44 KB
Referenced Files
None
Subscribers
None
diff --git a/src/Backend.cpp b/src/Backend.cpp
index f38c115..8c00633 100644
--- a/src/Backend.cpp
+++ b/src/Backend.cpp
@@ -1,514 +1,519 @@
/***************************************************************************
Backend.cpp - description
-------------------
begin : Mon Dec 9 2002
copyright : (C) 2002 by upi
email : upi@apocalypse.rulez.org
***************************************************************************/
#include "common.h"
#include "Backend.h"
#include "Audio.h"
#include "State.h"
#include <string>
#include <stdarg.h>
#include "MszPerl.h"
/***************************************************************************
PUBLIC EXPORTED VARIABLES
***************************************************************************/
PerlInterpreter* my_perl;
CBackend g_oBackend;
/***************************************************************************
PRIVATE VARIABLES (perl variable space)
***************************************************************************/
SV
*perl_bgx, *perl_bgy,
*perl_px[MAXPLAYERS], *perl_py[MAXPLAYERS], *perl_pf[MAXPLAYERS],
*perl_ph[MAXPLAYERS], *perl_phreal[MAXPLAYERS],
*perl_gametick, *perl_over, *perl_ko;
SV
*perl_doodad_x, *perl_doodad_y,
*perl_doodad_t, *perl_doodad_f,
*perl_doodad_dir, *perl_doodad_gfxowner,
*perl_doodad_text;
SV
*perl_sound, *perl_Translated;
/***************************************************************************
TRANSLATION SERVICES
***************************************************************************/
const char* Translate( const char* a_pcText )
{
dSP ;
ENTER ;
SAVETMPS ;
PUSHMARK(SP) ;
XPUSHs(sv_2mortal(newSVpv(a_pcText, 0)));
PUTBACK ;
call_pv("Translate", G_DISCARD);
FREETMPS ;
LEAVE ;
if ( NULL == perl_Translated )
{
perl_Translated = get_sv("Translated", TRUE);
}
return SvPV_nolen( perl_Translated );
}
const char* TranslateUTF8( const char* a_pcText )
{
dSP ;
ENTER ;
SAVETMPS ;
PUSHMARK(SP) ;
XPUSHs(sv_2mortal(newSVpv(a_pcText, 0)));
PUTBACK ;
call_pv("Translate", G_DISCARD);
FREETMPS ;
LEAVE ;
if ( NULL == perl_Translated )
{
perl_Translated = get_sv("Translated", TRUE);
}
return SvPVutf8_nolen( perl_Translated );
}
/***************************************************************************
BACKEND CLASS IMPLEMENTATION
***************************************************************************/
#define PERLEVAL(A) eval_pv(A, TRUE);
#define PERLCALL(PROC,A,B) { \
dSP; \
ENTER; \
SAVETMPS; \
PUSHMARK(SP); \
XPUSHs(sv_2mortal(newSViv(A))); \
XPUSHs(sv_2mortal(newSViv(B))); \
PUTBACK ; \
\
call_pv( (PROC), G_DISCARD ); \
\
FREETMPS; \
LEAVE; \
}
CBackend::CBackend()
{
m_iBgX = m_iBgY = 0;
m_iNumDoodads = m_iNumSounds = 0;
for ( int i=0; i<MAXPLAYERS; ++i )
{
m_aoPlayers[i].m_iX = m_aoPlayers[i].m_iY = 0;
m_aoPlayers[i].m_iFrame = 0;
m_aoPlayers[i].m_iHitPoints = 0;
}
}
CBackend::~CBackend()
{
if ( NULL != my_perl )
{
perl_destruct( my_perl );
perl_free( my_perl );
my_perl = NULL;
}
}
bool CBackend::Construct()
{
if ( my_perl != NULL )
{
// Already inited
return false;
}
perl_bgx = NULL;
perl_doodad_x = NULL;
std::string sFileName = DATADIR;
sFileName += "/script";
#ifndef _WINDOWS
chdir( sFileName.c_str() );
#endif
// char *perl_argv[] = {"", "-d:Trace", "Backend.pl"};
// int perl_argc = 3;
char *perl_argv[] = {"", "Backend.pl"};
int perl_argc = 2;
my_perl = perl_alloc();
if ( my_perl == NULL )
{
return false;
}
perl_construct( my_perl );
if ( perl_parse( my_perl, NULL, perl_argc, perl_argv, (char**)NULL ) )
{
char *error = SvPV_nolen(get_sv("@", FALSE));
fprintf( stderr, "%s", error );
return false;
}
if ( perl_run( my_perl ) )
{
char *error = SvPV_nolen(get_sv("@", FALSE));
fprintf( stderr, "%s", error );
return false;
}
return true;
}
const char* CBackend::PerlEvalF( const char* a_pcFormat, ... )
{
va_list ap;
va_start( ap, a_pcFormat );
char acBuffer[1024];
vsnprintf( acBuffer, 1023, a_pcFormat, ap );
acBuffer[1023] = 0;
eval_pv(acBuffer,FALSE);
const char *pcError = SvPV_nolen(get_sv("@", FALSE));
if ( pcError && *pcError )
{
debug( "eval '%s': '%s'\n", acBuffer, pcError );
exit(0);
}
va_end( ap );
return pcError;
}
const char* CBackend::GetPerlString( const char* acScalarName )
{
SV* poScalar = get_sv( acScalarName, FALSE );
if ( NULL == poScalar )
{
return "";
}
return SvPV_nolen( poScalar );
}
int CBackend::GetPerlInt( const char* acScalarName )
{
SV* poScalar = get_sv( acScalarName, FALSE );
if ( NULL == poScalar )
{
return 0;
}
return SvIV( poScalar );
}
/** Returns the total number of registered fighters in the backend.
This may be more than the actual number of playable characters, as
some or many characters may not be ready or installed.
\see GetFighterID
\see GetNumberOfAvailableFighters
*/
int CBackend::GetNumberOfFighters()
{
PerlEvalF( "$::CppNumberOfFighters = scalar keys %%::FighterStats;" );
return GetPerlInt( "CppNumberOfFighters" );
}
/** Returns the ID of a fighter. The index parameter should start from
zero, and be less than the value returned by GetNumberOfFighters().
\see GetNumberOfFighters
*/
FighterEnum CBackend::GetFighterID( int a_iIndex )
{
PerlEvalF( "$::CppFighterID = (sort { $a - $b } keys %%::FighterStats)[%d];", a_iIndex );
return (FighterEnum) GetPerlInt( "CppFighterID" );
}
/** Returns the number of fighters that are locally availaible for play.
This number is smaller or equal to the value returned by GetNumberOfFighters().
Note that the method GetFighterID() returns ID's of non-available
fighters as well, so it can only be used in conjunction with GetNumberOfFighters()
\see GetNumberOfFighters
*/
int CBackend::GetNumberOfAvailableFighters()
{
PerlEvalF( "GetNumberOfAvailableFighters();" ); // Defined in FighterStats.pl
return GetPerlInt( "CppNumberOfAvailableFighters" );
}
-
-
+
+/**
+Makes the perl interpreter advance from the current scene to the next one.
+This should be called a constant number of time per second to make the game
+running seamlessly. Most speedup or slowdown effects are accomplished by
+changing the frequency at which this method is called.
+*/
void CBackend::AdvancePerl()
{
PerlEvalF("GameAdvance();");
}
void CBackend::ReadFromPerl()
{
int i;
if ( perl_bgx == NULL )
{
perl_gametick = get_sv("gametick", TRUE);
perl_bgx = get_sv("bgx", TRUE);
perl_bgy = get_sv("bgy", TRUE);
perl_over= get_sv("over", TRUE);
perl_ko = get_sv("ko", TRUE);
char acVarName[128];
for ( i=0; i<MAXPLAYERS; ++i )
{
sprintf( acVarName, "p%dx", i+1 );
perl_px[i] = get_sv(acVarName, TRUE);
sprintf( acVarName, "p%dy", i+1 );
perl_py[i] = get_sv(acVarName, TRUE);
sprintf( acVarName, "p%df", i+1 );
perl_pf[i] = get_sv(acVarName, TRUE);
sprintf( acVarName, "p%dh", i+1 );
perl_ph[i] = get_sv(acVarName, TRUE);
sprintf( acVarName, "p%dhreal", i+1 );
perl_phreal[i] = get_sv(acVarName, TRUE);
}
}
m_iGameTick = SvIV( perl_gametick );
m_iBgX = SvIV( perl_bgx );
m_iBgY = SvIV( perl_bgy );
m_iGameOver = SvIV( perl_over );
m_bKO = SvIV( perl_ko ) != 0;
for ( i=0; i<g_oState.m_iNumPlayers; ++i )
{
m_aoPlayers[i].m_iX = SvIV( perl_px[i] );
m_aoPlayers[i].m_iY = SvIV( perl_py[i] );
m_aoPlayers[i].m_iFrame = SvIV( perl_pf[i] );
m_aoPlayers[i].m_iHitPoints = SvIV( perl_ph[i] ) / 10;
m_aoPlayers[i].m_iRealHitPoints = SvIV( perl_phreal[i] );
}
// READ DOODAD DATA
if ( perl_doodad_x == NULL )
{
perl_doodad_x = get_sv("doodad_x", TRUE);
perl_doodad_y = get_sv("doodad_y", TRUE);
perl_doodad_t = get_sv("doodad_t", TRUE);
perl_doodad_f = get_sv("doodad_f", TRUE);
perl_doodad_dir = get_sv("doodad_dir", TRUE);
perl_doodad_gfxowner = get_sv("doodad_gfxowner", TRUE);
perl_doodad_text = get_sv("doodad_text", TRUE);
}
for ( m_iNumDoodads=0; m_iNumDoodads<MAXDOODADS; ++m_iNumDoodads )
{
PERLEVAL("GetNextDoodadData();");
SDoodad& oDoodad = m_aoDoodads[m_iNumDoodads];
oDoodad.m_iType = SvIV(perl_doodad_t);
if ( oDoodad.m_iType < 0 )
{
break;
}
oDoodad.m_iX = SvIV(perl_doodad_x);
oDoodad.m_iY = SvIV(perl_doodad_y);
oDoodad.m_iFrame = SvIV(perl_doodad_f);
oDoodad.m_iDir = SvIV(perl_doodad_dir);
oDoodad.m_iGfxOwner = SvIV(perl_doodad_gfxowner);
if ( oDoodad.m_iType == 0 )
{
oDoodad.m_sText = SvPV_nolen(perl_doodad_text);
}
else
{
oDoodad.m_sText = "";
}
}
// READ SOUND DATA
if ( perl_sound == NULL )
{
perl_sound = get_sv("sound", TRUE);
}
for ( m_iNumSounds=0; m_iNumSounds<MAXSOUNDS; ++m_iNumSounds )
{
PERLEVAL("GetNextSoundData();");
const char* pcSound = SvPV_nolen(perl_sound);
if ( NULL == pcSound
|| 0 == *pcSound )
{
break;
}
m_asSounds[ m_iNumSounds ] = pcSound;
//Audio->PlaySample( pcSound );
}
}
bool CBackend::IsDead( int a_iPlayer )
{
return m_aoPlayers[ a_iPlayer ].m_iRealHitPoints <= 0;
}
void CBackend::PlaySounds()
{
for ( int i=0; i<m_iNumSounds; ++i )
{
Audio->PlaySample( m_asSounds[i].c_str() );
}
}
/***************************************************************************
PLAYBACK STRING CONVERSION ROUTINES
***************************************************************************/
void CBackend::WriteToString( std::string& a_rsOutString )
{
char acBuffer[2048];
int iNumChars = sprintf( acBuffer, "%d %d %d %d %d %d %d %d %d %d %d ",
m_iBgX, m_iBgY,
m_aoPlayers[0].m_iX, m_aoPlayers[0].m_iY, m_aoPlayers[0].m_iFrame, m_aoPlayers[0].m_iHitPoints,
m_aoPlayers[1].m_iX, m_aoPlayers[1].m_iY, m_aoPlayers[1].m_iFrame, m_aoPlayers[1].m_iHitPoints,
m_iNumDoodads );
int i;
for ( i = 0; i<m_iNumDoodads; ++i )
{
SDoodad& roDoodad = m_aoDoodads[i];
iNumChars += sprintf( acBuffer+iNumChars, "%d %d %d %d %d %d %d %s ",
roDoodad.m_iX, roDoodad.m_iY, roDoodad.m_iType, roDoodad.m_iFrame,
roDoodad.m_iDir, roDoodad.m_iGfxOwner,
roDoodad.m_sText.size(), roDoodad.m_sText.c_str() );
}
iNumChars += sprintf( acBuffer+iNumChars, "%d ", m_iNumSounds );
for ( i = 0; i<m_iNumSounds; ++i )
{
iNumChars += sprintf( acBuffer+iNumChars, " %d %s",
m_asSounds[i].size(), m_asSounds[i].c_str() );
}
// debug( "Frame: '%s'\n", acBuffer );
a_rsOutString = acBuffer;
}
void CBackend::ReadFromString( const std::string& a_rsString )
{
ReadFromString( a_rsString.c_str() );
}
void CBackend::ReadFromString( const char* a_pcBuffer )
{
if ( strlen( a_pcBuffer ) < 10 )
{
m_iNumDoodads = m_iNumSounds = 0;
return;
}
int iNumMatches;
int iOffset, iTotal;
iNumMatches = sscanf( a_pcBuffer, "%d %d %d %d %d %d %d %d %d %d %d%n",
&m_iBgX, &m_iBgY,
&m_aoPlayers[0].m_iX, &m_aoPlayers[0].m_iY, &m_aoPlayers[0].m_iFrame, &m_aoPlayers[0].m_iHitPoints,
&m_aoPlayers[1].m_iX, &m_aoPlayers[1].m_iY, &m_aoPlayers[1].m_iFrame, &m_aoPlayers[1].m_iHitPoints,
&m_iNumDoodads, &iTotal );
if ( m_iNumDoodads > MAXDOODADS )
{
m_iNumDoodads = m_iNumSounds = 0;
return;
}
int i, j;
for ( i=0; i<m_iNumDoodads; ++i )
{
SDoodad& roDoodad = m_aoDoodads[i];
iNumMatches += sscanf( a_pcBuffer+iTotal, "%d %d %d %d %d %d %d %n",
&roDoodad.m_iX, &roDoodad.m_iY, &roDoodad.m_iType, &roDoodad.m_iFrame,
&roDoodad.m_iDir, &roDoodad.m_iGfxOwner,
&j, &iOffset );
iTotal += iOffset;
roDoodad.m_sText.assign( a_pcBuffer + iTotal, j );
iTotal += j;
}
iNumMatches += sscanf( a_pcBuffer + iTotal, "%d%n",
&m_iNumSounds, &iOffset );
if ( m_iNumSounds > MAXSOUNDS )
{
m_iNumSounds = 0;
return;
}
iTotal += iOffset;
for ( i=0; i<m_iNumSounds; ++i )
{
iNumMatches += sscanf( a_pcBuffer+iTotal, "%d %n",
&j, &iOffset );
iTotal += iOffset;
m_asSounds[i].assign( a_pcBuffer + iTotal, j );
iTotal += j;
}
}
diff --git a/src/Backend.h b/src/Backend.h
index e4a3063..11d2dfa 100644
--- a/src/Backend.h
+++ b/src/Backend.h
@@ -1,95 +1,105 @@
/***************************************************************************
Backend.h - description
-------------------
begin : Sun Dec 8 2002
copyright : (C) 2002 by upi
email : upi@apocalypse.rulez.org
***************************************************************************/
#ifndef BACKEND_H
#define BACKEND_H
#include <string>
#include "FighterEnum.h"
class CRlePack;
#define MAXDOODADS 20
#define MAXSOUNDS 20
/**
\class CBackend
\ingroup GameLogic
\brief The CBackend class provides access to the perl game engine.
The backend maintains just about all game-relevant data, such as fighters,
player information, doodads, current game state, and so forth. CBackend
provides access for the frontend to the backend's variables and functions.
Some of this is done via custom methods (such as GetNumberOfFighters()),
but certain functions are only available via the "generic" perl interface,
PerlEvalF().
+
+It is the CBackend's job to provide variables which describe the current
+\i scene to the frontend. The backend can
+
+\li Read the scene from the Perl backend.
+\li Write the scene into a string
+\li Read the scene from a string.
+
+The string conversion routines are used for saving replays and instant
+playback.
*/
class CBackend
{
public:
// Lifecycle
CBackend();
~CBackend();
bool Construct();
// Miscellaneous
const char* PerlEvalF( const char* a_pcFormat, ... );
const char* GetPerlString( const char* a_pcScalarName );
int GetPerlInt( const char* a_pcScalarName );
// Fighter enumeration
int GetNumberOfFighters();
FighterEnum GetFighterID( int a_iIndex );
int GetNumberOfAvailableFighters();
// Game data
void AdvancePerl();
void ReadFromPerl();
bool IsDead( int a_iPlayer );
void PlaySounds();
void WriteToString( std::string& a_rsOutString );
void ReadFromString( const std::string& a_rsString );
void ReadFromString( const char* a_pcBuffer );
public:
int m_iGameTick;
int m_iGameOver;
bool m_bKO;
int m_iBgX, m_iBgY;
int m_iNumDoodads;
int m_iNumSounds;
struct SPlayer
{
int m_iX, m_iY, m_iFrame, m_iHitPoints, m_iRealHitPoints;
} m_aoPlayers[MAXPLAYERS];
struct SDoodad
{
int m_iX, m_iY, m_iType, m_iFrame;
int m_iDir, m_iGfxOwner;
std::string m_sText;
} m_aoDoodads[ MAXDOODADS ];
std::string m_asSounds[ MAXSOUNDS ];
};
extern CBackend g_oBackend;
#endif
diff --git a/src/RlePack.h b/src/RlePack.h
index 6b8383c..eddd3fe 100644
--- a/src/RlePack.h
+++ b/src/RlePack.h
@@ -1,61 +1,72 @@
/***************************************************************************
RlePack.h - description
-------------------
begin : Mon Sep 24 2001
copyright : (C) 2001 by upi
email : upi@apocalypse.rulez.org
***************************************************************************/
#ifndef __RLEPACK_H
#define __RLEPACK_H
#include "FighterEnum.h"
struct CRlePack_P;
struct SDL_Surface;
/**
\class CRlePack
-\brief CRlePack is responsible for loading and drawing "sprites" from a .DAT file.
+\brief CRlePack is an array of images, compressed with runlength encoding.
\ingroup Media
+
+OpenMortal stores the character graphics in CRlePack objects. The reason is
+simple: CRlePacks give an acceptable tradeoff between memory usage and
+blitting speed. Also the CRlePack allows the sprites to be draw horizontally
+flipped, thus saving memory (the mirrored version of the same sprite doesn't
+need to be stored).
+
+The sprites in the RlePack are always paletted (8 bits per pixel). The size
+of the palette is between 1 and 256. The RlePack stores two copies of its
+palette: one is the "base" palette, as it was read from disk, the other is
+the "tinted" palette. The TintEnum contains values that can be passed to
+SetTint(). This is used for two things:
+
+\li In case both players choose the same fighter, player 2's fighter is
+tinted so they won't get confused.
+\li Some special effects (e.g. frozen) make the figther tinted as well.
CRlePack loads the sprites from a .DAT file in its constructor. If there is
an error (e.g. file doesn't exist), the number of sprites loaded will be 0.
-CRlePack is usually used to store the many frames of a fighter in MSZ. It is
-also used for the 'cast' in the MainScreenDemo.
-
-The palette by default ranges from 1 to N (the number of colors). This,
-however, can be changed with OffsetSprites(). This is used to make sure that
-the two loaded fighters don't overwrite each others palettes or the background
-palette.
-
-The 'tint' can be set with the SetTint method. It will not immediately appear
-until ApplyPalette() is called. For an explanation about tints, please see the
-TintEnum documentation.
+CRlePack is usually used to store the many frames of a fighter in OpenMortal.
+It is also used for the 'cast' in the CMainScreenDemo.
+
+CRlePack doesn't concern itself with concepts such as "player" or "doodad",
+it merely stores the palette and sprites. This part of OpenMortal can be
+reused in any project with little changes.
\sa TintEnum
*/
class CRlePack
{
public:
CRlePack( const char* a_pcFilename, int a_iNumColors );
~CRlePack();
void Clear();
int LoadFile( const char* a_pcFilename, int a_iNumColors );
int Count();
void OffsetSprites( int a_iOffset );
void SetTint( TintEnum a_enTint );
void ApplyPalette();
int GetWidth( int a_iIndex );
int GetHeight( int a_iIndex );
void Draw( int a_iIndex, int a_iX, int a_iY, bool a_bFlipped=false );
SDL_Surface* CreateSurface( int a_iIndex, bool a_bFlipped=false );
private:
CRlePack_P* p;
};
#endif
diff --git a/src/State.h b/src/State.h
index 26b837b..4edf69f 100644
--- a/src/State.h
+++ b/src/State.h
@@ -1,83 +1,101 @@
/***************************************************************************
State.h - description
-------------------
begin : Mon Aug 12 2003
copyright : (C) 2003 by upi
email : upi@apocalypse.rulez.org
***************************************************************************/
#ifndef STATE_H
#define STATE_H
#define MAXPLAYERS 4
/**
\ingroup GameLogic
SState aggregates all the state variables of OpenMortal that do not belong
to the backend. This includes transient variables such as the current
game mode (e.g. SStade::IN_DEMO) and configuration variables (such as the
keyboard layout).
-The SState variables are manipulated by the CMenu.
+SState is a singlular object, and is accessed with a global pointer,
+g_oState. All other frontend modules access the state through this object.
+The state is made persistent through it's methods, Load() and Save().
+Load() is called on program start, Save() is called when the program exits.
+
+
+The State is the way the CMenu communicate with the rest of the system.
+For example, if the user chooses "Quit" from the menu, the m_bQuitFlag is
+set to true, and the program will react accordingly.
+
+
+The state's most important properties are:
+
+\li m_enGameMode: The mode changes when a game is started or the game ends
+(either in the GameOver screen, or via the "Surrender Game" menu option).
+\li m_bQuitFlag: This is set if the program receives a quit event from the operating system (e.g. KILL signal, window close event, etc), or the user chooses "Quit" from the menu. Once the quit flag is set, the program will abort. All main loops check the value of the quit flag, and will break as soon as it is true.
+\li m_bFullScreen: Quite simply, it is true in fullscreen mode, and false in windowed mode. The user can change this via the menu. The State's ToggleFullscreen() method will switch between fullscreen and windowed mode. Maybe this functionality doesn't belong to the State? ...
+\li Sound properties: Mixing rate, number of channels, volume, etc.
+\li m_aiPlayerKeys: A double array of each player's keys. This is used most often in processing SDL key events: if the event's keysym matches a value in m_aiPlayerKeys, that means that a meaningful key was pushed or released.
*/
struct SState
{
enum TGameMode {
- IN_DEMO,
- IN_SINGLE,
- IN_MULTI,
- IN_NETWORK,
- IN_CHAT,
+ IN_DEMO, ///< The game is currently in "demo" mode: displaying the intro screens, etc.
+ IN_SINGLE, ///< The game is in single-player mode.
+ IN_MULTI, ///< The game is in multi-player mode.
+ IN_NETWORK, ///< There is against a network opponent in progress
+ IN_CHAT, ///< The user is on MortalNet
} m_enGameMode;
bool m_bQuitFlag; // true if quit event came
const char* m_pcArgv0; // Set by main to argv[0]
// CONFIGURATION VARIABLES
int m_iNumPlayers; // The number of players =2
enum TTeamModeEnum {
Team_ONE_VS_ONE,
Team_GOOD_VS_EVIL,
Team_CUSTOM,
} m_enTeamMode; // Team mode
int m_iTeamSize; // The size of each team.
int m_bTeamMultiselect; // Can the same player be selected twice?
int m_iGameTime; // Time of rounds in seconds.
int m_iHitPoints; // The initial number of hit points.
int m_iGameSpeed; // The speed of the game (fps = 1000/GameSpeed)
bool m_bFullscreen; // True in fullscreen mode.
int m_iChannels; // 1: mono, 2: stereo
int m_iMixingRate; // The mixing rate, in kHz
int m_iMixingBits; // 1: 8bit, 2: 16bit
int m_iMusicVolume; // Volume of music; 0: off, 100: max
int m_iSoundVolume; // Volume of sound effects; 0: off, 100: max
int m_aiPlayerKeys[MAXPLAYERS][9]; // Player keysyms
char m_acLanguage[10]; // Language ID (en,hu,fr,es,..)
int m_iLanguageCode; // Non-persistend language code (set by backend based on the language)
char m_acLatestServer[256]; // Last server
bool m_bServer; // We were server in the last network game
char m_acNick[128]; // The user name on the last server.
SState();
void Load();
void Save();
void ToggleFullscreen();
void SetLanguage( const char* a_pcLanguage );
void SetServer( const char* a_pcServer );
};
extern SState g_oState;
#endif
diff --git a/src/main.cpp b/src/main.cpp
index 99ca160..38c0c24 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,762 +1,759 @@
/***************************************************************************
main.cpp - description
-------------------
begin : Wed Aug 22 10:18:47 CEST 2001
copyright : (C) 2001 by upi
email : upi@apocalypse.rulez.org
***************************************************************************/
/**
\mainpage
The document you read now describes the design of OpenMortal. This page
serves as a starting point. The documentation is generated with doxygen
(http://doxygen.org).
OpenMortal consists of two main parts: the \b frontend and the \b backend.
\li The frontend is a C++ program, responsible for multimedia
(sounds, music, graphics) and general interaction with the players
(menus, keyboard input), and the demo and intro screens.
\li The backend is written in Perl, and is incorporated into the C++
program with Perl embedding.
-\section s1 Modules
+\section s1 1. Modules
The classes of OpenMortal are organized into the following groups (see Modules above).
\li \ref Media - OpenMortal uses \b SDL (http://libsdl.org) for hardware
access such as screen drawing, music, sound effect and keyboard input. For
information and documentation of SDL, SDL_image, SDL_ttf and SDL_mixer,
please look at the SDL homepage.
-
\li \ref PlayerSelect
\li \ref Network
\li \ref Demo
\li \ref GameLogic
-\section s2 Main Functions
+\section s2 2. Main Functions
These global functions implement important parts of the program. They serve
as entry points into functional parts.
\li DoMenu() - Displays and runs the menu over the current screen
\li GameOver() - Displays the "Final Judgeent" screen
\li DoDemos() - Runs the demos in an endless loop until a game is started or the program ends.
\li DoGame() - Runs the game.
\li DoOnlineChat() - Connects to and runs the MortalNet.
\li CPlayerSelect::DoPlayerSelect() - Runs the player selection screen.
-\section s3 Definitions
+\section s3 3. Definitions
Here are the definitions of terms used in this documentation.
<dl>
<dt>\b Player <dd>
- Player refers to one of the two persons playing the game. A player chooses a fighter. The two players are referred to as "Player 1" and "Player 2", even though the C++ and perl code count arrays from 0.
-
-
+ Player refers to one of the two persons playing the game. A player chooses a fighter. The two players are referred to as "Player 1" and "Player 2", even though the C++ and perl code count arrays from 0.
<dt>\b Fighter <dd>
Fighter is one of the many available characters. Usually there are only two fighters loaded at any time. Fighters are static: their properties never change. Maybe Fighter should be renamed to Character?
<dt>\b Game <dd>
One game is the part of the program in which the players actually compete. The game consists of a number of rounds. The player selection, and gameover screen are not part of this definition.
<dt>\b Round <dd>
One round starts with both players at full health, and ends either with a timeout or with a ko.
<dt>\b Doodad <dd>
A graphical element on the game screen that is not the background or the characters. E.g. the "3x combo" text or a thrown projectile are doodads.
<dt>\b Tint <dd>
A tint is a methodical change in a palette. There are many ways to tint (e.g. grayscaling, darkening, green chroma, etc). Usually when two players choose the same fighter, the fighter of player 2 is tinted.
<dt>\b Scene <dd>
The description of a frozen moment in the course of a game. The Backend is responsible for calculating each consecutive scene. The number of scenes calculated per second is constant (except for the "hurry up mode", or if the computer is too slow).
<dt>\b FPS <dd>
Frames Per Second. The FPS indicator on the screen during a game indicates the number of scenes drawn, not the number of scenes calculated by the backend.
</dl>
-\section s4 C++ Coding conventions
+\section s4 4. C++ Coding conventions
Historically two different coding conventions were mixed in OpenMortal.
Hopefully most of the old conventions are eliminated by now.
Here I will describe the new conventions:
\li <B> Class names: </B> CMixedCaps.
\li <B> Struct names: </B> SMixedCaps.
\li <B> Typedef names: </B> CSomeTypedef (There's some traces of the old TSomeTypedef
left, these should be eliminated.
\li <B> Enum names: </B> SomeThingEnum.
\li <B> Enum values: </B> Prefix_ENUM_VALUE
\li <B> Method names: </B> MixedCaps.
\li <B> Variable names: </B> &lt;prefix&gt;VariableName.
\li <B> Instance property names: </B> m_&lt;prefix&gt;VariableName,
\li <B> Class property names </B>(a.k.a. static class variables): mg_&lt;prefix&gt;VariableName.
\li <B> Method argument names: </B> a_&lt;prefix&gt;VariableName.
If a reference or pointer argument is "output-only: a_&lt;prefix&gt;OutVariableName.
\li <B> Global variable names: </B> g_&lt;prefix&gt;VariableName.
The prefixes used are:
\li <B> Array of something: </B> a&lt;something&gt;
\li <B> Pointer to something: </B> p&lt;something&gt;
\li <B> Reference of something: </B> r&lt;something&gt;
\li <B> Basic types: </B> Integer: i; char: c; double: d; enum: en; object (class or struct): o; std::string: s;
Example:
\code
CSomeExampleClass: public CSomeBaseClass
{
public:
CSomeExampleClass();
void SomeMethod( int& a_riOutSomething );
protected:
int m_iSomething;
char* m_pcSomethingElse;
static enum SomeThingEnum
{
Ste_VALUE,
} mg_enWhatever;
};
\endcode
*/
#include "config.h"
#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;
bool bDebug = false;
Uint32 C_BLACK, C_BLUE, C_GREEN, C_CYAN, C_RED, C_MAGENTA, C_ORANGE, C_LIGHTGRAY,
C_DARKGRAY, C_LIGHTBLUE, C_LIGHTGREEN, C_LIGHTCYAN, C_LIGHTRED, C_LIGHTMAGENTA, C_YELLOW, C_WHITE;
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()
{
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);
SetVideoMode( false, g_oState.m_bFullscreen );
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 );
int i;
for ( i=0; i<16; ++i )
{
Colors[i].r *=4; Colors[i].g *=4; Colors[i].b *=4;
}
if ( gamescreen->format->BitsPerPixel > 8 )
{
i = 0;
C_BLACK = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
C_BLUE = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
C_GREEN = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
C_CYAN = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
C_RED = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
C_MAGENTA = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
C_ORANGE = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
C_LIGHTGRAY = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
C_DARKGRAY = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
C_LIGHTBLUE = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
C_LIGHTGREEN = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
C_LIGHTCYAN = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
C_LIGHTRED = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
C_LIGHTMAGENTA = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
C_YELLOW = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
C_WHITE = SDL_MapRGB( gamescreen->format, Colors[i].r, Colors[i].g, Colors[i].b ); ++i;
}
else
{
SDL_SetColors( gamescreen, Colors, 256-16, 16 );
C_BLACK = 240;
C_BLUE = 241;
C_GREEN = 242;
C_CYAN = 243;
C_RED = 244;
C_MAGENTA = 245;
C_ORANGE = 246;
C_LIGHTGRAY = 247;
C_DARKGRAY = 248;
C_LIGHTBLUE = 249;
C_LIGHTGREEN = 250;
C_LIGHTCYAN = 251;
C_LIGHTRED = 252;
C_LIGHTMAGENTA = 253;
C_YELLOW = 254;
C_WHITE = 255;
}
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.jpg", 240 );
DrawTextMSZ( "Version " VERSION " - European Union Editition", 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";
CRlePack pack( sStaffFilename.c_str(), 256 );
pack.ApplyPalette();
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;
*/
int iNumFighterFiles, i;
#ifdef MACOSX
//[segabor]
char char_buf[256];
sprintf(char_buf, "%s/characters", DATADIR);
g_oBackend.PerlEvalF( "$CppRetval = GetNumberOfFighterFiles('%s')", char_buf );
#else
g_oBackend.PerlEvalF( "$CppRetval = GetNumberOfFighterFiles('%s')", DATADIR "/characters" );
#endif
iNumFighterFiles = g_oBackend.GetPerlInt( "CppRetval" );
for ( i=0; i<iNumFighterFiles; ++i )
{
g_oBackend.PerlEvalF( "LoadFighterFile(%d);", i );
if ( i < 15 ) {
pack.Draw( i, x[i], y[i], false );
SDL_Flip( gamescreen );
}
}
SDL_FreeSurface( background );
return 0;
}
int InitJoystick();
/**
The game loop consists of the following events:
\li Player selection
\li DoGame
\li GameOver and FighterStatsDemo (not in network mode)
The loop ends if the game mode changes to a non-game mode (e.g. IN_DEMO or IN_CHAT)
*/
void GameLoop()
{
class CVideoModeChange
{
public:
CVideoModeChange( bool a_bWide )
{
m_bWide = a_bWide;
if ( m_bWide ) SetVideoMode( true, g_oState.m_bFullscreen );
}
~CVideoModeChange()
{
if ( m_bWide ) SetVideoMode( false, g_oState.m_bFullscreen );
}
bool m_bWide;
} oVideoModeChanger( g_oState.m_iNumPlayers > 2 );
#define IS_GAME_MODE (g_oState.m_enGameMode != SState::IN_DEMO \
&& g_oState.m_enGameMode != SState::IN_CHAT \
&& !g_oState.m_bQuitFlag)
Audio->PlaySample( "GAME_NEW" );
Audio->PlayMusic( "GameMusic" );
bool bNetworkGame = SState::IN_NETWORK == g_oState.m_enGameMode;
if ( bNetworkGame )
{
g_oState.m_enTeamMode = SState::Team_ONE_VS_ONE;
}
while ( IS_GAME_MODE )
{
if ( SState::Team_GOOD_VS_EVIL == g_oState.m_enTeamMode )
{
std::vector<FighterEnum>& roTeam0 = g_oPlayerSelect.EditPlayerInfo(0).m_aenTeam;
std::vector<FighterEnum>& roTeam1 = g_oPlayerSelect.EditPlayerInfo(1).m_aenTeam;
roTeam0.clear();
roTeam1.clear();
roTeam0.push_back( SIRPI );
roTeam0.push_back( MACI );
roTeam0.push_back( GRIZLI );
roTeam0.push_back( DANI );
roTeam0.push_back( KINGA );
roTeam0.push_back( CUMI );
roTeam1.push_back( ZOLI );
roTeam1.push_back( ULMAR );
roTeam1.push_back( BENCE );
roTeam1.push_back( AMBRUS );
roTeam1.push_back( DESCANT ); // Temporary assignment
roTeam1.push_back( UPI );
for ( int i=0; i<10; ++i )
{
int j = rand() % ( roTeam0.size() -1 );
int k = rand() % ( roTeam0.size() -1 );
FighterEnum enTemp;
enTemp = roTeam0[j]; roTeam0[j] = roTeam0[k]; roTeam0[k] = enTemp;
j = rand() % ( roTeam1.size() -1 );
k = rand() % ( roTeam1.size() -1 );
enTemp = roTeam1[j]; roTeam1[j] = roTeam1[k]; roTeam1[k] = enTemp;
}
}
else
{
g_oPlayerSelect.DoPlayerSelect();
}
if ( !IS_GAME_MODE ) break;
//sprintf( acReplayFile, "/tmp/msz%d.replay", ++iGameNumber );
int iGameResult = DoGame( NULL, false, bDebug );
//int iGameResult = DoGame( acReplayFile, false, bDebug );
//DoGame( acReplayFile, true, bDebug );
debug ( "iGameResult = %d\n", iGameResult );
if ( !IS_GAME_MODE ) break;
if ( iGameResult >= 0 && !bNetworkGame )
{
GameOver( iGameResult );
CFighterStatsDemo oDemo( g_oPlayerSelect.GetPlayerInfo( iGameResult ).m_enFighter );
oDemo.Run();
}
if ( !IS_GAME_MODE ) 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 );
SDL_Delay( 1000 );
GetKey( true );
}
if ( !g_oState.m_bQuitFlag )
{
Audio->PlayMusic( "DemoMusic" );
}
}
/**
The chat loop consists of:
\li DoOnlineChat
\li GameLoop (if a game was started
The loop ends if DoOnlineChat returns with a quit or disconnect
(not IN_NETWORK mode).
*/
void ChatLoop()
{
while (1)
{
DoOnlineChat();
if ( g_oState.m_bQuitFlag ||
SState::IN_CHAT != g_oState.m_enGameMode )
{
break;
}
if ( SState::IN_NETWORK == g_oState.m_enGameMode )
{
GameLoop();
}
if ( g_oState.m_bQuitFlag ) break;
g_oState.m_enGameMode = SState::IN_CHAT;
}
}
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();
bDebug = false;
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] );
printf( "Usage: %s [-debug]\n", argv[0] );
return 0;
}
}
if (init()<0)
{
return -1;
}
InitJoystick();
g_oState.SetLanguage( g_oState.m_acLanguage );
new COpenMortalAudio;
// 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, UPI );
g_oPlayerSelect.SetPlayer( 1, ULMAR );
/*
{
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 );
}
}
*/
/* while ( !g_oState.m_bQuitFlag )
{
g_oState.m_enGameMode = SState::IN_MULTI;
g_oState.m_bTeamMultiselect = false;
g_oState.m_iTeamSize = 3;
g_oState.m_enTeamMode = SState::Team_CUSTOM;
std::vector<FighterEnum>& roTeam0 = g_oPlayerSelect.EditPlayerInfo(0).m_aenTeam;
std::vector<FighterEnum>& roTeam1 = g_oPlayerSelect.EditPlayerInfo(1).m_aenTeam;
roTeam0.clear();
roTeam0.push_back( ZOLI );
roTeam0.push_back( SIRPI );
roTeam0.push_back( MACI );
roTeam1.clear();
roTeam1.push_back( UPI );
roTeam1.push_back( ZOLI );
roTeam1.push_back( ULMAR );
DoGame( NULL, false, false );
}
*/
while ( 1 )
{
if ( g_oState.m_bQuitFlag ) break;
switch ( g_oState.m_enGameMode )
{
case SState::IN_DEMO:
DoDemos();
continue;
case SState::IN_CHAT:
ChatLoop();
continue;
default:
GameLoop();
continue;
}
#if 0
// 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 );
SDL_Delay( 1000 );
GetKey( true );
}
if ( g_oState.m_bQuitFlag ) break;
Audio->PlayMusic( "DemoMusic" );
#endif
}
g_oState.Save();
SDL_Quit();
return EXIT_SUCCESS;
}

File Metadata

Mime Type
text/x-diff
Expires
Tue, Jun 16, 1:01 AM (2 w, 23 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
72633
Default Alt Text
(44 KB)

Event Timeline