From f716768a713b6c7d6bf5526b78d8aaa4fe8d4b7e Mon Sep 17 00:00:00 2001 From: Eric House Date: Sun, 18 Feb 2024 08:16:41 -0800 Subject: [PATCH] support sub7 trades on Android too --- .../android/xw4/GameConfigDelegate.java | 3 ++ .../eehouse/android/xw4/jni/CommonPrefs.java | 5 +++ .../eehouse/android/xw4/jni/CurGameInfo.java | 8 +++++ .../app/src/main/res/layout/game_config.xml | 7 +++- .../app/src/main/res/values/common_rsrc.xml | 1 + .../app/src/main/res/values/tmpstrings.xml | 4 +++ .../app/src/main/res/xml/prefs_dflts.xml | 6 ++++ xwords4/android/jni/xwjni.c | 1 + xwords4/common/game.c | 10 +++--- xwords4/common/gameinfo.h | 4 +-- xwords4/common/nwgamest.c | 4 +-- xwords4/common/server.c | 33 ++++++++++++++----- xwords4/linux/cursesmain.c | 2 +- 13 files changed, 69 insertions(+), 19 deletions(-) diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/GameConfigDelegate.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/GameConfigDelegate.java index c15aef369..a0472d3da 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/GameConfigDelegate.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/GameConfigDelegate.java @@ -115,6 +115,7 @@ public class GameConfigDelegate extends DelegateBase R.id.lang_spinner, R.id.dict_spinner, R.id.hints_allowed, + R.id.trade_sub_seven, R.id.duplicate_check, R.id.pick_faceup, R.id.boardsize_spinner, @@ -683,6 +684,7 @@ public class GameConfigDelegate extends DelegateBase tweakTimerStuff(); setChecked( R.id.hints_allowed, !m_gi.hintsNotAllowed ); + setChecked( R.id.trade_sub_seven, m_gi.tradeSub7 ); setChecked( R.id.pick_faceup, m_gi.allowPickTiles ); setBoardsizeSpinner(); @@ -1276,6 +1278,7 @@ public class GameConfigDelegate extends DelegateBase m_gi.inDuplicateMode = getChecked( R.id.duplicate_check ); m_gi.hintsNotAllowed = !getChecked( R.id.hints_allowed ); + m_gi.tradeSub7 = getChecked( R.id.trade_sub_seven ); m_gi.allowPickTiles = getChecked( R.id.pick_faceup ); m_gi.timerEnabled = getChecked( R.id.use_timer ); diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/CommonPrefs.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/CommonPrefs.java index fe2951b02..9537652f6 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/CommonPrefs.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/CommonPrefs.java @@ -303,6 +303,11 @@ public class CommonPrefs extends XWPrefs { return getPrefsBoolean( context, key, true ); } + public static boolean getSub7TradeAllowed( Context context ) + { + return getPrefsBoolean( context, R.string.key_init_tradeSub7, false ); + } + public static boolean getDefaultDupMode( Context context ) { return getPrefsBoolean( context, R.string.key_init_dupmodeon, false ); diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/CurGameInfo.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/CurGameInfo.java index 774a2174b..29794fc98 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/CurGameInfo.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/jni/CurGameInfo.java @@ -54,6 +54,7 @@ public class CurGameInfo implements Serializable { private static final String ALLOW_PICK = "ALLOW_PICK"; private static final String PHONIES = "PHONIES"; private static final String DUP = "DUP"; + private static final String SUB7 = "SUB7"; public enum XWPhoniesChoice { PHONIES_IGNORE, PHONIES_WARN, PHONIES_DISALLOW, PHONIES_BLOCK, }; public enum DeviceRole { SERVER_STANDALONE, SERVER_ISSERVER, SERVER_ISCLIENT }; @@ -71,6 +72,7 @@ public class CurGameInfo implements Serializable { public DeviceRole serverRole; public boolean inDuplicateMode; + public boolean tradeSub7; public boolean hintsNotAllowed; public boolean timerEnabled; public boolean allowPickTiles; @@ -102,6 +104,7 @@ public class CurGameInfo implements Serializable { : DeviceRole.SERVER_STANDALONE; hintsNotAllowed = !CommonPrefs.getDefaultHintsAllowed( context, isNetworked ); + tradeSub7 = CommonPrefs.getSub7TradeAllowed( context ); phoniesAction = CommonPrefs.getDefaultPhonies( context ); timerEnabled = CommonPrefs.getDefaultTimerEnabled( context ); allowPickTiles = false; @@ -156,6 +159,7 @@ public class CurGameInfo implements Serializable { isoCodeStr = src.isoCodeStr; hintsNotAllowed = src.hintsNotAllowed; inDuplicateMode = src.inDuplicateMode; + tradeSub7 = src.tradeSub7; phoniesAction = src.phoniesAction; timerEnabled = src.timerEnabled; allowPickTiles = src.allowPickTiles; @@ -211,6 +215,7 @@ public class CurGameInfo implements Serializable { .put( BINGO_MIN, bingoMin ) .put( NO_HINTS, hintsNotAllowed ) .put( DUP, inDuplicateMode ) + .put( SUB7, tradeSub7 ) .put( TIMER, timerEnabled ) .put( ALLOW_PICK, allowPickTiles ) .put( PHONIES, phoniesAction.ordinal() ) @@ -233,6 +238,7 @@ public class CurGameInfo implements Serializable { bingoMin = obj.optInt( BINGO_MIN, bingoMin ); hintsNotAllowed = obj.optBoolean( NO_HINTS, hintsNotAllowed ); inDuplicateMode = obj.optBoolean( DUP, inDuplicateMode ); + tradeSub7 = obj.optBoolean( SUB7, tradeSub7 ); timerEnabled = obj.optBoolean( TIMER, timerEnabled ); allowPickTiles = obj.optBoolean( ALLOW_PICK, allowPickTiles ); int tmp = obj.optInt( PHONIES, phoniesAction.ordinal() ); @@ -331,6 +337,7 @@ public class CurGameInfo implements Serializable { || bingoMin != other.bingoMin || hintsNotAllowed != other.hintsNotAllowed || inDuplicateMode != other.inDuplicateMode + || tradeSub7 != other.tradeSub7 || allowPickTiles != other.allowPickTiles || phoniesAction != other.phoniesAction; @@ -367,6 +374,7 @@ public class CurGameInfo implements Serializable { && forceChannel == other.forceChannel && hintsNotAllowed == other.hintsNotAllowed && inDuplicateMode == other.inDuplicateMode + && tradeSub7 == other.tradeSub7 && timerEnabled == other.timerEnabled && allowPickTiles == other.allowPickTiles && allowHintRect == other.allowHintRect diff --git a/xwords4/android/app/src/main/res/layout/game_config.xml b/xwords4/android/app/src/main/res/layout/game_config.xml index 5381a0de2..89b348f33 100644 --- a/xwords4/android/app/src/main/res/layout/game_config.xml +++ b/xwords4/android/app/src/main/res/layout/game_config.xml @@ -142,7 +142,6 @@ + + key_logging_on key_show_sms key_init_hintsallowed + key_init_tradeSub7 key_init_dupmodeon key_unhide_dupmode key_init_nethintsallowed diff --git a/xwords4/android/app/src/main/res/values/tmpstrings.xml b/xwords4/android/app/src/main/res/values/tmpstrings.xml index 354c5275f..ae4e042be 100644 --- a/xwords4/android/app/src/main/res/values/tmpstrings.xml +++ b/xwords4/android/app/src/main/res/values/tmpstrings.xml @@ -13,4 +13,8 @@ Unquash + + Allow trades below seven tiles left + Common in Spanish play, this + lets you trade tiles when as few as 1 are left in the pool. diff --git a/xwords4/android/app/src/main/res/xml/prefs_dflts.xml b/xwords4/android/app/src/main/res/xml/prefs_dflts.xml index 0840dedd2..575bb51ed 100644 --- a/xwords4/android/app/src/main/res/xml/prefs_dflts.xml +++ b/xwords4/android/app/src/main/res/xml/prefs_dflts.xml @@ -41,6 +41,12 @@ android:defaultValue="true" /> + + inDuplicateMode = srcGI->inDuplicateMode; XP_LOGFF( "copied forceChannel: %d; inDuplicateMode: %d", destGI->forceChannel, destGI->inDuplicateMode ); - destGI->tradeSubSeven = srcGI->tradeSubSeven; + destGI->tradeSub7 = srcGI->tradeSub7; const LocalPlayer* srcPl; LocalPlayer* destPl; @@ -726,7 +726,7 @@ gi_equal( const CurGameInfo* gi1, const CurGameInfo* gi2 ) equal = strEq( gi1->isoCodeStr, gi2->isoCodeStr ); break; case 17: - equal = gi1->tradeSubSeven == gi2->tradeSubSeven; + equal = gi1->tradeSub7 == gi2->tradeSub7; break; case 18: for ( int jj = 0; equal && jj < gi1->nPlayers; ++jj ) { @@ -869,7 +869,7 @@ gi_readFromStream( MPFORMAL XWStreamCtxt* stream, CurGameInfo* gi ) gi->inDuplicateMode = strVersion >= STREAM_VERS_DUPLICATE ? stream_getBits( stream, 1 ) : XP_FALSE; - gi->tradeSubSeven = strVersion >= STREAM_VERS_SUBSEVEN + gi->tradeSub7 = strVersion >= STREAM_VERS_SUBSEVEN ? stream_getBits( stream, 1 ) : XP_FALSE; if ( strVersion >= STREAM_VERS_41B4 ) { @@ -962,7 +962,7 @@ gi_writeToStream( XWStreamCtxt* stream, const CurGameInfo* gi ) stream_putBits( stream, 1, gi->timerEnabled ); stream_putBits( stream, 1, gi->inDuplicateMode ); if ( strVersion >= STREAM_VERS_SUBSEVEN ) { - stream_putBits( stream, 1, gi->tradeSubSeven ); + stream_putBits( stream, 1, gi->tradeSub7 ); } stream_putBits( stream, 1, gi->allowPickTiles ); stream_putBits( stream, 1, gi->allowHintRect ); @@ -1066,7 +1066,7 @@ game_logGI( const CurGameInfo* gi, const char* msg, const char* func, int line ) XP_LOGF( " serverRole: %d", gi->serverRole ); XP_LOGF( " dictName: %s", gi->dictName ); XP_LOGF( " isoCode: %s", gi->isoCodeStr ); - XP_LOGF( " tradeSubSeven: %s", boolToStr(gi->tradeSubSeven) ); + XP_LOGF( " tradeSub7: %s", boolToStr(gi->tradeSub7) ); } } #endif diff --git a/xwords4/common/gameinfo.h b/xwords4/common/gameinfo.h index 00d3faf35..09205bf5f 100644 --- a/xwords4/common/gameinfo.h +++ b/xwords4/common/gameinfo.h @@ -61,12 +61,12 @@ typedef struct CurGameInfo { XP_Bool allowPickTiles; XP_Bool allowHintRect; XP_Bool inDuplicateMode; - XP_Bool tradeSubSeven; + XP_Bool tradeSub7; XWPhoniesChoice phoniesAction; XP_Bool confirmBTConnect; /* only used for BT */ } CurGameInfo; -#define MIN_TRADE_TILES(GI) ((GI)->tradeSubSeven ? 1 : (GI)->traySize) +#define MIN_TRADE_TILES(GI) ((GI)->tradeSub7 ? 1 : (GI)->traySize) #ifdef DEBUG # define LOGGI( gip, msg ) game_logGI( (gip), (msg), __func__, __LINE__ ) diff --git a/xwords4/common/nwgamest.c b/xwords4/common/nwgamest.c index 98dd0cab1..1d8b27e42 100644 --- a/xwords4/common/nwgamest.c +++ b/xwords4/common/nwgamest.c @@ -151,7 +151,7 @@ newg_load( NewGameCtx* ngc, XWEnv xwe, const CurGameInfo* gi ) value.ng_bool = ngc->duplicateEnabled; (*ngc->setAttrProc)( closure, NG_ATTR_DUPLICATE, value ); - ngc->sub7Enabled = gi->tradeSubSeven; + ngc->sub7Enabled = gi->tradeSub7; value.ng_bool = ngc->sub7Enabled; (*ngc->setAttrProc)( closure, NG_ATTR_SUB7, value ); @@ -234,7 +234,7 @@ newg_store( NewGameCtx* ngc, XWEnv xwe, CurGameInfo* gi, XP_Bool warn ) gi->timerEnabled = gi->gameSeconds > 0; gi->inDuplicateMode = ngc->duplicateEnabled; - gi->tradeSubSeven = ngc->sub7Enabled; + gi->tradeSub7 = ngc->sub7Enabled; gi->gameSeconds = ngc->timerSeconds; gi->timerEnabled = gi->gameSeconds > 0; diff --git a/xwords4/common/server.c b/xwords4/common/server.c index 521404ba6..5702461ad 100644 --- a/xwords4/common/server.c +++ b/xwords4/common/server.c @@ -1139,6 +1139,7 @@ callDupTimerListener( const ServerCtxt* server, XWEnv xwe, XP_S32 oldVal, XP_S32 static void setStreamVersion( ServerCtxt* server ) { + XP_ASSERT( amHost( server ) ); XP_U8 streamVersion = CUR_STREAM_VERS; for ( XP_U16 devIndex = 1; devIndex < server->nv.nDevices; ++devIndex ) { XP_U8 devVersion = server->nv.addresses[devIndex].streamVersion; @@ -1149,13 +1150,28 @@ setStreamVersion( ServerCtxt* server ) SRVR_LOGFFV( "setting streamVersion: 0x%x", streamVersion ); server->nv.streamVersion = streamVersion; - CurGameInfo* gi = server->vol.gi; - if ( STREAM_VERS_NINETILES > streamVersion ) { - if ( 7 < gi->traySize ) { - SRVR_LOGFF( "reducing tray size from %d to 7", gi->traySize ); - gi->traySize = gi->bingoMin = 7; + /* If we're downgrading stream to accomodate an older guest, we need to + re-write gi in that version in case there are newer features the game + can't support, e.g. allowing to trade with less than a full tray left + in the pool. */ + if ( CUR_STREAM_VERS != streamVersion ) { + CurGameInfo* gi = server->vol.gi; + XP_U16 oldTraySize = gi->traySize; + XP_U16 oldBingoMin = gi->bingoMin; + + XWStreamCtxt* tmp = mkServerStream( server, streamVersion ); + gi_writeToStream( tmp, gi ); + gi_disposePlayerInfo( MPPARM(server->mpool) gi ); + gi_readFromStream( MPPARM(server->mpool) tmp, gi ); + stream_destroy( tmp ); + /* If downgrading forced tray size change, model needs to know. BUT: + the guest would have to be >two years old now for this to happen. */ + if ( oldTraySize != gi->traySize || oldBingoMin != gi->bingoMin ) { + XP_ASSERT( 7 == gi->traySize && 7 == gi->bingoMin ); + if ( 7 == gi->traySize && 7 == gi->bingoMin ) { + model_forceStack7Tiles( server->vol.model ); + } } - model_forceStack7Tiles( server->vol.model ); } } @@ -1221,8 +1237,9 @@ handleRegistrationMsg( ServerCtxt* server, XWEnv xwe, XWStreamCtxt* stream ) if ( 0 < stream_getSize(stream) ) { XP_U8 streamVersion = stream_getU8( stream ); if ( streamVersion >= STREAM_VERS_BIGBOARD ) { - SRVR_LOGFF( "upping device %d streamVersion to 0x%x", - clientIndex, streamVersion ); + SRVR_LOGFF( "setting addresses[%d] streamVersion to 0x%x " + "(CUR_STREAM_VERS is 0x%x)", + clientIndex, streamVersion, CUR_STREAM_VERS ); server->nv.addresses[clientIndex].streamVersion = streamVersion; } } diff --git a/xwords4/linux/cursesmain.c b/xwords4/linux/cursesmain.c index f150b8532..6e4a01201 100644 --- a/xwords4/linux/cursesmain.c +++ b/xwords4/linux/cursesmain.c @@ -1522,7 +1522,7 @@ makeGameFromArgs( CursesAppGlobals* aGlobals, cJSON* args ) } tmp = cJSON_GetObjectItem( args, "allowSub7" ); - gi.tradeSubSeven = !!tmp && cJSON_IsTrue( tmp ); + gi.tradeSub7 = !!tmp && cJSON_IsTrue( tmp ); tmp = cJSON_GetObjectItem( args, "isSolo" ); XP_ASSERT( !!tmp );