diff --git a/xwords4/common/comtypes.h b/xwords4/common/comtypes.h index b36d99994..42130e2ae 100644 --- a/xwords4/common/comtypes.h +++ b/xwords4/common/comtypes.h @@ -47,6 +47,7 @@ #endif #define MAX_COLS MAX_ROWS +#define STREAM_VERS_DUPLICATE 0x1B #define STREAM_VERS_DISABLEDS 0x1A #define STREAM_VERS_DEVIDS 0x19 #define STREAM_VERS_MULTIADDR 0x18 @@ -88,7 +89,7 @@ #define STREAM_VERS_405 0x01 /* search for FIX_NEXT_VERSION_CHANGE next time this is changed */ -#define CUR_STREAM_VERS STREAM_VERS_DISABLEDS +#define CUR_STREAM_VERS STREAM_VERS_DUPLICATE typedef struct XP_Rect { XP_S16 left; diff --git a/xwords4/common/game.c b/xwords4/common/game.c index 1facc227f..187a6e1c7 100644 --- a/xwords4/common/game.c +++ b/xwords4/common/game.c @@ -487,7 +487,9 @@ gi_copy( MPFORMAL CurGameInfo* destGI, const CurGameInfo* srcGI ) destGI->phoniesAction = srcGI->phoniesAction; destGI->allowPickTiles = srcGI->allowPickTiles; destGI->forceChannel = srcGI->forceChannel; - XP_LOGF( "%s: copied forceChannel: %d", __func__, destGI->forceChannel ); + destGI->inDuplicateMode = srcGI->inDuplicateMode; + XP_LOGF( "%s: copied forceChannel: %d; inDuplicateMode: %d", __func__, + destGI->forceChannel, destGI->inDuplicateMode ); for ( srcPl = srcGI->players, destPl = destGI->players, ii = 0; ii < nPlayers; ++srcPl, ++destPl, ++ii ) { @@ -566,6 +568,9 @@ gi_readFromStream( MPFORMAL XWStreamCtxt* stream, CurGameInfo* gi ) gi->phoniesAction = (XWPhoniesChoice)stream_getBits( stream, 2 ); gi->timerEnabled = stream_getBits( stream, 1 ); + gi->inDuplicateMode = strVersion >= STREAM_VERS_DUPLICATE + ? stream_getBits( stream, 1 ) + : XP_FALSE; if ( strVersion >= STREAM_VERS_41B4 ) { gi->allowPickTiles = stream_getBits( stream, 1 ); gi->allowHintRect = stream_getBits( stream, 1 ); @@ -641,6 +646,7 @@ gi_writeToStream( XWStreamCtxt* stream, const CurGameInfo* gi ) stream_putBits( stream, 1, gi->hintsNotAllowed ); stream_putBits( stream, 2, gi->phoniesAction ); stream_putBits( stream, 1, gi->timerEnabled ); + stream_putBits( stream, 1, gi->inDuplicateMode ); stream_putBits( stream, 1, gi->allowPickTiles ); stream_putBits( stream, 1, gi->allowHintRect ); stream_putBits( stream, 1, gi->confirmBTConnect ); diff --git a/xwords4/common/gameinfo.h b/xwords4/common/gameinfo.h index aa931bc5b..608b7c059 100644 --- a/xwords4/common/gameinfo.h +++ b/xwords4/common/gameinfo.h @@ -58,6 +58,7 @@ typedef struct CurGameInfo { XP_Bool timerEnabled; XP_Bool allowPickTiles; XP_Bool allowHintRect; + XP_Bool inDuplicateMode; XWPhoniesChoice phoniesAction; XP_Bool confirmBTConnect; /* only used for BT */ } CurGameInfo; diff --git a/xwords4/common/server.c b/xwords4/common/server.c index 325f3b38a..85d5404dd 100644 --- a/xwords4/common/server.c +++ b/xwords4/common/server.c @@ -1,6 +1,6 @@ /* -*- compile-command: "cd ../linux && make -j3 MEMDEBUG=TRUE"; -*- */ /* - * Copyright 1997-2009 by Eric House (xwords@eehouse.org). All rights + * Copyright 1997 - 2019 by Eric House (xwords@eehouse.org). All rights * reserved. * * This program is free software; you can redistribute it and/or @@ -84,6 +84,7 @@ typedef struct ServerVolatiles { typedef struct ServerNonvolatiles { XP_U32 lastMoveTime; /* seconds of last turn change */ + XP_S32 dupTimerExpires; XP_U8 nDevices; XW_State gameState; XW_State stateAfterShow; @@ -103,6 +104,9 @@ typedef struct ServerNonvolatiles { RemoteAddress addresses[MAX_NUM_PLAYERS]; XWStreamCtxt* prevMoveStream; /* save it to print later */ XWStreamCtxt* prevWordsStream; + XP_Bool dupTurnsMade[MAX_NUM_PLAYERS]; + XP_Bool dupTurnsForced[MAX_NUM_PLAYERS]; + XP_Bool dupTurnsSent; /* used on client only */ } ServerNonvolatiles; struct ServerCtxt { @@ -290,6 +294,9 @@ getNV( XWStreamCtxt* stream, ServerNonvolatiles* nv, XP_U16 nPlayers ) if ( STREAM_VERS_DICTNAME <= version ) { nv->lastMoveTime = stream_getU32( stream ); } + if ( STREAM_VERS_DUPLICATE <= version ) { + nv->dupTimerExpires = stream_getU32( stream ); + } if ( version < STREAM_VERS_SERVER_SAVES_TOSHOW ) { /* no longer used */ @@ -327,6 +334,15 @@ getNV( XWStreamCtxt* stream, ServerNonvolatiles* nv, XP_U16 nPlayers ) } /* XP_LOGF( "%s: read streamVersion: 0x%x", __func__, nv->streamVersion ); */ #endif + + if ( version >= STREAM_VERS_DUPLICATE ) { + for ( ii = 0; ii < nPlayers; ++ii ) { + nv->dupTurnsMade[ii] = stream_getBits( stream, 1 ); + XP_LOGF( "%s(): dupTurnsMade[%d]: %d", __func__, ii, nv->dupTurnsMade[ii] ); + nv->dupTurnsForced[ii] = stream_getBits( stream, 1 ); + } + nv->dupTurnsSent = stream_getBits( stream, 1 ); + } } /* getNV */ static void @@ -335,6 +351,7 @@ putNV( XWStreamCtxt* stream, const ServerNonvolatiles* nv, XP_U16 nPlayers ) XP_U16 ii; stream_putU32( stream, nv->lastMoveTime ); + stream_putU32( stream, nv->dupTimerExpires ); /* number of players is upper limit on device count */ stream_putBits( stream, NDEVICES_NBITS, nv->nDevices-1 ); @@ -358,6 +375,12 @@ putNV( XWStreamCtxt* stream, const ServerNonvolatiles* nv, XP_U16 nPlayers ) stream_putU8( stream, nv->streamVersion ); /* XP_LOGF( "%s: wrote streamVersion: 0x%x", __func__, nv->streamVersion ); */ #endif + + for ( ii = 0; ii < nPlayers; ++ii ) { + stream_putBits( stream, 1, nv->dupTurnsMade[ii] ); + stream_putBits( stream, 1, nv->dupTurnsForced[ii] ); + } + stream_putBits( stream, 1, nv->dupTurnsSent ); } /* putNV */ static XWStreamCtxt*