xwords/wince/ceginfo.c
ehouse 4939cf1785 Turn on and enable UI for relay and sms transport. relay doensn't
work, at least on win32 where threading code is broken, and former is
completely stubbed out.
2009-01-05 14:13:40 +00:00

747 lines
25 KiB
C
Executable file

/* -*-mode: C; fill-column: 77; c-basic-offset: 4; compile-command: "make TARGET_OS=wince DEBUG=TRUE"; -*- */
/*
* Copyright 2002-2009 by Eric House (xwords@eehouse.org). All rights
* reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdio.h> /* swprintf */
#include "ceginfo.h"
#include "cemain.h"
#include "ceutil.h"
#include "cedict.h"
#include "cecondlg.h"
#include "strutils.h"
#include "cedebug.h"
#include "strutils.h"
#define NUM_COLS 4
#define MENUDICTS_INCR 16
static XP_S16
findInsertPoint( const wchar_t* wPath, wchar_t** menuDicts,
XP_U16 nMenuDicts )
{
XP_S16 loc = 0; /* simple case: nothing here */
if ( nMenuDicts > 0 ) {
wchar_t thisShortBuf[CE_MAX_PATH_LEN+1];
wchar_t* thisShortName = wbname( thisShortBuf, sizeof(thisShortBuf),
wPath );
/* If the short path doesn't already exist, find where it belongs. This
is wasteful if we're doing this a lot since the short path isn't
cached. */
for ( /* loc = 0*/; loc < nMenuDicts; ++loc ) {
wchar_t oneShortBuf[CE_MAX_PATH_LEN+1];
wchar_t* oneShortName = wbname( oneShortBuf, sizeof(oneShortBuf),
menuDicts[loc] );
int diff = _wcsicmp( thisShortName, oneShortName );
if ( diff > 0 ) {
continue;
} else if ( diff == 0 ) {
loc = -1;
}
break;
}
}
return loc;
} /* findInsertPoint */
static XP_Bool
addDictToState( const wchar_t* wPath, XP_U16 XP_UNUSED(index), void* ctxt )
{
GameInfoState* state = (GameInfoState*)ctxt;
/* Let's display only the short form, but save the whole path */
wchar_t* wstr;
XP_U16 len;
XP_S16 loc; /* < 0 means skip it */
loc = findInsertPoint( wPath, state->menuDicts,
state->nMenuDicts );
if ( loc >= 0 ) {
/* make a copy of the long name */
len = wcslen( wPath ) + 1;
wstr = (wchar_t*)XP_MALLOC( state->dlgHdr.globals->mpool,
len * sizeof(wstr[0]) );
XP_MEMCPY( wstr, wPath, len*sizeof(wstr[0]) );
if ( !state->menuDicts ) {
XP_ASSERT( state->nMenuDicts == 0 );
XP_ASSERT( state->capMenuDicts == 0 );
state->capMenuDicts = MENUDICTS_INCR;
state->menuDicts
= (wchar_t**)XP_MALLOC( state->dlgHdr.globals->mpool,
state->capMenuDicts
* sizeof(state->menuDicts[0]) );
} else if ( state->nMenuDicts == state->capMenuDicts ) {
state->capMenuDicts += MENUDICTS_INCR;
state->menuDicts
= (wchar_t**)XP_REALLOC( state->dlgHdr.globals->mpool,
state->menuDicts,
state->capMenuDicts
* sizeof(state->menuDicts[0]) );
}
if ( loc < state->nMenuDicts ) {
XP_MEMMOVE( &state->menuDicts[loc+1], &state->menuDicts[loc],
(state->nMenuDicts - loc)
* sizeof(state->menuDicts[0]) );
}
state->menuDicts[loc] = wstr;
++state->nMenuDicts;
}
return XP_FALSE;
} /* addDictToState */
static void
addDictsToMenu( GameInfoState* state )
{
wchar_t* shortname;
wchar_t shortPath[CE_MAX_PATH_LEN+1];
XP_U16 i, nMenuDicts = state->nMenuDicts;
XP_S16 sel = 0;
CEAppGlobals* globals = state->dlgHdr.globals;
/* insert the short names in the menu */
for ( i = 0; i < nMenuDicts; ++i ) {
wchar_t* wPath = state->menuDicts[i];
shortname = wbname( shortPath, sizeof(shortPath), wPath );
SendDlgItemMessage( state->dlgHdr.hDlg, state->dictListId,
ADDSTRING(globals), 0, (long)shortname );
if ( state->newDictName[0] != 0 && sel == 0 ) {
XP_UCHAR buf[CE_MAX_PATH_LEN+1];
WideCharToMultiByte( CP_ACP, 0, wPath, -1, buf, sizeof(buf),
NULL, NULL );
if ( 0 == XP_STRCMP( buf, state->newDictName ) ) {
sel = i;
}
}
}
SendDlgItemMessage( state->dlgHdr.hDlg, state->dictListId,
SETCURSEL(globals), sel, 0L );
} /* addDictsToMenu */
static void
cleanupGameInfoState( GameInfoState* state )
{
if ( !!state->menuDicts ) {
XP_U16 nMenuDicts = state->nMenuDicts;
XP_U16 i;
for ( i = 0; i < nMenuDicts; ++i ) {
XP_FREE( state->dlgHdr.globals->mpool, state->menuDicts[i] );
}
XP_FREE( state->dlgHdr.globals->mpool, state->menuDicts );
state->menuDicts = NULL;
}
if ( !!state->moveIds ) {
XP_FREE( state->dlgHdr.globals->mpool, state->moveIds );
state->moveIds = NULL;
}
} /* cleanupGameInfoState */
static void
loadFromGameInfo( GameInfoState* state )
{
XP_U16 ii;
CEAppGlobals* globals = state->dlgHdr.globals;
CurGameInfo* gi = &globals->gameInfo;
#ifndef XWFEATURE_STANDALONE_ONLY
wchar_t* roles[] = { L"Standalone", L"Host", L"Guest" };
for ( ii = 0; ii < VSIZE(roles); ++ii ) {
SendDlgItemMessage( state->dlgHdr.hDlg, state->roleComboId,
ADDSTRING(globals), 0, (long)roles[ii] );
}
#endif
for ( ii = 0; ii < MAX_NUM_PLAYERS; ++ii ) {
wchar_t widebuf[8];
/* put a string in the moronic combobox */
swprintf( widebuf, L"%d", ii + 1 );
SendDlgItemMessage( state->dlgHdr.hDlg, state->nPlayersId,
ADDSTRING(globals), 0, (long)widebuf );
}
newg_load( state->newGameCtx, gi );
#ifndef STUBBED_DICT
if ( !!gi->dictName ) {
XP_MEMCPY( state->newDictName, gi->dictName,
(XP_U16)XP_STRLEN(gi->dictName)+1 );
}
if ( state->isNewGame ) {
(void)ceLocateNDicts( globals, CE_MAXDICTS, addDictToState, state );
} else {
wchar_t wPath[CE_MAX_PATH_LEN+1];
XP_ASSERT( gi->dictName[0] != '\0' );
MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, gi->dictName, -1,
wPath, VSIZE(wPath) );
(void)addDictToState( wPath, 0, state );
}
addDictsToMenu( state );
#endif
if ( !state->isNewGame ) {
ceEnOrDisable( state->dlgHdr.hDlg, state->dictListId, XP_FALSE );
}
} /* loadFromGameInfo */
static XP_Bool
stateToGameInfo( GameInfoState* state )
{
CEAppGlobals* globals = state->dlgHdr.globals;
CurGameInfo* gi = &globals->gameInfo;
HWND hDlg = state->dlgHdr.hDlg;
XP_Bool timerOn;
XP_Bool success = newg_store( state->newGameCtx, gi, XP_TRUE );
if ( success ) {
/* dictionary */ {
int sel;
sel = SendDlgItemMessage( hDlg, state->dictListId,
GETCURSEL(globals), 0, 0L );
if ( sel >= 0 ) {
WideCharToMultiByte( CP_ACP, 0, state->menuDicts[sel], -1,
state->newDictName,
sizeof(state->newDictName), NULL, NULL );
}
replaceStringIfDifferent( globals->mpool, &gi->dictName,
state->newDictName );
}
/* timer */
timerOn = ceGetChecked( hDlg, TIMER_CHECK );
gi->timerEnabled = timerOn;
if ( timerOn ) {
XP_UCHAR numBuf[10];
XP_U16 len = sizeof(numBuf);
ceGetDlgItemText( hDlg, TIMER_EDIT, numBuf, &len );
if ( len > 0 ) {
XP_U16 num = atoi( numBuf );
gi->gameSeconds = num * 60;
}
}
/* preferences */
if ( state->prefsChanged ) {
loadCurPrefsFromState( globals, &globals->appPrefs, gi,
&state->prefsPrefs );
}
}
return success;
} /* stateToGameInfo */
static void
raiseForHiddenPlayers( GameInfoState* state, XP_U16 nPlayers )
{
HWND hDlg = state->dlgHdr.hDlg;
XP_U16 ii;
XP_S16 moveY;
if ( nPlayers != state->prevNPlayers ) {
if ( !state->moveIds ) {
XP_S16 ids[32];
HWND child;
RECT rect;
XP_U16 playersBottom;
ceGetItemRect( hDlg, NAME_EDIT4, &rect );
playersBottom = rect.bottom;
ceGetItemRect( hDlg, NAME_EDIT3, &rect );
state->playersSpacing = playersBottom - rect.bottom;
for ( child = GetWindow( hDlg, GW_CHILD ), ii = 0;
!!child;
child = GetWindow( child, GW_HWNDNEXT ) ) {
XP_S16 resID = GetDlgCtrlID( child );
if ( resID > 0 ) {
ceGetItemRect( hDlg, resID, &rect );
if ( rect.top > playersBottom ) {
XP_ASSERT( ii < VSIZE(ids)-1 );
ids[ii] = resID;
++ii;
}
}
}
state->moveIds = XP_MALLOC( state->dlgHdr.globals->mpool,
sizeof(state->moveIds[0]) * ii );
XP_MEMCPY( state->moveIds, ids,
sizeof(state->moveIds[0]) * ii );
state->nMoveIds = ii;
}
moveY = state->playersSpacing * (nPlayers - state->prevNPlayers);
for ( ii = 0; ii < state->nMoveIds; ++ii ) {
ceMoveItem( hDlg, state->moveIds[ii], 0, moveY );
}
state->prevNPlayers = nPlayers;
#ifdef _WIN32_WCE
if ( IS_SMARTPHONE(state->dlgHdr.globals) ) {
SendMessage( hDlg, DM_RESETSCROLL, (WPARAM)FALSE, (LPARAM)TRUE );
}
#endif
}
}
static void
handlePrefsButton( HWND hDlg, CEAppGlobals* globals, GameInfoState* state )
{
CePrefsDlgState prefsState;
/* need to keep my stuff in a temporary place and to read back out of it
if launched a second time before the user's cancelled or not out of
the calling dlg.*/
if ( WrapPrefsDialog( hDlg, globals, &prefsState, &state->prefsPrefs,
state->isNewGame ) ) {
state->prefsChanged = XP_TRUE;
state->colorsChanged = prefsState.colorsChanged;
/* nothing to do until user finally does confirm the parent dialog */
}
} /* handlePrefsButton */
#ifndef XWFEATURE_STANDALONE_ONLY
static void
handleConnOptionsButton( HWND hDlg, CEAppGlobals* globals,
DeviceRole role, GameInfoState* state )
{
if ( role == SERVER_STANDALONE ) {
NGValue value;
role = (DeviceRole)SendDlgItemMessage( hDlg,
state->roleComboId,
GETCURSEL(globals), 0,
0L);
value.ng_role = role;
newg_attrChanged( state->newGameCtx, NG_ATTR_ROLE, value );
}
if ( role != state->lastRole ) {
state->lastRole = role;
if ( role != SERVER_STANDALONE) {
if ( WrapConnsDlg( hDlg, globals, &state->prefsPrefs.addrRec,
&state->prefsPrefs.addrRec, role ) ) {
state->addrChanged = XP_TRUE;
}
}
}
}
#endif
static XP_U16
resIDForCol( XP_U16 player, NewGameColumn col )
{
XP_U16 resID = 0;
switch ( col ) {
#ifndef XWFEATURE_STANDALONE_ONLY
case NG_COL_REMOTE:
resID = REMOTE_CHECK1;
break;
#endif
case NG_COL_ROBOT:
resID = ROBOT_CHECK1;
break;
case NG_COL_NAME:
resID = NAME_EDIT1;
break;
case NG_COL_PASSWD:
resID = PASS_EDIT1;
break;
}
XP_ASSERT( resID != 0 );
return resID + ( player * NUM_COLS );
} /* resIDForCol */
static XP_U16
resIDForAttr( GameInfoState* state, NewGameAttr attr )
{
XP_U16 resID = 0;
switch( attr ) {
case NG_ATTR_NPLAYERS:
resID = state->nPlayersId;
break;
#ifndef XWFEATURE_STANDALONE_ONLY
case NG_ATTR_ROLE:
resID = state->roleComboId;
break;
case NG_ATTR_REMHEADER:
resID = IDC_REMOTE_LABEL;
break;
#endif
case NG_ATTR_NPLAYHEADER:
resID = IDC_TOTAL_LABEL;
break;
case NG_ATTR_CANJUGGLE:
resID = GIJUGGLE_BUTTON;
break;
default:
break;
}
XP_ASSERT( resID != 0 );
return resID;
} /* resIDForAttr */
static void
doForNWEnable( HWND hDlg, XP_U16 resID, XP_TriEnable enable )
{
XP_Bool makeVisible = enable != TRI_ENAB_HIDDEN;
ceShowOrHide( hDlg, resID, makeVisible );
if ( makeVisible ) {
ceEnOrDisable( hDlg, resID, enable == TRI_ENAB_ENABLED );
}
} /* doForNWEnable */
static void
ceEnableColProc( void* closure, XP_U16 player, NewGameColumn col,
XP_TriEnable enable )
{
GameInfoState* state = (GameInfoState*)closure;
XP_U16 resID = resIDForCol( player, col );
doForNWEnable( state->dlgHdr.hDlg, resID, enable );
}
static void
ceEnableAttrProc( void* closure, NewGameAttr attr, XP_TriEnable enable )
{
GameInfoState* state = (GameInfoState*)closure;
XP_U16 resID = resIDForAttr( state, attr );
doForNWEnable( state->dlgHdr.hDlg, resID, enable );
} /* ceEnableAttrProc */
static void
ceGetColProc( void* closure, XP_U16 player, NewGameColumn col,
NgCpCallbk cpcb, const void* cpClosure )
{
NGValue value;
GameInfoState* state = (GameInfoState*)closure;
XP_U16 resID = resIDForCol( player, col );
XP_UCHAR txt[128];
XP_U16 len;
switch ( col ) {
#ifndef XWFEATURE_STANDALONE_ONLY
case NG_COL_REMOTE:
#endif
case NG_COL_ROBOT:
value.ng_bool = ceGetChecked( state->dlgHdr.hDlg, resID );
break;
case NG_COL_NAME:
case NG_COL_PASSWD:
len = sizeof(txt);
ceGetDlgItemText( state->dlgHdr.hDlg, resID, txt, &len );
value.ng_cp = &txt[0];
break;
default:
XP_ASSERT(0);
}
(*cpcb)( value, cpClosure );
} /* ceGetColProc */
static void
ceSetColProc( void* closure, XP_U16 player, NewGameColumn col,
const NGValue value )
{
GameInfoState* state = (GameInfoState*)closure;
XP_U16 resID = resIDForCol( player, col );
const XP_UCHAR* cp;
XP_UCHAR buf[16];
switch( col ) {
case NG_COL_PASSWD:
case NG_COL_NAME:
if ( NULL != value.ng_cp ) {
cp = value.ng_cp;
} else if ( col == NG_COL_NAME ) {
snprintf( buf, sizeof(buf), "Player %d", player + 1 );
cp = buf;
} else {
cp = "";
}
ceSetDlgItemText( state->dlgHdr.hDlg, resID, cp );
break;
#ifndef XWFEATURE_STANDALONE_ONLY
case NG_COL_REMOTE:
#endif
case NG_COL_ROBOT:
ceSetChecked( state->dlgHdr.hDlg, resID, value.ng_bool );
break;
default:
XP_ASSERT(0);
}
} /* ceSetColProc */
static void
ceSetAttrProc(void* closure, NewGameAttr attr, const NGValue value )
{
GameInfoState* state = (GameInfoState*)closure;
XP_U16 resID = resIDForAttr( state, attr );
CEAppGlobals* globals = state->dlgHdr.globals;
switch ( attr ) {
case NG_ATTR_NPLAYERS:
SendDlgItemMessage( state->dlgHdr.hDlg, resID,
SETCURSEL(globals),
value.ng_u16 - 1, 0L );
raiseForHiddenPlayers( state, value.ng_u16 );
break;
#ifndef XWFEATURE_STANDALONE_ONLY
case NG_ATTR_ROLE:
SendDlgItemMessage( state->dlgHdr.hDlg, resID, SETCURSEL(globals),
value.ng_role, 0L );
break;
#endif
case NG_ATTR_NPLAYHEADER:
ceSetDlgItemText( state->dlgHdr.hDlg, resID, value.ng_cp );
break;
default:
break;
}
} /* ceSetAttrProc */
static XP_U16
playerFromID( XP_U16 id, XP_U16 base )
{
XP_U16 player;
player = (id - base) / NUM_COLS;
return player;
}
static void
handleColChecked( GameInfoState* state, XP_U16 id, XP_U16 base )
{
NGValue value;
XP_U16 player = playerFromID( id, base );
value.ng_bool = ceGetChecked( state->dlgHdr.hDlg, id );
newg_colChanged( state->newGameCtx, player );
}
/* It's too much work at this point to get the icon button looking good,
* e.g. properly greyed-out when disabled. So I'm sticking with the "J".
* Here's the code to start with if I get more ambitious. Remember: the
* GIJUGGLE_BUTTON needs to have the BS_OWNERDRAW attribute for this to work.
*/
#ifdef OWNERDRAW_JUGGLE
static void
ceDrawIconButton( CEAppGlobals* globals, DRAWITEMSTRUCT* dis )
{
HBITMAP bmp = LoadBitmap( globals->hInst,
MAKEINTRESOURCE(IDB_JUGGLEBUTTON) );
if ( !!bmp ) {
ceDrawBitmapInRect( dis->hDC, &dis->rcItem, bmp );
DeleteObject( bmp );
}
} /* ceDrawColorButton */
#endif
static void
checkUpdateCombo( GameInfoState* state, XP_U16 id )
{
HWND hDlg = state->dlgHdr.hDlg;
if ( id == state->nPlayersId ) {
if ( state->isNewGame ) { /* ignore if in info mode */
XP_S16 sel;
XP_U16 nPlayers;
NGValue value;
sel = SendDlgItemMessage( hDlg, id,
GETCURSEL(state->dlgHdr.globals), 0, 0L);
nPlayers = 1 + sel;
value.ng_u16 = nPlayers;
XP_ASSERT( !!state->newGameCtx );
newg_attrChanged( state->newGameCtx,
NG_ATTR_NPLAYERS, value );
raiseForHiddenPlayers( state, nPlayers );
}
} else if ( id == state->roleComboId ) {
XP_ASSERT( SERVER_STANDALONE == 0 );
handleConnOptionsButton( hDlg, state->dlgHdr.globals,
SERVER_STANDALONE, state );
}
} /* checkUpdateCombo */
LRESULT CALLBACK
GameInfo(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
CEAppGlobals* globals;
XP_U16 id;
GameInfoState* state;
LRESULT result = FALSE;
/* XP_LOGF( "%s: %s(%d)", __func__, messageToStr( message ), message ); */
if ( message == WM_INITDIALOG ) {
SetWindowLongPtr( hDlg, GWL_USERDATA, lParam );
state = (GameInfoState*)lParam;
globals = state->dlgHdr.globals;
state->nPlayersId = LB_IF_PPC(globals,IDC_NPLAYERSCOMBO);
#ifndef XWFEATURE_STANDALONE_ONLY
state->roleComboId = LB_IF_PPC(globals, IDC_ROLECOMBO);
#endif
state->dictListId = LB_IF_PPC(globals,IDC_DICTLIST);
state->prevNPlayers = MAX_NUM_PLAYERS;
ceDlgSetup( &state->dlgHdr, hDlg, DLG_STATE_TRAPBACK );
#ifndef XWFEATURE_STANDALONE_ONLY
ceDlgComboShowHide( &state->dlgHdr, IDC_ROLECOMBO );
#endif
ceDlgComboShowHide( &state->dlgHdr, IDC_NPLAYERSCOMBO );
ceDlgComboShowHide( &state->dlgHdr, IDC_DICTLIST );
state->newGameCtx = newg_make( MPPARM(globals->mpool)
state->isNewGame,
&globals->util,
ceEnableColProc,
ceEnableAttrProc,
ceGetColProc,
ceSetColProc,
ceSetAttrProc,
state );
loadFromGameInfo( state );
loadStateFromCurPrefs( globals, &globals->appPrefs, &globals->gameInfo,
&state->prefsPrefs );
if ( state->isNewGame ) {
(void)SetWindowText( hDlg, L"New game" );
}
result = TRUE;
} else {
state = (GameInfoState*)GetWindowLongPtr( hDlg, GWL_USERDATA );
if ( !!state ) {
globals = state->dlgHdr.globals;
XP_ASSERT( hDlg == state->dlgHdr.hDlg );
result = ceDoDlgHandle( &state->dlgHdr, message, wParam, lParam );
if ( !result ) {
switch (message) {
#ifdef OWNERDRAW_JUGGLE
case WM_DRAWITEM: /* for BS_OWNERDRAW style */
ceDrawIconButton( globals, (DRAWITEMSTRUCT*)lParam );
result = TRUE;
break;
#endif
case WM_NOTIFY:
if ( !!state->newGameCtx ) {
checkUpdateCombo( state, LOWORD(wParam)-1 );
}
break;
case WM_COMMAND:
result = TRUE;
id = LOWORD(wParam);
if ( id == state->nPlayersId
#ifndef XWFEATURE_STANDALONE_ONLY
|| id == state->roleComboId
#endif
) {
if ( HIWORD(wParam) == CBN_SELCHANGE ) {
checkUpdateCombo( state, id );
}
} else {
switch( id ) {
case ROBOT_CHECK1:
case ROBOT_CHECK2:
case ROBOT_CHECK3:
case ROBOT_CHECK4:
handleColChecked( state, id, ROBOT_CHECK1 );
break;
#ifndef XWFEATURE_STANDALONE_ONLY
case REMOTE_CHECK1:
case REMOTE_CHECK2:
case REMOTE_CHECK3:
case REMOTE_CHECK4:
handleColChecked( state, id, REMOTE_CHECK1 );
break;
case IDC_ROLECOMBO:
case IDC_ROLECOMBO_PPC:
if ( HIWORD(wParam) == CBN_SELCHANGE ) {
if ( state->isNewGame ) { /* ignore if in info
mode */
/* If we've switched to a state where we'll be
connecting */
handleConnOptionsButton( hDlg, globals,
SERVER_STANDALONE,
state );
}
}
break;
#endif
case GIJUGGLE_BUTTON:
XP_ASSERT( state->isNewGame );
/* Juggle vs switch. On Win32, updates are
coalesced so you don't see anything on screen
if you change a field then change it back. In
terms of messages, all we see here is a
WM_CTLCOLOREDIT for each field being changed.
If I post a custom event here, it comes in
*before* the WM_CTLCOLOREDIT events. Short of
a timer, which starts a race with the user, I
see no way to get notified after the drawing's
done. So for now, we switch rather than
juggle: call juggle until something actually
happens. */
while ( !newg_juggle( state->newGameCtx ) ) {
}
break;
case OPTIONS_BUTTON:
handlePrefsButton( hDlg, globals, state );
break;
case IDOK:
if ( !stateToGameInfo( state ) ) {
break;
}
case IDCANCEL:
EndDialog(hDlg, id);
state->userCancelled = id == IDCANCEL;
cleanupGameInfoState( state );
newg_destroy( state->newGameCtx );
state->newGameCtx = NULL;
}
break;
default:
result = FALSE;
}
}
}
}
}
return result;
} /* GameInfo */