Page Menu
Home
Phabricator (Chris)
Search
Configure Global Search
Log In
Files
F102546
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
45 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/MortalNetworkImpl.cpp b/src/MortalNetworkImpl.cpp
index 4a04ef0..a0ccbab 100644
--- a/src/MortalNetworkImpl.cpp
+++ b/src/MortalNetworkImpl.cpp
@@ -1,902 +1,902 @@
/***************************************************************************
MortalNetworkImpl.cpp - description
-------------------
begin : Sun Jan 25 2004
copyright : (C) 2004 by upi
email : upi@feel
***************************************************************************/
#include "MortalNetworkImpl.h"
#include "State.h"
#include "PlayerSelect.h"
#include "common.h"
#include "config.h"
#define MORTALNETWORKPORT 0x3A22
// Some graphics routines, defined in menu.cpp
void MortalNetworkResetMessages( bool a_bClear );
void MortalNetworkMessage( const char* format, ... );
bool MortalNetworkCheckKey();
const char* GetGameTimeString( int a_iValue );
const char* GetGameSpeedString( int a_iValue );
const char* GetHitPointsString( int a_iValue );
CMortalNetwork* g_poNetwork = NULL;
void CMortalNetwork::Create() // static
{
if ( NULL == g_poNetwork )
{
g_poNetwork = new CMortalNetworkImpl;
}
}
CMortalNetworkImpl::CMortalNetworkImpl()
{
m_enState = NS_DISCONNECTED;
m_bServer = false;
m_bMaster = false;
m_poSocket = NULL;
m_enRemoteFighter = UNKNOWN;
m_bRemoteReady = false;
m_bRoundOver = false;
m_iWhoWon = -1;
m_bGameOver = false;
m_iGameTime = 0;
m_iGamePhase = 0;
m_iHurryupCode = 0;
m_iIncomingBufferSize = 0;
if(SDLNet_Init()==-1)
{
m_bNetworkAvailable = false;
m_sLastError = SDLNet_GetError();
debug ( "Error opening SDLNet: %s\n", m_sLastError.c_str() );
}
m_bNetworkAvailable = true;
}
CMortalNetworkImpl::~CMortalNetworkImpl()
{
Stop();
}
bool CMortalNetworkImpl::Start( const char* a_pcServerName )
{
#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; }
if ( !m_bNetworkAvailable )
{
return false;
}
debug( "CMortalNetworkImpl::Start( %s )\n", a_pcServerName ? a_pcServerName : "NULL" );
IPaddress oAddress;
if ( a_pcServerName )
{
MortalNetworkMessage( Translate("Resolving hostname...") );
}
int iResult = SDLNet_ResolveHost( &oAddress, a_pcServerName, MORTALNETWORKPORT );
if ( iResult )
{
m_sLastError = Translate( "Couldn't resolve host." );
RETURNNOERROR;
}
debug( "IP Address of server is 0x%x\n", oAddress.host );
if ( a_pcServerName )
{
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);
}
if ( !a_pcServerName )
{
// SERVER-MODE CONNECTION
m_poSocket = SDLNet_TCP_Open( &oAddress );
// Wait for connection ...
MortalNetworkMessage ( Translate("Waiting for connection... (press any key to abort)") );
TCPsocket poClient;
while ( 1 )
{
poClient = SDLNet_TCP_Accept( m_poSocket );
if ( poClient ) break;
if (MortalNetworkCheckKey()) break;;
SDL_Delay( 100 );
}
SDLNet_TCP_Close( m_poSocket );
if ( NULL == poClient )
{
m_sLastError = "No connection.";
return false;
}
IPaddress* poRemoteAddress = SDLNet_TCP_GetPeerAddress(poClient);
if ( !poRemoteAddress )
{
RETURNWITHERROR;
}
Uint32 ipaddr=SDL_SwapBE32(poRemoteAddress->host);
MortalNetworkMessage("Accepted connection from %d.%d.%d.%d port %d",
ipaddr>>24, (ipaddr>>16)&0xff, (ipaddr>>8)&0xff, ipaddr&0xff, oAddress.port);
// Set the client socket as our socket, and drop the server socket.
m_poSocket = poClient;
}
else
{
// CLIENT-MODE CONNECTION
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.") );
struct SIntroPackage
{
char cID;
char acVersion[10];
} oIntroPackage, oRemotePackage;
oIntroPackage.cID = 'I';
strncpy( oIntroPackage.acVersion, VERSION, 10 );
oIntroPackage.acVersion[9] = 0;
debug( "Sending intro package... " );
int iRetval = SDLNet_TCP_Send( m_poSocket, &oIntroPackage, sizeof( oIntroPackage ) );
if ( iRetval < (int) sizeof( oIntroPackage ) )
{
RETURNWITHERROR;
}
iRetval = SDLNet_TCP_Recv( m_poSocket, &oRemotePackage, sizeof( oRemotePackage ) );
if ( iRetval <= 0 )
{
RETURNWITHERROR;
}
if ( iRetval < (int) sizeof( oRemotePackage )
|| oRemotePackage.cID != 'I'
|| strncmp( oRemotePackage.acVersion, VERSION, 9 ) )
{
m_sLastError = Translate( "The remote side has a different version of OpenMortal running." );
RETURNNOERROR;
}
MortalNetworkMessage( Translate("Life is good.") );
m_enState = NS_CHARACTER_SELECTION;
m_bServer = NULL == a_pcServerName;
m_bMaster = m_bServer;
m_sLastError = "";
m_asMsgs.clear();
m_enRemoteFighter = UNKNOWN;
m_bRemoteReady = false;
m_sLatestGameData = "";
m_aiKeystrokes.clear();
m_abKeystrokes.clear();
m_iGameTime = 0;
m_iGamePhase = 0;
m_iHurryupCode = 0;
m_iIncomingBufferSize = 0;
m_aiAvailableRemoteFighters.clear();
m_oGameParams.iGameTime = m_oGameParams.iGameSpeed = m_oGameParams.iHitPoints = -1;
m_poSocketSet = SDLNet_AllocSocketSet( 1 );
SDLNet_TCP_AddSocket( m_poSocketSet, m_poSocket ); // Check for errors?
return true;
}
void CMortalNetworkImpl::Stop()
{
if ( NS_DISCONNECTED == m_enState )
{
return;
}
g_oState.m_enGameMode = SState::IN_DEMO;
m_enState = NS_DISCONNECTED;
SDLNet_FreeSocketSet( m_poSocketSet );
SDLNet_TCP_Close( m_poSocket );
}
bool CMortalNetworkImpl::IsConnectionAlive()
{
return ( NS_DISCONNECTED != m_enState );
}
#define DISCONNECTONCOMMUNICATIONERROR { \
m_sLastError = Translate("Communication error. Disconnecting."); \
Stop(); \
return; }
#define DISCONNECTWITH(A) { \
m_sLastError = Translate("Communication error. Disconnecting."); \
Stop(); \
return(A); }
#define CHECKCONNECTION if ( NS_DISCONNECTED == m_enState ) return;
void CMortalNetworkImpl::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
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;
while ( iOffset < m_iIncomingBufferSize )
{
// 3.1. Check if we have enough data to receive the package.
if ( m_iIncomingBufferSize - iOffset < 4 )
{
// Not enough space left for a full header.
debug( "Not enough space left for a full header (%d).\n", m_iIncomingBufferSize-iOffset );
break;
}
unsigned int iLengthOfPackage = SDL_SwapBE16(*((Uint16*)(m_acIncomingBuffer + iOffset + 1)));
if ( iLengthOfPackage > 1000 )
{
debug( "Maximum package size exceeded.\n" );
DISCONNECTONCOMMUNICATIONERROR;
}
debug( "Receiving stuff.. %c type, %d package length, offset %d in buffer, %d bytes in buffer\n",
m_acIncomingBuffer[iOffset], iLengthOfPackage, iOffset, m_iIncomingBufferSize );
if ( iOffset + 4 + (int)iLengthOfPackage > m_iIncomingBufferSize )
{
// Not enough space left for the actual package.
debug( "Not enough space left for the actual package.\n" );
break;
}
// 3.2. Receive the data.
switch ( m_acIncomingBuffer[iOffset] )
{
case 'M': ReceiveMsg( m_acIncomingBuffer+iOffset+4, iLengthOfPackage ); break;
case 'F': ReceiveFighter( m_acIncomingBuffer+iOffset+4, iLengthOfPackage ); break;
case 'R': ReceiveReady( m_acIncomingBuffer+iOffset+4, iLengthOfPackage ); break;
case 'S': m_bSynchQueryResponse=true; break;
case 'G': ReceiveGameData( m_acIncomingBuffer+iOffset+4, iLengthOfPackage ); break;
case 'K': ReceiveKeystroke( m_acIncomingBuffer+iOffset+4, iLengthOfPackage ); break;
case 'O': ReceiveRoundOver( m_acIncomingBuffer+iOffset+4, iLengthOfPackage ); break;
case 'T': ReceiveGameTime( m_acIncomingBuffer+iOffset+4, iLengthOfPackage ); break;
case 'H': ReceiveHurryup( m_acIncomingBuffer+iOffset+4, iLengthOfPackage ); break;
case 'A': ReceiveRemoteFighterAvailable( m_acIncomingBuffer+iOffset+4, iLengthOfPackage ); break;
case 'Q': ReceiveRemoteFighterQuery( m_acIncomingBuffer+iOffset+4, iLengthOfPackage ); break;
case 'P': ReceiveGameParams( m_acIncomingBuffer+iOffset+4, iLengthOfPackage ); break;
default:
{
debug( "Bad ID: %c (%d)\n", m_acIncomingBuffer[iOffset], m_acIncomingBuffer[iOffset] );
DISCONNECTONCOMMUNICATIONERROR;
}
}
if ( !IsConnectionAlive() )
{
return;
}
iOffset += iLengthOfPackage + 4;
}
// 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;
}
const char* CMortalNetworkImpl::GetLastError()
{
return m_sLastError.c_str();
}
bool CMortalNetworkImpl::IsMaster()
{
return m_bMaster;
}
const char* CMortalNetworkImpl::GetRemoteUsername()
{
return "upi";
}
/*************************************************************************
MSG RELATED METHODS
*************************************************************************/
/** All sent data must go through this method. It ensures the well-formed
header for the data.
The header itself looks like this:
ID char
Length Uint16
Reserved char
This is followed by as many bytes as the Length is.
*/
void CMortalNetworkImpl::SendRawData( char a_cID, const void* a_pData, int a_iLength )
{
CHECKCONNECTION;
char acBuffer[4];
acBuffer[0] = a_cID;
*((Uint16*)(acBuffer+1)) = SDL_SwapBE16( a_iLength );
acBuffer[3] = 0;
int iRetval = SDLNet_TCP_Send( m_poSocket, &acBuffer, 4 );
if ( iRetval != 4 ) DISCONNECTONCOMMUNICATIONERROR;
if ( a_iLength )
{
iRetval = SDLNet_TCP_Send( m_poSocket, (void*) a_pData, a_iLength );
if (iRetval != a_iLength ) DISCONNECTONCOMMUNICATIONERROR;
}
}
#define MAXSTRINGLENGTH 900
void CMortalNetworkImpl::SendMsg( const char* a_pcMsg )
{
CHECKCONNECTION;
int iMsgLen = strlen( a_pcMsg ) + 1;
if ( iMsgLen > MAXSTRINGLENGTH )
{
// Will not be 0 terminated if exceeds length!
iMsgLen = MAXSTRINGLENGTH;
}
SendRawData( 'M', a_pcMsg, iMsgLen );
}
void CMortalNetworkImpl::ReceiveMsg( void* a_pData, int a_iLength )
{
if ( a_iLength < 1 || a_iLength > MAXSTRINGLENGTH ) DISCONNECTONCOMMUNICATIONERROR;
char* acData = (char*) a_pData;
acData[ a_iLength-1 ] = 0; // Last char should be 0, just making sure..
m_asMsgs.push_back( acData );
}
bool CMortalNetworkImpl::IsMsgAvailable()
{
return m_asMsgs.size() > 0;
}
const char* CMortalNetworkImpl::GetMsg()
{
static std::string sLastMsg;
if ( IsMsgAvailable() )
{
sLastMsg = m_asMsgs.front();
m_asMsgs.pop_front();
return sLastMsg.c_str();
}
return NULL;
}
/*************************************************************************
CHARACTER SELECTION RELATED METHODS
*************************************************************************/
bool CMortalNetworkImpl::IsRemoteFighterAvailable( FighterEnum a_enFighter )
{
if ( 0 == a_enFighter )
{
return false;
}
// Check if we already have it cached.
if ( std::find( m_aiAvailableRemoteFighters.begin(), m_aiAvailableRemoteFighters.end(), a_enFighter ) != m_aiAvailableRemoteFighters.end() )
{
return true;
}
if ( std::find( m_aiAvailableRemoteFighters.begin(), m_aiAvailableRemoteFighters.end(), -a_enFighter ) != m_aiAvailableRemoteFighters.end() )
{
return false;
}
Uint32 iFighter = SDL_SwapBE32( a_enFighter );
SendRawData( 'Q', &iFighter, sizeof(Uint32) );
for ( int i=0; i<100; ++i )
{
SDL_Delay(10);
Update();
if ( std::find( m_aiAvailableRemoteFighters.begin(), m_aiAvailableRemoteFighters.end(), a_enFighter ) != m_aiAvailableRemoteFighters.end() )
{
return true;
}
if ( std::find( m_aiAvailableRemoteFighters.begin(), m_aiAvailableRemoteFighters.end(), -a_enFighter ) != m_aiAvailableRemoteFighters.end() )
{
return false;
}
}
m_aiAvailableRemoteFighters.push_front( -a_enFighter );
return false;
}
void CMortalNetworkImpl::ReceiveRemoteFighterQuery( void* a_pData, int a_iLength )
{
if ( a_iLength != sizeof(Uint32) ) DISCONNECTONCOMMUNICATIONERROR;
FighterEnum iFighter = (FighterEnum) SDL_SwapBE32( *((Uint32*)a_pData) );
bool bAvailable = g_oPlayerSelect.IsLocalFighterAvailable( iFighter );
Uint32 iResponse = bAvailable ? iFighter : iFighter + 100000;
debug( "ReceiveRemoteFighterQuery: %d -> %d\n", iFighter, iResponse );
iResponse = SDL_SwapBE32( iResponse );
SendRawData( 'A', &iResponse, sizeof(Uint32) );
}
void CMortalNetworkImpl::ReceiveRemoteFighterAvailable( void* a_pData, int a_iLength )
{
if ( a_iLength != sizeof(Uint32) ) DISCONNECTONCOMMUNICATIONERROR;
Uint32 iFighter = SDL_SwapBE32( *((Uint32*)a_pData) );
debug( "ReceiveRemoteFighterAvailable: %d\n", iFighter );
if ( iFighter >= 100000 )
{
m_aiAvailableRemoteFighters.push_front( -(iFighter-100000) );
}
else
{
m_aiAvailableRemoteFighters.push_front( iFighter );
}
}
void CMortalNetworkImpl::SendFighter( FighterEnum a_enFighter )
{
CHECKCONNECTION;
Uint32 iFighter = SDL_SwapBE32( a_enFighter );
SendRawData( 'F', &iFighter, sizeof (iFighter) );
}
void CMortalNetworkImpl::ReceiveFighter( void* a_pcData, int a_iLength )
{
Uint32 iFighter;
if ( a_iLength != sizeof(iFighter) ) DISCONNECTONCOMMUNICATIONERROR;
iFighter = *((Uint32*)a_pcData);
m_enRemoteFighter = (FighterEnum) SDL_SwapBE32( iFighter );
debug( "ReceiveFighter: %d\n", m_enRemoteFighter );
}
FighterEnum CMortalNetworkImpl::GetRemoteFighter()
{
return m_enRemoteFighter;
}
void CMortalNetworkImpl::SendReady()
{
CHECKCONNECTION;
SendRawData( 'R', NULL, 0 );
}
void CMortalNetworkImpl::ReceiveReady( void* a_pData, int a_iLength )
{
if ( a_iLength != 0 ) DISCONNECTONCOMMUNICATIONERROR;
m_bRemoteReady = true;
}
bool CMortalNetworkImpl::IsRemoteSideReady()
{
return m_bRemoteReady;
}
void CMortalNetworkImpl::SendGameParams( int a_iGameSpeed, int a_iGameTime, int a_iHitPoints )
{
CHECKCONNECTION;
if ( (int)m_oGameParams.iGameSpeed == a_iGameSpeed
&& (int)m_oGameParams.iGameTime == a_iGameTime
&& (int)m_oGameParams.iHitPoints == a_iHitPoints )
{
// Nothing to update.
return;
}
m_oGameParams.iGameSpeed = a_iGameSpeed;
m_oGameParams.iGameTime = a_iGameTime;
m_oGameParams.iHitPoints = a_iHitPoints;
SGameParams oPackage;
oPackage.iGameSpeed = SDL_SwapBE32( a_iGameSpeed );
oPackage.iGameTime = SDL_SwapBE32( a_iGameTime );
oPackage.iHitPoints = SDL_SwapBE32( a_iHitPoints );
SendRawData( 'P', &oPackage, sizeof(SGameParams) );
}
void CMortalNetworkImpl::ReceiveGameParams( void* a_pData, int a_iLength )
{
if ( a_iLength != sizeof(SGameParams) ) DISCONNECTONCOMMUNICATIONERROR;
SGameParams* poPackage = (SGameParams*) a_pData;
if ( m_oGameParams.iGameSpeed != SDL_SwapBE32( poPackage->iGameSpeed ) )
{
m_oGameParams.iGameSpeed = SDL_SwapBE32( poPackage->iGameSpeed );
- m_asMsgs.push_back( GetGameSpeedString( m_oGameParams.iGameSpeed ) );
+ m_asMsgs.push_back( std::string("*** ") + GetGameSpeedString( m_oGameParams.iGameSpeed ) );
}
if ( m_oGameParams.iGameTime != SDL_SwapBE32( poPackage->iGameTime ) )
{
m_oGameParams.iGameTime = SDL_SwapBE32( poPackage->iGameTime );
- m_asMsgs.push_back( GetGameTimeString( m_oGameParams.iGameTime) );
+ m_asMsgs.push_back( std::string("*** ") + GetGameTimeString( m_oGameParams.iGameTime) );
}
if ( m_oGameParams.iHitPoints != SDL_SwapBE32( poPackage->iHitPoints ) )
{
m_oGameParams.iHitPoints = SDL_SwapBE32( poPackage->iHitPoints );
- m_asMsgs.push_back( GetHitPointsString( m_oGameParams.iHitPoints ) );
+ m_asMsgs.push_back( std::string("*** ") + GetHitPointsString( m_oGameParams.iHitPoints ) );
}
}
/*************************************************************************
GAME RELATED METHODS
*************************************************************************/
bool CMortalNetworkImpl::SynchStartRound()
{
debug( "SynchStartRound STARTED.\n" );
m_bSynchQueryResponse = false;
// run until both sides manage to get a SYNCH
int i=0;
while ( !m_bSynchQueryResponse )
{
SendRawData('S', NULL, 0);
if ( !IsConnectionAlive() ) break;
Update();
SDL_Delay(100);
if ( !IsConnectionAlive() ) break;
++i;
if ( i == 10 )
{
debug( "Synch is slow...\n" );
MortalNetworkResetMessages( true );
MortalNetworkMessage( "Synching with remote side..." );
MortalNetworkMessage( "Press any key to disconnect." );
}
if ( i > 10
&& MortalNetworkCheckKey() )
{
Stop();
return false;
}
}
if ( IsConnectionAlive() )
{
m_enState = NS_IN_GAME;
m_bRoundOver = false;
m_bGameOver = false;
m_bRemoteReady = false;
m_bSynchQueryResponse = false;
m_iHurryupCode = -1;
}
return IsConnectionAlive();
debug( "SynchStartRound FINISHED.\n" );
}
void CMortalNetworkImpl::SendGameData( const char* a_pcGameData )
{
CHECKCONNECTION;
int iMsgLen = strlen( a_pcGameData ) + 1;
if ( iMsgLen > MAXSTRINGLENGTH )
{
// Will not be 0 terminated if exceeds length!
iMsgLen = MAXSTRINGLENGTH;
}
SendRawData( 'G', a_pcGameData, iMsgLen );
}
void CMortalNetworkImpl::ReceiveGameData( void* a_pData, int a_iLength )
{
if ( a_iLength < 1 || a_iLength > MAXSTRINGLENGTH ) DISCONNECTONCOMMUNICATIONERROR;
char* pcData = (char*) a_pData;
pcData[ a_iLength-1 ] = 0; // Last char should be 0, just making sure..
if ( pcData[0] )
{
m_sLatestGameData = pcData;
}
}
const char* CMortalNetworkImpl::GetLatestGameData()
{
return m_sLatestGameData.c_str();
}
struct SKeystrokePackage
{
char cKey;
bool bPressed;
};
void CMortalNetworkImpl::SendKeystroke( int a_iKey, bool a_bPressed )
{
CHECKCONNECTION;
SKeystrokePackage oPackage;
oPackage.cKey = a_iKey;
oPackage.bPressed = a_bPressed;
SendRawData( 'K', &oPackage, sizeof( oPackage) );
}
void CMortalNetworkImpl::ReceiveKeystroke( void* a_pData, int a_iLength )
{
if ( a_iLength != (int)sizeof(SKeystrokePackage) ) DISCONNECTONCOMMUNICATIONERROR;
SKeystrokePackage* poPackage = (SKeystrokePackage*) a_pData;
m_aiKeystrokes.push_back( poPackage->cKey );
m_abKeystrokes.push_back( poPackage->bPressed );
}
bool CMortalNetworkImpl::GetKeystroke( int& a_riOutKey, bool& a_rbOutPressed )
{
if ( m_aiKeystrokes.size() == 0 )
{
return false;
}
a_riOutKey = m_aiKeystrokes.front();
a_rbOutPressed = m_abKeystrokes.front();
m_aiKeystrokes.pop_front();
m_abKeystrokes.pop_front();
debug( "GetKeystroke: %d, %d\n", a_riOutKey, a_rbOutPressed );
return true;
}
struct SGameTimePackage
{
int iGameTime;
int iGamePhase;
};
void CMortalNetworkImpl::SendGameTime( int a_iGameTime, int a_iGamePhase )
{
CHECKCONNECTION;
if ( a_iGameTime == m_iGameTime
&& a_iGamePhase == m_iGamePhase )
{
return; // Nothing to update, the other side already knows.
}
SGameTimePackage oPackage;
m_iGameTime = a_iGameTime;
m_iGamePhase = a_iGamePhase;
oPackage.iGameTime = SDL_SwapBE32( a_iGameTime );
oPackage.iGamePhase = SDL_SwapBE32( a_iGamePhase );
SendRawData( 'T', &oPackage, sizeof(SGameTimePackage) );
}
void CMortalNetworkImpl::ReceiveGameTime( void* a_pData, int a_iLength )
{
if ( a_iLength != sizeof(SGameTimePackage) ) DISCONNECTONCOMMUNICATIONERROR;
SGameTimePackage* poPackage = (SGameTimePackage*) a_pData;
m_iGameTime = SDL_SwapBE32( poPackage->iGameTime );
m_iGamePhase = SDL_SwapBE32( poPackage->iGamePhase );
}
int CMortalNetworkImpl::GetGameTime()
{
return m_iGameTime;
}
int CMortalNetworkImpl::GetGamePhase()
{
return m_iGamePhase;
}
void CMortalNetworkImpl::SendHurryup( int a_iHurryUpCode )
{
CHECKCONNECTION;
int iPackage = SDL_SwapBE32( a_iHurryUpCode );
SendRawData( 'H', &iPackage, sizeof(int) );
}
void CMortalNetworkImpl::ReceiveHurryup( void* a_pData, int a_iLength )
{
if ( a_iLength != sizeof(int) ) DISCONNECTONCOMMUNICATIONERROR;
m_iHurryupCode = SDL_SwapBE32( *((int*)a_pData) );
}
int CMortalNetworkImpl::GetHurryup()
{
int iRetval = m_iHurryupCode;
m_iHurryupCode = -1;
return iRetval;
}
struct SRoundOrder
{
int iWhoWon;
bool bGameOver;
};
void CMortalNetworkImpl::SendRoundOver( int a_iWhoWon, bool a_bGameOver )
{
CHECKCONNECTION;
SRoundOrder oPackage;
oPackage.iWhoWon = a_iWhoWon;
oPackage.bGameOver = a_bGameOver;
SendRawData( 'O', &oPackage, sizeof(SRoundOrder) );
if ( a_bGameOver )
{
m_enState = NS_CHARACTER_SELECTION;
}
}
void CMortalNetworkImpl::ReceiveRoundOver( void* a_pData, int a_iLength )
{
if ( a_iLength != sizeof(SRoundOrder) ) DISCONNECTONCOMMUNICATIONERROR;
SRoundOrder* poPackage = (SRoundOrder*) a_pData;
m_iWhoWon = poPackage->iWhoWon;
m_bGameOver = poPackage->bGameOver;
m_bRoundOver = true;
}
bool CMortalNetworkImpl::IsRoundOver()
{
return m_bRoundOver;
}
bool CMortalNetworkImpl::IsGameOver()
{
return m_bGameOver;
}
int CMortalNetworkImpl::GetWhoWon()
{
return m_iWhoWon;
}
diff --git a/src/PlayerSelect.cpp b/src/PlayerSelect.cpp
index 253243d..a35179f 100644
--- a/src/PlayerSelect.cpp
+++ b/src/PlayerSelect.cpp
@@ -1,702 +1,735 @@
/***************************************************************************
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"
#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() )
{
- m_poTextArea->AddString( g_poNetwork->GetMsg(), C_YELLOW );
+ 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 ( IsNetworkGame() )
+ if ( bNetworkMode )
{
m_iChooserLeft = 158;
- m_iChooserTop = 74;
+ 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( IsNetworkGame() ? "PlayerSelect_chat.png" : "PlayerSelect.png", 111 );
+ SDL_Surface* poBackground = LoadBackground( bNetworkMode ? "PlayerSelect_chat.png" : "PlayerSelect.png", 111 );
- DrawGradientText( "Choose A Fighter Dammit", titleFont, 10, poBackground );
+ 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 ( IsNetworkGame() )
+ 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 ( IsNetworkGame() && g_poNetwork->IsMaster() )
+ 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:350 - 470:470
+ // Chat is 165:318 - 470:470
char acMsg[256];
- sprintf( acMsg, "Press Enter to chat..." );
+ sprintf( acMsg, "Press Enter to chat, Page Up/Page Down to scroll..." );
bool bDoingChat = false;
- if ( IsNetworkGame() )
+ if ( bNetworkMode )
{
m_poReadline = new CReadline( IsNetworkGame() ? poBackground : NULL, impactFont,
acMsg, strlen(acMsg), 256, 15, 465, 610, C_LIGHTCYAN, C_BLACK, 255 );
- m_poTextArea = new CTextArea( poBackground, impactFont, 15, 350, 610, 32*3 );
+ m_poTextArea = new CTextArea( poBackground, impactFont, 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 )
+ {
+ SDLKey enKey = event.key.keysym.sym;
+ if ( IsNetworkGame() )
+ {
+ if ( enKey == SDLK_PAGEUP || enKey == SDLK_KP9 )
+ {
+ m_poTextArea->ScrollUp();
+ continue;
+ }
+ if ( enKey == SDLK_PAGEDOWN || enKey == SDLK_KP3 )
+ {
+ m_poTextArea->ScrollDown();
+ continue;
+ }
+ }
+ }
+
+ // HANDLE CHATTING
if ( bDoingChat )
{
// 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 );
- m_poTextArea->AddString( acMsg, C_WHITE );
+ m_poTextArea->AddString( acMsg, 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
- switch (event.type)
+ if ( event.type == SDL_KEYDOWN )
{
- case SDL_KEYDOWN:
+ SDLKey enKey = event.key.keysym.sym;
+
+ if ( enKey == SDLK_ESCAPE )
{
- if ( event.key.keysym.sym == SDLK_ESCAPE )
- {
- DoMenu( false );
- 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) )
+ DoMenu( false );
+ if ( IsNetworkGame() && g_poNetwork->IsMaster() )
{
- bDoingChat = true;
- acMsg[0] = 0;
- m_poReadline->Clear();
- m_poReadline->Restart( acMsg, strlen(acMsg), 256, C_LIGHTCYAN, C_BLACK, 255 );
- break;
+ g_poNetwork->SendGameParams( g_oState.m_iGameSpeed, g_oState.m_iGameTime, g_oState.m_iHitPoints );
}
- for ( i=0; i<2; i++ )
+ 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 );
+ break;
+ }
+ for ( i=0; i<2; i++ )
+ {
+ for ( j=0; j<9; j++ )
{
- for ( j=0; j<9; j++ )
+ if (g_oState.m_aiPlayerKeys[i][j] == event.key.keysym.sym)
{
- if (g_oState.m_aiPlayerKeys[i][j] == event.key.keysym.sym)
- {
- DrawRect( m_iP1, 240 );
- DrawRect( m_iP2, 240 );
- HandleKey( i, j );
- }
+ DrawRect( m_iP1, 240 );
+ DrawRect( m_iP2, 240 );
+ HandleKey( i, j );
}
}
}
- break;
- } // 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 );
+ 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/TextArea.cpp b/src/TextArea.cpp
index cbff4b0..a440bd3 100644
--- a/src/TextArea.cpp
+++ b/src/TextArea.cpp
@@ -1,75 +1,110 @@
/***************************************************************************
TextArea.cpp - description
-------------------
begin : Wed Jan 28 2004
copyright : (C) 2004 by upi
email : upi@feel
***************************************************************************/
#include "TextArea.h"
#include "sge_surface.h"
#include "sge_tt_text.h"
#include "gfx.h"
#include "common.h"
CTextArea::CTextArea( SDL_Surface* a_poScreen, _sge_TTFont* a_poFont, int a_x, int a_y, int a_w, int a_h )
{
m_poScreen = a_poScreen;
m_poFont = a_poFont;
+ m_iScrollOffset = 0;
m_oClipRect.x = x = a_x;
m_oClipRect.y = y = a_y;
m_oClipRect.w = w = a_w;
m_oClipRect.h = h = a_h;
m_poBackground = sge_copy_surface( a_poScreen, x, y, w, h );
}
CTextArea::~CTextArea()
{
SDL_FreeSurface( m_poBackground );
m_poBackground = NULL;
}
+void CTextArea::Clear()
+{
+ m_aiRowColors.clear();
+ m_asRowTexts.clear();
+ m_iScrollOffset = 0;
+}
+
+
void CTextArea::AddString( const char* a_poText, int a_iColor )
{
m_asRowTexts.push_front( a_poText );
m_aiRowColors.push_front( a_iColor );
debug( "Added '%s', number of texts is %d\n", a_poText, m_asRowTexts.size() );
}
+void CTextArea::ScrollUp()
+{
+ if ( m_iScrollOffset < (int) m_asRowTexts.size() - 1 )
+ {
+ ++m_iScrollOffset;
+ Redraw();
+ }
+}
+
+
+void CTextArea::ScrollDown()
+{
+ if ( m_iScrollOffset > 0 )
+ {
+ --m_iScrollOffset;
+ Redraw();
+ }
+}
+
+
void CTextArea::Redraw()
{
TStringList::const_iterator itString = m_asRowTexts.begin();
TIntList::const_iterator itColors = m_aiRowColors.begin();
+ for ( int i=0; i<m_iScrollOffset; ++i )
+ {
+ ++itString;
+ ++itColors;
+ }
+
SDL_Rect oOldClipRect;
SDL_GetClipRect( m_poScreen, &oOldClipRect );
SDL_SetClipRect( m_poScreen, &m_oClipRect );
sge_Blit( m_poBackground, m_poScreen, 0, 0, x, y, w, h );
for ( int yPos = y + h - sge_TTF_FontHeight( m_poFont );
yPos >= y /*+ sge_TTF_FontAscent( m_poFont )*/;
yPos -= sge_TTF_FontHeight( m_poFont ) )
{
if ( itColors == m_aiRowColors.end() )
{
break;
}
// Print the current text
sge_tt_textout( m_poScreen, m_poFont, itString->c_str(), x, yPos + sge_TTF_FontAscent(m_poFont), *itColors, C_BLACK, 255 );
++itString;
++itColors;
}
sge_UpdateRect( m_poScreen, x, y, w, h );
SDL_SetClipRect( m_poScreen, &oOldClipRect );
}
diff --git a/src/TextArea.h b/src/TextArea.h
index 03814d8..ffcdba4 100644
--- a/src/TextArea.h
+++ b/src/TextArea.h
@@ -1,47 +1,50 @@
/***************************************************************************
TextArea.h - description
-------------------
begin : Wed Jan 28 2004
copyright : (C) 2004 by upi
email : upi@feel
***************************************************************************/
#ifndef TEXTAREA_H
#define TEXTAREA_H
#include "SDL_video.h"
struct SDL_Surface;
struct _sge_TTFont;
#include <string>
#include <list>
typedef std::list<std::string> TStringList;
typedef std::list<int> TIntList;
class CTextArea
{
public:
CTextArea( SDL_Surface* a_poScreen, _sge_TTFont* a_poFont, int a_x, int a_y, int a_w, int a_h );
~CTextArea();
void AddString( const char* a_poText, int a_iColor );
void Redraw();
+ void Clear();
+ void ScrollUp();
+ void ScrollDown();
protected:
SDL_Surface* m_poScreen;
SDL_Surface* m_poBackground;
_sge_TTFont* m_poFont;
SDL_Rect m_oClipRect;
int x, y, w, h;
- int m_iNumRows;
+ int m_iScrollOffset;
TStringList m_asRowTexts;
TIntList m_aiRowColors;
};
#endif // TEXTAREA_H
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Wed, Feb 4, 2:10 PM (2 h, 6 m ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
55617
Default Alt Text
(45 KB)
Attached To
Mode
R76 OpenMortal
Attached
Detach File
Event Timeline
Log In to Comment