2009-02-28 20:25:46 +01:00
|
|
|
/* -*- compile-command: "cd ../linux && make MEMDEBUG=TRUE"; -*- */
|
2006-06-07 03:26:04 +02:00
|
|
|
/*
|
2009-02-28 20:25:46 +01:00
|
|
|
* Copyright 1997 - 2009 by Eric House (xwords@eehouse.org). All rights
|
2006-06-07 03:26:04 +02:00
|
|
|
* 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 "nwgamest.h"
|
2006-06-07 03:45:03 +02:00
|
|
|
#include "strutils.h"
|
2006-06-10 07:45:53 +02:00
|
|
|
#include "LocalizedStrIncludes.h"
|
2006-06-07 03:26:04 +02:00
|
|
|
|
|
|
|
#ifdef CPLUS
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
|
|
|
|
2006-06-11 22:12:20 +02:00
|
|
|
#define NG_NUM_COLS ((XP_U16)(NG_COL_PASSWD+1))
|
|
|
|
|
2006-06-07 03:26:04 +02:00
|
|
|
struct NewGameCtx {
|
|
|
|
NewGameEnableColProc enableColProc;
|
|
|
|
NewGameEnableAttrProc enableAttrProc;
|
|
|
|
NewGameSetColProc setColProc;
|
|
|
|
NewGameGetColProc getColProc;
|
|
|
|
NewGameSetAttrProc setAttrProc;
|
2006-06-10 07:45:53 +02:00
|
|
|
XW_UtilCtxt* util;
|
2006-06-07 03:26:04 +02:00
|
|
|
void* closure;
|
|
|
|
|
|
|
|
/* Palm needs to store cleartext passwords separately in order to
|
|
|
|
store '***' in the visible field */
|
2006-10-28 15:21:32 +02:00
|
|
|
XP_TriEnable enabled[NG_NUM_COLS][MAX_NUM_PLAYERS];
|
2007-02-02 09:15:07 +01:00
|
|
|
XP_U16 nPlayersShown; /* real nPlayers lives in gi */
|
|
|
|
XP_U16 nPlayersTotal; /* used only until changedNPlayers set */
|
2008-08-27 14:09:30 +02:00
|
|
|
XP_U16 nLocalPlayers; /* not changed except in newg_load */
|
2007-02-02 09:34:37 +01:00
|
|
|
DeviceRole role;
|
2006-06-07 03:26:04 +02:00
|
|
|
XP_Bool isNewGame;
|
2007-02-02 09:15:07 +01:00
|
|
|
XP_Bool changedNPlayers;
|
2006-10-28 15:21:32 +02:00
|
|
|
XP_TriEnable juggleEnabled;
|
2009-03-08 20:54:14 +01:00
|
|
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
|
|
|
XP_TriEnable settingsEnabled;
|
|
|
|
#endif
|
2006-06-07 03:26:04 +02:00
|
|
|
|
|
|
|
MPSLOT
|
|
|
|
};
|
|
|
|
|
|
|
|
static void enableOne( NewGameCtx* ngc, XP_U16 player, NewGameColumn col,
|
2006-10-28 15:21:32 +02:00
|
|
|
XP_TriEnable enable, XP_Bool force );
|
2006-06-07 03:26:04 +02:00
|
|
|
static void adjustAllRows( NewGameCtx* ngc, XP_Bool force );
|
|
|
|
static void adjustOneRow( NewGameCtx* ngc, XP_U16 player, XP_Bool force );
|
2006-06-10 07:45:53 +02:00
|
|
|
static void setRoleStrings( NewGameCtx* ngc );
|
2009-03-08 20:54:14 +01:00
|
|
|
static void considerEnable( NewGameCtx* ngc );
|
2006-06-24 03:20:44 +02:00
|
|
|
static void storePlayer( NewGameCtx* ngc, XP_U16 player, LocalPlayer* lp );
|
|
|
|
static void loadPlayer( NewGameCtx* ngc, XP_U16 player,
|
|
|
|
const LocalPlayer* lp );
|
2008-01-19 17:04:48 +01:00
|
|
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
2008-08-27 14:09:30 +02:00
|
|
|
static XP_Bool changeRole( NewGameCtx* ngc, DeviceRole role );
|
2008-01-04 15:47:52 +01:00
|
|
|
static XP_Bool checkConsistent( NewGameCtx* ngc, XP_Bool warnUser );
|
2008-01-19 17:04:48 +01:00
|
|
|
#else
|
|
|
|
# define checkConsistent( ngc, warnUser ) XP_TRUE
|
|
|
|
#endif
|
2006-06-07 03:26:04 +02:00
|
|
|
|
|
|
|
NewGameCtx*
|
2006-06-07 03:45:03 +02:00
|
|
|
newg_make( MPFORMAL XP_Bool isNewGame,
|
2006-06-10 07:45:53 +02:00
|
|
|
XW_UtilCtxt* util,
|
2006-06-07 03:45:03 +02:00
|
|
|
NewGameEnableColProc enableColProc,
|
|
|
|
NewGameEnableAttrProc enableAttrProc,
|
|
|
|
NewGameGetColProc getColProc, NewGameSetColProc setColProc,
|
|
|
|
NewGameSetAttrProc setAttrProc, void* closure )
|
2006-06-07 03:26:04 +02:00
|
|
|
{
|
|
|
|
NewGameCtx* result = XP_MALLOC( mpool, sizeof(*result) );
|
|
|
|
XP_MEMSET( result, 0, sizeof(*result) );
|
|
|
|
|
|
|
|
result->enableColProc = enableColProc;
|
|
|
|
result->enableAttrProc = enableAttrProc;
|
|
|
|
result->setColProc = setColProc;
|
|
|
|
result->getColProc = getColProc;
|
|
|
|
result->setAttrProc = setAttrProc;
|
|
|
|
result->closure = closure;
|
|
|
|
result->isNewGame = isNewGame;
|
2006-06-10 07:45:53 +02:00
|
|
|
result->util = util;
|
2006-06-07 03:26:04 +02:00
|
|
|
MPASSIGN(result->mpool, mpool);
|
|
|
|
|
|
|
|
return result;
|
2006-06-07 03:45:03 +02:00
|
|
|
} /* newg_make */
|
2006-06-07 03:26:04 +02:00
|
|
|
|
|
|
|
void
|
2006-06-07 03:45:03 +02:00
|
|
|
newg_destroy( NewGameCtx* ngc )
|
2006-06-07 03:26:04 +02:00
|
|
|
{
|
2006-06-10 07:45:53 +02:00
|
|
|
XP_FREE( ngc->mpool, ngc );
|
2006-06-07 03:45:03 +02:00
|
|
|
} /* newg_destroy */
|
2006-06-07 03:26:04 +02:00
|
|
|
|
|
|
|
void
|
2006-06-07 03:45:03 +02:00
|
|
|
newg_load( NewGameCtx* ngc, const CurGameInfo* gi )
|
2006-06-07 03:26:04 +02:00
|
|
|
{
|
|
|
|
void* closure = ngc->closure;
|
2006-06-08 03:26:18 +02:00
|
|
|
NGValue value;
|
2007-02-02 09:15:07 +01:00
|
|
|
XP_U16 nPlayers, nLoaded;
|
|
|
|
XP_S16 ii, jj;
|
2007-02-02 09:34:37 +01:00
|
|
|
DeviceRole role;
|
2006-09-15 09:36:51 +02:00
|
|
|
XP_Bool localOnly;
|
2011-04-13 07:17:45 +02:00
|
|
|
XP_Bool shown[MAX_NUM_PLAYERS] = { XP_FALSE };
|
2006-06-07 03:26:04 +02:00
|
|
|
|
2007-02-02 09:15:07 +01:00
|
|
|
ngc->juggleEnabled = TRI_ENAB_NONE;
|
2009-03-08 20:54:14 +01:00
|
|
|
ngc->settingsEnabled = TRI_ENAB_NONE;
|
2007-02-02 09:15:07 +01:00
|
|
|
for ( ii = 0; ii < NG_NUM_COLS; ++ii ) {
|
|
|
|
for ( jj = 0; jj < MAX_NUM_PLAYERS; ++jj ) {
|
|
|
|
ngc->enabled[ii][jj] = TRI_ENAB_NONE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-09-15 09:36:51 +02:00
|
|
|
ngc->role = role = gi->serverRole;
|
2009-10-24 16:50:23 +02:00
|
|
|
localOnly = (role == SERVER_ISCLIENT) && ngc->isNewGame;
|
2006-06-08 03:51:34 +02:00
|
|
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
2006-09-15 09:36:51 +02:00
|
|
|
value.ng_role = role;
|
2006-06-08 03:26:18 +02:00
|
|
|
(*ngc->setAttrProc)( closure, NG_ATTR_ROLE, value );
|
2006-06-10 07:45:53 +02:00
|
|
|
(*ngc->enableAttrProc)( closure, NG_ATTR_ROLE, ngc->isNewGame?
|
2006-10-28 15:21:32 +02:00
|
|
|
TRI_ENAB_ENABLED : TRI_ENAB_DISABLED );
|
2006-06-08 03:51:34 +02:00
|
|
|
#endif
|
2006-09-15 09:36:51 +02:00
|
|
|
|
|
|
|
nPlayers = gi->nPlayers;
|
2007-02-02 09:15:07 +01:00
|
|
|
ngc->nPlayersTotal = nPlayers;
|
2006-09-15 09:36:51 +02:00
|
|
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
2007-02-02 09:15:07 +01:00
|
|
|
for ( ii = nPlayers - 1; ii >= 0; --ii ) {
|
|
|
|
if ( gi->players[ii].isLocal ) {
|
|
|
|
++ngc->nLocalPlayers;
|
2006-09-15 09:36:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2007-02-02 09:15:07 +01:00
|
|
|
if ( localOnly ) {
|
|
|
|
nPlayers = ngc->nLocalPlayers;
|
|
|
|
}
|
|
|
|
ngc->nPlayersShown = nPlayers;
|
|
|
|
|
|
|
|
value.ng_u16 = ngc->nPlayersShown;
|
2006-09-15 09:36:51 +02:00
|
|
|
(*ngc->setAttrProc)( closure, NG_ATTR_NPLAYERS, value );
|
|
|
|
(*ngc->enableAttrProc)( closure, NG_ATTR_NPLAYERS, ngc->isNewGame?
|
2006-10-28 15:21:32 +02:00
|
|
|
TRI_ENAB_ENABLED : TRI_ENAB_DISABLED );
|
2006-09-15 09:36:51 +02:00
|
|
|
|
2006-06-10 07:45:53 +02:00
|
|
|
setRoleStrings( ngc );
|
2009-03-08 20:54:14 +01:00
|
|
|
considerEnable( ngc );
|
2006-06-07 03:26:04 +02:00
|
|
|
|
2006-09-15 09:36:51 +02:00
|
|
|
/* Load local players first */
|
2007-02-02 09:15:07 +01:00
|
|
|
nLoaded = 0;
|
2006-09-15 09:36:51 +02:00
|
|
|
do {
|
2007-02-02 09:15:07 +01:00
|
|
|
for ( ii = 0; ii < MAX_NUM_PLAYERS; ++ii ) {
|
|
|
|
if ( !shown[ii] ) {
|
|
|
|
const LocalPlayer* lp = &gi->players[ii];
|
|
|
|
if ( !localOnly
|
|
|
|
|| (lp->isLocal && (nLoaded < ngc->nLocalPlayers)) ) {
|
|
|
|
shown[ii] = XP_TRUE;
|
|
|
|
loadPlayer( ngc, nLoaded++, lp );
|
|
|
|
}
|
|
|
|
}
|
2006-09-15 09:36:51 +02:00
|
|
|
}
|
2007-02-02 09:15:07 +01:00
|
|
|
XP_ASSERT( localOnly || nLoaded == MAX_NUM_PLAYERS );
|
2006-09-15 09:36:51 +02:00
|
|
|
localOnly = XP_FALSE; /* for second pass */
|
2007-02-02 09:15:07 +01:00
|
|
|
} while ( nLoaded < MAX_NUM_PLAYERS );
|
2006-06-07 03:26:04 +02:00
|
|
|
|
|
|
|
adjustAllRows( ngc, XP_TRUE );
|
2006-06-07 03:45:03 +02:00
|
|
|
} /* newg_load */
|
|
|
|
|
|
|
|
typedef struct NGCopyClosure {
|
|
|
|
XP_U16 player;
|
|
|
|
NewGameColumn col;
|
|
|
|
NewGameCtx* ngc;
|
2006-06-24 03:20:44 +02:00
|
|
|
LocalPlayer* lp;
|
2006-06-07 03:45:03 +02:00
|
|
|
} NGCopyClosure;
|
|
|
|
|
|
|
|
static void
|
2006-06-24 03:20:44 +02:00
|
|
|
cpToLP( NGValue value, const void* cbClosure )
|
2006-06-07 03:45:03 +02:00
|
|
|
{
|
|
|
|
NGCopyClosure* cpcl = (NGCopyClosure*)cbClosure;
|
2006-06-24 03:20:44 +02:00
|
|
|
LocalPlayer* lp = cpcl->lp;
|
2006-06-07 03:45:03 +02:00
|
|
|
XP_UCHAR** strAddr = NULL;
|
|
|
|
|
|
|
|
switch ( cpcl->col ) {
|
|
|
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
2006-06-08 03:26:18 +02:00
|
|
|
case NG_COL_REMOTE:
|
2006-06-24 03:20:44 +02:00
|
|
|
lp->isLocal = !value.ng_bool;
|
2006-06-07 03:45:03 +02:00
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
case NG_COL_NAME:
|
2006-06-24 03:20:44 +02:00
|
|
|
strAddr = &lp->name;
|
2006-06-07 03:45:03 +02:00
|
|
|
break;
|
|
|
|
case NG_COL_PASSWD:
|
2006-06-24 03:20:44 +02:00
|
|
|
strAddr = &lp->password;
|
2006-06-07 03:45:03 +02:00
|
|
|
break;
|
|
|
|
case NG_COL_ROBOT:
|
2011-01-10 15:44:28 +01:00
|
|
|
lp->robotIQ = value.ng_bool ? 1 : 0;
|
2006-06-07 03:45:03 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !!strAddr ) {
|
2006-09-15 09:36:51 +02:00
|
|
|
/* This is leaking!!! But doesn't leak if am playing via IR, at least
|
|
|
|
in the simulator. */
|
|
|
|
replaceStringIfDifferent( cpcl->ngc->mpool, strAddr,
|
2006-06-07 03:45:03 +02:00
|
|
|
value.ng_cp );
|
|
|
|
}
|
2006-06-24 03:20:44 +02:00
|
|
|
} /* cpToLP */
|
2006-06-07 03:26:04 +02:00
|
|
|
|
2008-01-04 15:47:52 +01:00
|
|
|
XP_Bool
|
2008-02-16 17:02:49 +01:00
|
|
|
newg_store( NewGameCtx* ngc, CurGameInfo* gi,
|
|
|
|
XP_Bool XP_UNUSED_STANDALONE(warn) )
|
2006-06-07 03:26:04 +02:00
|
|
|
{
|
2006-06-24 03:20:44 +02:00
|
|
|
XP_U16 player;
|
2008-01-04 15:47:52 +01:00
|
|
|
XP_Bool consistent = checkConsistent( ngc, warn );
|
2006-06-07 03:26:04 +02:00
|
|
|
|
2008-01-04 15:47:52 +01:00
|
|
|
if ( consistent ) {
|
2009-02-28 20:25:46 +01:00
|
|
|
XP_Bool makeLocal = XP_FALSE;
|
2008-01-04 15:47:52 +01:00
|
|
|
gi->nPlayers = ngc->nPlayersShown;
|
2006-06-08 03:51:34 +02:00
|
|
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
2008-01-04 15:47:52 +01:00
|
|
|
gi->serverRole = ngc->role;
|
2009-02-28 20:25:46 +01:00
|
|
|
makeLocal = ngc->role != SERVER_ISSERVER;
|
2006-06-08 03:51:34 +02:00
|
|
|
#endif
|
2006-06-07 03:26:04 +02:00
|
|
|
|
2008-01-04 15:47:52 +01:00
|
|
|
for ( player = 0; player < MAX_NUM_PLAYERS; ++player ) {
|
|
|
|
storePlayer( ngc, player, &gi->players[player] );
|
2009-02-28 20:25:46 +01:00
|
|
|
if ( makeLocal ) {
|
|
|
|
gi->players[player].isLocal = XP_TRUE;
|
|
|
|
}
|
2008-01-04 15:47:52 +01:00
|
|
|
}
|
2006-06-07 03:26:04 +02:00
|
|
|
}
|
2008-01-04 15:47:52 +01:00
|
|
|
return consistent;
|
2006-06-07 03:45:03 +02:00
|
|
|
} /* newg_store */
|
2006-06-07 03:26:04 +02:00
|
|
|
|
|
|
|
void
|
2006-08-16 15:44:44 +02:00
|
|
|
newg_colChanged( NewGameCtx* ngc, XP_U16 player )
|
2006-06-07 03:26:04 +02:00
|
|
|
{
|
2006-06-08 03:26:18 +02:00
|
|
|
/* Sometimes we'll get this notification for inactive rows, e.g. when
|
|
|
|
setting default values. */
|
2007-02-02 09:15:07 +01:00
|
|
|
if ( player < ngc->nPlayersShown ) {
|
2006-06-08 03:26:18 +02:00
|
|
|
adjustOneRow( ngc, player, XP_FALSE );
|
|
|
|
}
|
2006-06-07 03:26:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2006-06-07 03:45:03 +02:00
|
|
|
newg_attrChanged( NewGameCtx* ngc, NewGameAttr attr, NGValue value )
|
2006-06-07 03:26:04 +02:00
|
|
|
{
|
2008-08-27 14:09:30 +02:00
|
|
|
XP_Bool changed = XP_FALSE;
|
2006-06-07 03:26:04 +02:00
|
|
|
if ( attr == NG_ATTR_NPLAYERS ) {
|
2007-02-02 09:15:07 +01:00
|
|
|
if ( ngc->nPlayersShown != value.ng_u16 ) {
|
|
|
|
ngc->nPlayersShown = value.ng_u16;
|
|
|
|
ngc->changedNPlayers = XP_TRUE;
|
2008-08-27 14:09:30 +02:00
|
|
|
changed = XP_TRUE;
|
2007-02-02 09:15:07 +01:00
|
|
|
}
|
2006-06-08 03:51:34 +02:00
|
|
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
2006-06-07 03:26:04 +02:00
|
|
|
} else if ( NG_ATTR_ROLE == attr ) {
|
2008-08-27 14:09:30 +02:00
|
|
|
changed = changeRole( ngc, value.ng_role );
|
2006-06-08 03:51:34 +02:00
|
|
|
#endif
|
2006-06-07 03:26:04 +02:00
|
|
|
} else {
|
|
|
|
XP_ASSERT( 0 );
|
|
|
|
}
|
2008-08-27 14:09:30 +02:00
|
|
|
|
|
|
|
if ( changed ) {
|
2009-03-08 20:54:14 +01:00
|
|
|
considerEnable( ngc );
|
2008-08-27 14:09:30 +02:00
|
|
|
adjustAllRows( ngc, XP_FALSE );
|
|
|
|
}
|
2006-06-07 03:26:04 +02:00
|
|
|
}
|
|
|
|
|
2006-06-07 03:45:03 +02:00
|
|
|
typedef struct DeepValue {
|
|
|
|
NGValue value;
|
|
|
|
NewGameColumn col;
|
|
|
|
MPSLOT
|
|
|
|
} DeepValue;
|
|
|
|
|
|
|
|
static void
|
|
|
|
deepCopy( NGValue value, const void* closure )
|
|
|
|
{
|
|
|
|
DeepValue* dvp = (DeepValue*)closure;
|
|
|
|
switch ( dvp->col ) {
|
|
|
|
case NG_COL_ROBOT:
|
2006-06-08 03:51:34 +02:00
|
|
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
2006-06-08 03:26:18 +02:00
|
|
|
case NG_COL_REMOTE:
|
2006-06-08 03:51:34 +02:00
|
|
|
#endif
|
2006-06-07 03:45:03 +02:00
|
|
|
dvp->value.ng_bool = value.ng_bool;
|
|
|
|
break;
|
|
|
|
case NG_COL_NAME:
|
|
|
|
case NG_COL_PASSWD:
|
2006-09-15 09:36:51 +02:00
|
|
|
dvp->value.ng_cp = copyString( dvp->mpool, value.ng_cp );
|
2006-06-07 03:45:03 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-06-29 05:38:25 +02:00
|
|
|
XP_Bool
|
2006-06-07 03:45:03 +02:00
|
|
|
newg_juggle( NewGameCtx* ngc )
|
|
|
|
{
|
2006-06-29 05:38:25 +02:00
|
|
|
XP_Bool changed = XP_FALSE;
|
2007-02-02 09:15:07 +01:00
|
|
|
XP_U16 nPlayers = ngc->nPlayersShown;
|
|
|
|
|
|
|
|
XP_ASSERT( ngc->isNewGame );
|
2006-06-07 03:45:03 +02:00
|
|
|
|
|
|
|
if ( nPlayers > 1 ) {
|
2006-06-24 03:20:44 +02:00
|
|
|
LocalPlayer tmpPlayers[MAX_NUM_PLAYERS];
|
2006-06-07 03:45:03 +02:00
|
|
|
XP_U16 pos[MAX_NUM_PLAYERS];
|
2006-06-24 03:20:44 +02:00
|
|
|
XP_U16 player;
|
2006-06-07 03:45:03 +02:00
|
|
|
|
2006-06-27 08:30:44 +02:00
|
|
|
/* Get a randomly juggled array of numbers 0..nPlayers-1. Then the
|
|
|
|
number at pos[n] inicates where the entry currently at n should
|
|
|
|
be. */
|
2010-12-08 03:43:53 +01:00
|
|
|
changed = randIntArray( pos, nPlayers );
|
2006-06-29 05:38:25 +02:00
|
|
|
if ( changed ) {
|
2006-06-27 08:30:44 +02:00
|
|
|
|
|
|
|
/* Deep-copy off to tmp storage. But skip lines that won't be moved
|
|
|
|
in the juggle. */
|
|
|
|
XP_MEMSET( &tmpPlayers, 0, sizeof(tmpPlayers) );
|
|
|
|
for ( player = 0; player < nPlayers; ++player ) {
|
|
|
|
if ( player != pos[player] ) {
|
|
|
|
storePlayer( ngc, player, &tmpPlayers[player] );
|
|
|
|
}
|
2006-06-24 03:20:44 +02:00
|
|
|
}
|
2006-06-07 03:45:03 +02:00
|
|
|
|
2006-06-27 08:30:44 +02:00
|
|
|
for ( player = 0; player < nPlayers; ++player ) {
|
|
|
|
if ( player != pos[player] ) {
|
|
|
|
LocalPlayer* lp = &tmpPlayers[player];
|
2006-07-02 02:34:41 +02:00
|
|
|
XP_U16 dest = pos[player];
|
|
|
|
|
|
|
|
loadPlayer( ngc, dest, lp );
|
|
|
|
|
2011-04-08 03:07:45 +02:00
|
|
|
XP_FREEP( ngc->mpool, &lp->name );
|
|
|
|
XP_FREEP( ngc->mpool, &lp->password );
|
|
|
|
XP_FREEP( ngc->mpool, &lp->dictName );
|
2006-07-02 02:34:41 +02:00
|
|
|
|
|
|
|
adjustOneRow( ngc, dest, XP_FALSE );
|
2006-06-24 03:20:44 +02:00
|
|
|
}
|
|
|
|
}
|
2006-06-07 03:45:03 +02:00
|
|
|
}
|
|
|
|
}
|
2006-06-29 05:38:25 +02:00
|
|
|
return changed;
|
2006-06-07 03:45:03 +02:00
|
|
|
} /* newg_juggle */
|
|
|
|
|
2008-01-19 17:04:48 +01:00
|
|
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
2008-01-04 15:47:52 +01:00
|
|
|
static XP_Bool
|
|
|
|
checkConsistent( NewGameCtx* ngc, XP_Bool warnUser )
|
|
|
|
{
|
|
|
|
XP_Bool consistent;
|
2012-08-22 16:44:21 +02:00
|
|
|
XP_U16 ii;
|
2008-01-04 15:47:52 +01:00
|
|
|
|
|
|
|
/* If ISSERVER, make sure there's at least one non-local player. */
|
|
|
|
consistent = ngc->role != SERVER_ISSERVER;
|
2012-08-22 16:44:21 +02:00
|
|
|
for ( ii = 0; !consistent && ii < ngc->nPlayersShown; ++ii ) {
|
2008-01-04 15:47:52 +01:00
|
|
|
DeepValue dValue;
|
|
|
|
dValue.col = NG_COL_REMOTE;
|
2012-08-22 16:44:21 +02:00
|
|
|
(*ngc->getColProc)( ngc->closure, ii, NG_COL_REMOTE,
|
2008-01-04 15:47:52 +01:00
|
|
|
deepCopy, &dValue );
|
|
|
|
if ( dValue.value.ng_bool ) {
|
|
|
|
consistent = XP_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( !consistent && warnUser ) {
|
|
|
|
util_userError( ngc->util, ERR_REG_SERVER_SANS_REMOTE );
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add other consistency checks, and error messages, here. */
|
|
|
|
|
|
|
|
return consistent;
|
|
|
|
} /* checkConsistent */
|
2008-01-19 17:04:48 +01:00
|
|
|
#endif
|
2008-01-04 15:47:52 +01:00
|
|
|
|
2006-06-07 03:26:04 +02:00
|
|
|
static void
|
|
|
|
enableOne( NewGameCtx* ngc, XP_U16 player, NewGameColumn col,
|
2006-10-28 15:21:32 +02:00
|
|
|
XP_TriEnable enable, XP_Bool force )
|
2006-06-07 03:26:04 +02:00
|
|
|
{
|
2006-10-28 15:21:32 +02:00
|
|
|
XP_TriEnable* esp = &ngc->enabled[col][player];
|
2006-06-07 03:26:04 +02:00
|
|
|
if ( force || (*esp != enable) ) {
|
|
|
|
(*ngc->enableColProc)( ngc->closure, player, col, enable );
|
|
|
|
}
|
|
|
|
*esp = enable;
|
|
|
|
} /* enableOne */
|
|
|
|
|
|
|
|
static void
|
|
|
|
adjustAllRows( NewGameCtx* ngc, XP_Bool force )
|
|
|
|
{
|
|
|
|
XP_U16 player;
|
|
|
|
for ( player = 0; player < MAX_NUM_PLAYERS; ++player ) {
|
|
|
|
adjustOneRow( ngc, player, force );
|
|
|
|
}
|
|
|
|
} /* adjustAllRows */
|
|
|
|
|
|
|
|
static void
|
|
|
|
adjustOneRow( NewGameCtx* ngc, XP_U16 player, XP_Bool force )
|
|
|
|
{
|
2006-10-28 15:21:32 +02:00
|
|
|
XP_TriEnable enable[NG_NUM_COLS];
|
2006-06-07 03:26:04 +02:00
|
|
|
NewGameColumn col;
|
|
|
|
XP_Bool isLocal = XP_TRUE;
|
2006-09-24 23:10:17 +02:00
|
|
|
XP_Bool isNewGame = ngc->isNewGame;
|
2007-02-02 09:34:37 +01:00
|
|
|
DeviceRole role = ngc->role;
|
2006-06-07 03:45:03 +02:00
|
|
|
DeepValue dValue;
|
2006-06-07 03:26:04 +02:00
|
|
|
|
2006-06-10 07:45:53 +02:00
|
|
|
for ( col = 0; col < NG_NUM_COLS; ++col ) {
|
2006-10-28 15:21:32 +02:00
|
|
|
enable[col] = TRI_ENAB_HIDDEN;
|
2006-06-10 07:45:53 +02:00
|
|
|
}
|
|
|
|
|
2006-06-07 03:26:04 +02:00
|
|
|
/* If there aren't this many players, all are disabled */
|
2007-02-02 09:15:07 +01:00
|
|
|
if ( player >= ngc->nPlayersShown ) {
|
2006-06-10 07:45:53 +02:00
|
|
|
/* do nothing: all are hidden above */
|
2006-06-07 03:26:04 +02:00
|
|
|
} else {
|
|
|
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
2006-06-10 07:45:53 +02:00
|
|
|
/* If standalone or client, remote is hidden. If server but not
|
|
|
|
new game, it's disabled */
|
2006-09-24 23:10:17 +02:00
|
|
|
if ( (role == SERVER_ISSERVER )
|
|
|
|
|| (role == SERVER_ISCLIENT && !isNewGame ) ) {
|
|
|
|
if ( isNewGame ) {
|
2006-10-28 15:21:32 +02:00
|
|
|
enable[NG_COL_REMOTE] = TRI_ENAB_ENABLED;
|
2006-06-10 07:45:53 +02:00
|
|
|
} else {
|
2006-10-28 15:21:32 +02:00
|
|
|
enable[NG_COL_REMOTE] = TRI_ENAB_DISABLED;
|
2006-06-10 07:45:53 +02:00
|
|
|
}
|
2006-06-08 03:26:18 +02:00
|
|
|
dValue.col = NG_COL_REMOTE;
|
|
|
|
(*ngc->getColProc)( ngc->closure, player, NG_COL_REMOTE,
|
|
|
|
deepCopy, &dValue );
|
|
|
|
isLocal = !dValue.value.ng_bool;
|
2006-06-07 03:26:04 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2006-06-10 07:45:53 +02:00
|
|
|
/* If remote is enabled and set, then if it's a new game all else is
|
|
|
|
hidden. But if it's not a new game, they're disabled. Password is
|
|
|
|
always hidden if robot is set. */
|
2006-06-07 03:26:04 +02:00
|
|
|
if ( isLocal ) {
|
2006-10-28 15:21:32 +02:00
|
|
|
XP_TriEnable tmp;
|
2006-09-24 23:10:17 +02:00
|
|
|
|
2006-06-10 07:45:53 +02:00
|
|
|
/* No changing name or robotness since they're sent to remote
|
|
|
|
host. */
|
2006-09-24 23:10:17 +02:00
|
|
|
tmp = (isNewGame || role == SERVER_STANDALONE)?
|
2006-10-28 15:21:32 +02:00
|
|
|
TRI_ENAB_ENABLED:TRI_ENAB_DISABLED;
|
2006-09-24 23:10:17 +02:00
|
|
|
enable[NG_COL_NAME] = tmp;
|
|
|
|
enable[NG_COL_ROBOT] = tmp;
|
|
|
|
|
|
|
|
/* Password and game info (the not isNewGame case): passwords are
|
|
|
|
not transmitted: they're local only. There's no harm in
|
|
|
|
allowing local players to change them. So passwords should be
|
|
|
|
enabled whenever it's not a robot regardless of both isNewGame
|
|
|
|
and role. */
|
2006-06-10 07:45:53 +02:00
|
|
|
|
2006-06-07 03:45:03 +02:00
|
|
|
dValue.col = NG_COL_ROBOT;
|
|
|
|
(*ngc->getColProc)( ngc->closure, player, NG_COL_ROBOT, deepCopy,
|
|
|
|
&dValue );
|
|
|
|
if ( !dValue.value.ng_bool ) {
|
2006-09-24 23:10:17 +02:00
|
|
|
/* If it's a robot, leave it hidden */
|
2006-10-28 15:21:32 +02:00
|
|
|
enable[NG_COL_PASSWD] = TRI_ENAB_ENABLED;
|
2006-06-10 07:45:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
2006-09-24 23:10:17 +02:00
|
|
|
if ( isNewGame ) {
|
2006-06-10 07:45:53 +02:00
|
|
|
/* leave 'em hidden */
|
|
|
|
} else {
|
2006-10-28 15:21:32 +02:00
|
|
|
enable[NG_COL_NAME] = TRI_ENAB_DISABLED;
|
|
|
|
enable[NG_COL_ROBOT] = TRI_ENAB_DISABLED;
|
2006-06-10 07:45:53 +02:00
|
|
|
/* leave passwd hidden */
|
2006-06-07 03:26:04 +02:00
|
|
|
}
|
|
|
|
}
|
2006-06-10 07:45:53 +02:00
|
|
|
}
|
2006-06-07 03:26:04 +02:00
|
|
|
|
|
|
|
for ( col = 0; col < NG_NUM_COLS; ++col ) {
|
|
|
|
enableOne( ngc, player, col, enable[col], force );
|
|
|
|
}
|
|
|
|
} /* adjustOneRow */
|
|
|
|
|
2007-02-02 09:15:07 +01:00
|
|
|
/* changeRole. When role changes, number of players displayed, and which
|
|
|
|
* players, may change. Host shows all players (up to nPlayers). Guest shows
|
|
|
|
* only local players, but if role changes should show the rest. Change from
|
|
|
|
* Host or Standalone to guest should reduce the number shown.
|
|
|
|
*
|
|
|
|
* Here's the fun part: what happens when user changes nPlayers, then changes
|
|
|
|
* role? Say we're a guest with one player. User makes it two, than makes us
|
|
|
|
* host. Do we pull in a new player? No. Let's not change any of this stuff
|
|
|
|
* ONCE USER'S CHANGED NPLAYERS. Goal is to prevent his having to do that for
|
|
|
|
* the most common case, which is playing again with the same players. In
|
|
|
|
* that case changing role then back again should not lose/change data.
|
|
|
|
*/
|
2008-02-16 17:02:49 +01:00
|
|
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
2008-08-27 14:09:30 +02:00
|
|
|
static XP_Bool
|
2007-02-02 09:34:37 +01:00
|
|
|
changeRole( NewGameCtx* ngc, DeviceRole newRole )
|
2007-02-02 09:15:07 +01:00
|
|
|
{
|
2007-02-02 09:34:37 +01:00
|
|
|
DeviceRole oldRole = ngc->role;
|
2008-08-27 14:09:30 +02:00
|
|
|
XP_Bool changing = oldRole != newRole;
|
|
|
|
if ( changing ) {
|
2007-02-02 09:15:07 +01:00
|
|
|
if ( !ngc->changedNPlayers ) {
|
|
|
|
NGValue value;
|
|
|
|
if ( newRole == SERVER_ISCLIENT ) {
|
|
|
|
value.ng_u16 = ngc->nLocalPlayers;
|
|
|
|
} else {
|
|
|
|
value.ng_u16 = ngc->nPlayersTotal;
|
|
|
|
}
|
|
|
|
if ( value.ng_u16 != ngc->nPlayersShown ) {
|
|
|
|
ngc->nPlayersShown = value.ng_u16;
|
|
|
|
(*ngc->setAttrProc)( ngc->closure, NG_ATTR_NPLAYERS, value );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ngc->role = newRole;
|
|
|
|
setRoleStrings( ngc );
|
|
|
|
}
|
2008-08-27 14:09:30 +02:00
|
|
|
return changing;
|
2007-02-02 09:15:07 +01:00
|
|
|
}
|
2008-02-16 17:02:49 +01:00
|
|
|
#endif
|
2007-02-02 09:15:07 +01:00
|
|
|
|
2006-06-10 07:45:53 +02:00
|
|
|
static void
|
|
|
|
setRoleStrings( NewGameCtx* ngc )
|
|
|
|
{
|
|
|
|
XP_U16 strID;
|
|
|
|
NGValue value;
|
|
|
|
void* closure = ngc->closure;
|
|
|
|
/* Tell client to set/change players label text, and also to add remote
|
|
|
|
checkbox column header if required. */
|
|
|
|
|
|
|
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
|
|
|
(*ngc->enableAttrProc)( closure, NG_ATTR_REMHEADER,
|
2006-09-24 23:10:17 +02:00
|
|
|
( (ngc->role == SERVER_ISSERVER)
|
|
|
|
|| (!ngc->isNewGame
|
|
|
|
&& (ngc->role != SERVER_STANDALONE)) )?
|
2006-10-28 15:21:32 +02:00
|
|
|
TRI_ENAB_ENABLED : TRI_ENAB_HIDDEN );
|
2006-06-10 07:45:53 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
if ( 0 ) {
|
|
|
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
2006-10-28 15:21:32 +02:00
|
|
|
} else if ( ngc->role == SERVER_ISCLIENT && ngc->isNewGame ) {
|
2006-06-10 07:45:53 +02:00
|
|
|
strID = STR_LOCALPLAYERS;
|
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
strID = STR_TOTALPLAYERS;
|
|
|
|
}
|
|
|
|
|
|
|
|
value.ng_cp = util_getUserString( ngc->util, strID );
|
|
|
|
(*ngc->setAttrProc)( closure, NG_ATTR_NPLAYHEADER, value );
|
|
|
|
} /* setRoleStrings */
|
|
|
|
|
2006-06-18 21:02:47 +02:00
|
|
|
static void
|
2009-03-08 20:54:14 +01:00
|
|
|
considerEnable( NewGameCtx* ngc )
|
2006-06-18 21:02:47 +02:00
|
|
|
{
|
2006-10-28 15:21:32 +02:00
|
|
|
XP_TriEnable newEnable;
|
2007-02-02 09:15:07 +01:00
|
|
|
newEnable = (ngc->isNewGame && ngc->nPlayersShown > 1)?
|
2006-10-28 15:21:32 +02:00
|
|
|
TRI_ENAB_ENABLED : TRI_ENAB_HIDDEN;
|
2006-06-18 21:02:47 +02:00
|
|
|
|
|
|
|
if ( newEnable != ngc->juggleEnabled ) {
|
|
|
|
(*ngc->enableAttrProc)( ngc->closure, NG_ATTR_CANJUGGLE, newEnable );
|
|
|
|
ngc->juggleEnabled = newEnable;
|
|
|
|
}
|
2009-03-08 20:54:14 +01:00
|
|
|
|
|
|
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
|
|
|
newEnable = (ngc->role == SERVER_STANDALONE)?
|
|
|
|
TRI_ENAB_HIDDEN : TRI_ENAB_ENABLED;
|
|
|
|
|
|
|
|
if ( newEnable != ngc->settingsEnabled ) {
|
|
|
|
ngc->settingsEnabled = newEnable;
|
|
|
|
(*ngc->enableAttrProc)( ngc->closure, NG_ATTR_CANCONFIG, newEnable );
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
} /* considerEnable */
|
2006-06-18 21:02:47 +02:00
|
|
|
|
2006-06-24 03:20:44 +02:00
|
|
|
static void
|
|
|
|
storePlayer( NewGameCtx* ngc, XP_U16 player, LocalPlayer* lp )
|
|
|
|
{
|
|
|
|
void* closure = ngc->closure;
|
|
|
|
NGCopyClosure cpcl;
|
|
|
|
cpcl.player = player;
|
|
|
|
cpcl.ngc = ngc;
|
|
|
|
cpcl.lp = lp;
|
|
|
|
|
|
|
|
for ( cpcl.col = 0; cpcl.col < NG_NUM_COLS; ++cpcl.col ) {
|
|
|
|
(*ngc->getColProc)( closure, cpcl.player, cpcl.col,
|
|
|
|
cpToLP, &cpcl );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
loadPlayer( NewGameCtx* ngc, XP_U16 player, const LocalPlayer* lp )
|
|
|
|
{
|
|
|
|
NGValue value;
|
|
|
|
void* closure = ngc->closure;
|
|
|
|
|
|
|
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
|
|
|
value.ng_bool = !lp->isLocal;
|
|
|
|
(*ngc->setColProc)(closure, player, NG_COL_REMOTE, value );
|
|
|
|
#endif
|
|
|
|
value.ng_cp = lp->name;
|
|
|
|
(*ngc->setColProc)(closure, player, NG_COL_NAME, value );
|
|
|
|
|
|
|
|
value.ng_cp = lp->password;
|
|
|
|
(*ngc->setColProc)(closure, player, NG_COL_PASSWD, value );
|
|
|
|
|
2011-01-10 15:44:28 +01:00
|
|
|
value.ng_bool = LP_IS_ROBOT(lp);
|
2006-06-24 03:20:44 +02:00
|
|
|
(*ngc->setColProc)(closure, player, NG_COL_ROBOT, value );
|
|
|
|
}
|
|
|
|
|
2006-06-07 03:26:04 +02:00
|
|
|
#ifdef CPLUS
|
|
|
|
}
|
|
|
|
#endif
|