diff --git a/xwords4/android/XWords4/res/layout/game_config.xml b/xwords4/android/XWords4/res/layout/game_config.xml index 20ff24f73..26a2fe507 100644 --- a/xwords4/android/XWords4/res/layout/game_config.xml +++ b/xwords4/android/XWords4/res/layout/game_config.xml @@ -25,6 +25,13 @@ android:layout_height="fill_parent" android:orientation="vertical"> + + key_notagain_zoom key_notagain_undo key_notagain_done + key_notagain_unlock + key_notagain_conndall + key_notagain_conndfirst + key_notagain_conndmid org.eehouse.android.xw4.relayids_extra diff --git a/xwords4/android/XWords4/res/values/strings.xml b/xwords4/android/XWords4/res/values/strings.xml index 69a1b5c86..eaa89a403 100644 --- a/xwords4/android/XWords4/res/values/strings.xml +++ b/xwords4/android/XWords4/res/values/strings.xml @@ -79,8 +79,8 @@ Turn done Shuffle Flip - Exchange - Hide tray + Exchange tiles + Hide rack Undo Undo current Undo last @@ -112,7 +112,7 @@ - %d [time] move (from %s across) move (from %s down) - Tray at start: %s + Rack at start: %s Exchanged %s for %s. Illegal word in move; turn lost! Cumulative score: %d @@ -153,6 +153,7 @@ Players Players (%d local, %d off-device) Players -- local only + Lock settings Add player Shuffle players @@ -184,8 +185,14 @@ This game is in play. If you save these changes it must be restarted. Do you want to save these changes? - Are you sure you want to - delete all games? This action cannot be undone. + Are you sure you want to delete this + game? + Are you sure you want to delete + all games? + Are you sure you want to reset this + game? Resetting erases all moves and any connection + information. + Are you sure you want to delete this dictionary? You will not be able to open any games that use it. @@ -197,8 +204,8 @@ Draw tiles using color of player who played them Show board arrow - Tapped tray tiles land on this - arrow when it is visible + Tapped rack tiles land on this + arrow when it is visible Explain robot moves Display score summary after every robot turn @@ -206,8 +213,8 @@ Do NOT display score summary after every human turn Sort new tiles - Sort trays whenever new tiles - are added + Sort racks whenever new tiles + are added Volume keys zoom Zoom board using volume keys Hide titlebar @@ -292,8 +299,8 @@ SMS (broken) Bluetooth (pending) - Connected to relay in room - \"%s\". Waiting for %d player[s]. + Device %d connected to relay in + room \"%s\". Waiting for %d player[s]. All players are here in room \"%s\". Connection status. @@ -418,9 +425,15 @@ Or try joining or creating a public room. The new game you have created has - two players, the first a robot, both on this device. To play - the game, tap it; to change its configuration or for other - options, long-tap it. + two players, the first a robot, both on this device. Tap it to + play; long-tap it to change its configuration or for other + options. + The new game you have created + has two players but only one is on this device. To play the + game, tap it, and it will begin by connecting over the internet + looking for that other player in the default no-name + room. Long-tap it to configure - e.g. change the room name - or + for other options. This button shows all possible moves in ascending order (using tiles to the right of the rack @@ -438,9 +451,25 @@ This button undos or redoes the current turn. - The new game you have created - The \"pts\" counter that appears at - the right end of the rack is an alternative to this menu - item. + Tapping the \"pts\" counter that + appears at the right end of the rack is the easiest way to + commit a move. (There is no shortcut for ending a + trade.) + This game is in play. Some + settings, e.g. the number of players, cannot be changed without + restarting it. When you leave this page you will have a chance + to discard changes to avoid a restart. + + You have connected and joined a + game on the relay; the room is now full. The device that + created the room will now assign your initial tiles and play can + begin. + You have connected and started + a game in a new room. Once the remaining devices have joined + your room and Crosswords has assigned them tiles the game can + begin. + You have connected and joined a + game on the relay. You will be notified when the remaining + device[s] have joined your room and play can begin. diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java index fb5d1b3bf..8de6abfc3 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java @@ -471,7 +471,7 @@ public class BoardActivity extends XWActivity implements UtilCtxt { // cmd = JNIThread.JNICmd.CMD_FLIP; // break; case R.id.board_menu_trade: - cmd = JNIThread.JNICmd.CMD_TOGGLE_TRADE; + cmd = JNIThread.JNICmd.CMD_TRADE; break; case R.id.board_menu_tray: cmd = JNIThread.JNICmd.CMD_TOGGLE_TRAY; @@ -625,7 +625,9 @@ public class BoardActivity extends XWActivity implements UtilCtxt { { CommsTransport.ConndMsg cndmsg = (CommsTransport.ConndMsg)msg.obj; - Utils.logf( "handleConndMessage: devOrder=%d", cndmsg.m_devOrder ); + + int naMsg = 0; + int naKey = 0; String str = null; if ( cndmsg.m_allHere ) { // All players have now joined the game. The device that @@ -633,16 +635,38 @@ public class BoardActivity extends XWActivity implements UtilCtxt { // the first player's turn String fmt = getString( R.string.msg_relay_all_heref ); str = String.format( fmt, cndmsg.m_room ); + if ( cndmsg.m_devOrder > 1 ) { + naMsg = R.string.not_again_conndall; + naKey = R.string.key_notagain_conndall; + } } else if ( cndmsg.m_nMissing > 0 ) { String fmt = getString( R.string.msg_relay_waiting ); - str = String.format( fmt, cndmsg.m_room, cndmsg.m_nMissing ); + str = String.format( fmt, cndmsg.m_devOrder, + cndmsg.m_room, cndmsg.m_nMissing ); + if ( cndmsg.m_devOrder == 1 ) { + naMsg = R.string.not_again_conndfirst; + naKey = R.string.key_notagain_conndfirst; + } else { + naMsg = R.string.not_again_conndmid; + naKey = R.string.key_notagain_conndmid; + } } if ( null != str ) { - Toast.makeText( BoardActivity.this, str, - Toast.LENGTH_SHORT).show(); + final String fstr = str; + Runnable proc = new Runnable() { + public void run() { + Toast.makeText( BoardActivity.this, fstr, + Toast.LENGTH_SHORT).show(); + } + }; + if ( naMsg == 0 ) { + proc.run(); + } else { + showNotAgainDlgThen( naMsg, naKey, proc ); + } } - } + } // handleConndMessage ////////////////////////////////////////// // XW_UtilCtxt interface implementation // diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameConfig.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameConfig.java index 065d50ae7..9c474fe10 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameConfig.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameConfig.java @@ -69,6 +69,8 @@ public class GameConfig extends XWActivity private static final int NO_NAME_FOUND = PLAYER_EDIT + 4; private CheckBox m_joinPublicCheck; + private CheckBox m_gameLockedCheck; + private boolean m_isLocked; private LinearLayout m_publicRoomsSet; private LinearLayout m_privateRoomsSet; @@ -98,9 +100,23 @@ public class GameConfig extends XWActivity private CommonPrefs m_cp; private boolean m_canDoSMS = false; private boolean m_canDoBT = false; - private int m_nMoves = 0; + private boolean m_gameStarted = false; private CommsAddrRec.CommsConnType[] m_types; private String[] m_connStrings; + private static final int[] s_disabledWhenLocked = { R.id.juggle_players + ,R.id.add_player + ,R.id.dict_spinner + ,R.id.join_public_room_check + ,R.id.room_edit + ,R.id.advertise_new_room_check + ,R.id.room_spinner + ,R.id.refresh_button + ,R.id.hints_allowed + ,R.id.use_timer + ,R.id.timer_minutes_edit + ,R.id.smart_robot + ,R.id.phonies_spinner + }; class RemoteChoices extends XWListAdapter { public RemoteChoices() { super( GameConfig.this, m_gi.nPlayers ); } @@ -127,7 +143,7 @@ public class GameConfig extends XWActivity } @Override - protected Dialog onCreateDialog( int id ) + protected Dialog onCreateDialog( final int id ) { Dialog dialog = super.onCreateDialog( id ); if ( null == dialog ) { @@ -199,41 +215,40 @@ public class GameConfig extends XWActivity } }); break; - case CONFIRM_CHANGE: - dialog = new AlertDialog.Builder( this ) - .setTitle( R.string.confirm_save_title ) - .setMessage( R.string.confirm_save ) - .setPositiveButton( R.string.button_save, - new DialogInterface.OnClickListener() { - public void onClick( DialogInterface dlg, - int whichButton ) { - applyChanges( true ); - finish(); - } - }) - .setNegativeButton( R.string.button_discard, - new DialogInterface.OnClickListener() { - public void onClick( DialogInterface dlg, - int whichButton ) { - finish(); - } - }) - .create(); - break; case CONFIRM_CHANGE_PLAY: - dialog = new AlertDialog.Builder( this ) + case CONFIRM_CHANGE: + dlpos = new DialogInterface.OnClickListener() { + public void onClick( DialogInterface dlg, + int whichButton ) { + applyChanges( true ); + if ( CONFIRM_CHANGE_PLAY == id ) { + launchGame(); + } + } + }; + ab = new AlertDialog.Builder( this ) .setTitle( R.string.confirm_save_title ) .setMessage( R.string.confirm_save ) - .setPositiveButton( R.string.button_save, - new DialogInterface.OnClickListener() { - public void onClick( DialogInterface dlg, - int whichButton ) { - applyChanges( true ); - launchGame(); - } - }) - .setNegativeButton( R.string.button_cancel, null ) - .create(); + .setPositiveButton( R.string.button_save, dlpos ); + if ( CONFIRM_CHANGE_PLAY == id ) { + dlpos = new DialogInterface.OnClickListener() { + public void onClick( DialogInterface dlg, + int whichButton ) { + launchGame(); + } + }; + } else { + dlpos = null; + } + ab.setNegativeButton( R.string.button_discard, dlpos ); + dialog = ab.create(); + + dialog.setOnDismissListener( new DialogInterface. + OnDismissListener() { + public void onDismiss( DialogInterface di ) { + finish(); + } + }); break; case NO_NAME_FOUND: dialog = new AlertDialog.Builder( this ) @@ -350,11 +365,23 @@ public class GameConfig extends XWActivity m_path = m_path.substring( 1 ); } + setContentView(R.layout.game_config); + int gamePtr = XwJNI.initJNI(); m_giOrig = new CurGameInfo( this ); GameUtils.loadMakeGame( this, gamePtr, m_giOrig, m_path ); - m_nMoves = XwJNI.model_getNMoves( gamePtr ); - m_giOrig.setInProgress( 0 < m_nMoves ); + m_gameStarted = XwJNI.model_getNMoves( gamePtr ) > 0 + || XwJNI.comms_isConnected( gamePtr ); + m_giOrig.setInProgress( m_gameStarted ); + + if ( m_gameStarted ) { + m_gameLockedCheck = (CheckBox)findViewById( R.id.game_locked_check ); + m_gameLockedCheck.setVisibility( View.VISIBLE ); + m_gameLockedCheck.setChecked( true ); + m_gameLockedCheck.setOnClickListener( this ); + handleLockedChange(); + } + int curSel = listAvailableDicts( m_giOrig.dictName ); m_giOrig.dictLang = DictLangCache.getLangCode( this, @@ -373,8 +400,6 @@ public class GameConfig extends XWActivity m_car = new CommsAddrRec( m_carOrig ); - setContentView(R.layout.game_config); - m_notNetworkedGame = DeviceRole.SERVER_STANDALONE == m_gi.serverRole; if ( !m_notNetworkedGame ) { @@ -463,6 +488,14 @@ public class GameConfig extends XWActivity loadPlayers(); } else if ( m_joinPublicCheck == view ) { adjustConnectStuff(); + } else if ( m_gameLockedCheck == view ) { + showNotAgainDlgThen( R.string.not_again_unlock, + R.string.key_notagain_unlock, + new Runnable() { + public void run() { + handleLockedChange(); + } + }); } else if ( m_refreshRoomsButton == view ) { refreshNames(); } else if ( m_playButton == view ) { @@ -471,7 +504,7 @@ public class GameConfig extends XWActivity // from here if there's no confirmation needed, or launch // a new dialog whose OK button does the same thing. saveChanges(); - if ( 0 >= m_nMoves ) { // no confirm needed + if ( !m_gameStarted ) { // no confirm needed applyChanges( true ); launchGame(); } else if ( m_giOrig.changesMatter(m_gi) @@ -494,7 +527,7 @@ public class GameConfig extends XWActivity boolean consumed = false; if ( keyCode == KeyEvent.KEYCODE_BACK ) { saveChanges(); - if ( 0 >= m_nMoves ) { // no confirm needed + if ( !m_gameStarted ) { // no confirm needed applyChanges( true ); } else if ( m_giOrig.changesMatter(m_gi) || (! m_notNetworkedGame @@ -544,6 +577,7 @@ public class GameConfig extends XWActivity } } ); m_playerLayout.addView( view ); + view.setEnabled( !m_isLocked ); View divider = factory.inflate( R.layout.divider_view, null ); divider.setVisibility( View.VISIBLE ); @@ -700,6 +734,26 @@ public class GameConfig extends XWActivity m_publicRoomsSet.setVisibility( View.GONE ); } } + + // User's toggling whether everything's locked. That should mean + // we enable/disable a bunch of widgits. And if we're going from + // unlocked to locked we need to confirm that everything can be + // reverted. + private void handleLockedChange() + { + boolean locking = m_gameLockedCheck.isChecked(); + m_isLocked = locking; + for ( int id : s_disabledWhenLocked ) { + View view = findViewById( id ); + view.setEnabled( !m_isLocked ); + } + if ( null != m_playerLayout ) { + for ( int ii = m_playerLayout.getChildCount()-1; ii >= 0; --ii ) { + View view = m_playerLayout.getChildAt( ii ); + view.setEnabled( !m_isLocked ); + } + } + } private int connTypeToPos( CommsAddrRec.CommsConnType typ ) { diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java index 2c463a474..4fa3ebd91 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GamesList.java @@ -274,15 +274,32 @@ public class GamesList extends XWListActivity private boolean handleMenuItem( int menuID, int position ) { boolean handled = true; - byte[] stream; - String invalPath = null; - String path = GameUtils.gamesList( this )[position]; + final String path = GameUtils.gamesList( this )[position]; if ( R.id.list_item_delete == menuID ) { - GameUtils.deleteGame( this, path ); - invalPath = path; + DialogInterface.OnClickListener lstnr = + new DialogInterface.OnClickListener() { + public void onClick( DialogInterface dlg, int ii ) { + GameUtils.deleteGame( GamesList.this, path ); + m_adapter.inval( path ); + onContentChanged(); + } + }; + showConfirmThen( R.string.confirm_delete, lstnr ); + } else if ( R.id.list_item_reset == menuID ) { + DialogInterface.OnClickListener lstnr = + new DialogInterface.OnClickListener() { + public void onClick( DialogInterface dlg, int ii ) { + GameUtils.resetGame( GamesList.this, + path, path ); + m_adapter.inval( path ); + onContentChanged(); + } + }; + showConfirmThen( R.string.confirm_reset, lstnr ); } else { + String invalPath = null; String[] missingName = new String[1]; int[] missingLang = new int[1]; boolean hasDict = GameUtils.gameDictHere( this, path, @@ -296,11 +313,6 @@ public class GamesList extends XWListActivity m_invalPath = path; break; - case R.id.list_item_reset: - // TODO confirm_data_loss(); - GameUtils.resetGame( this, path, path ); - invalPath = path; - break; case R.id.list_item_new_from: String newName = GameUtils.resetGame( this, path ); invalPath = newName; @@ -311,7 +323,7 @@ public class GamesList extends XWListActivity if ( summary.inNetworkGame() ) { showOKOnlyDialog( R.string.no_copy_network ); } else { - stream = GameUtils.savedGame( this, path ); + byte[] stream = GameUtils.savedGame( this, path ); newName = GameUtils.saveGame( this, stream ); DBUtils.saveSummary( this, newName, summary ); } @@ -331,14 +343,13 @@ public class GamesList extends XWListActivity break; } } - } - if ( null != invalPath ) { - m_adapter.inval( invalPath ); - } - - if ( handled ) { - onContentChanged(); + if ( null != invalPath ) { + m_adapter.inval( invalPath ); + } + if ( handled ) { + onContentChanged(); + } } return handled; diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWListItem.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWListItem.java index 64bc15331..791e39a30 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWListItem.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/XWListItem.java @@ -30,7 +30,6 @@ import android.graphics.Rect; public class XWListItem extends LinearLayout { private int m_position; - private ImageButton m_button; private Context m_context; DeleteCallback m_cb; @@ -64,4 +63,15 @@ public class XWListItem extends LinearLayout { } ); button.setVisibility( View.VISIBLE ); } + + @Override + public void setEnabled( boolean enabled ) + { + ImageButton button = (ImageButton)getChildAt( 1 ); + button.setEnabled( enabled ); + // calling super here means the list item can't be opened for + // the user to inspect data. Might want to reconsider this. + // PENDING + super.setEnabled( enabled ); + } } diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIThread.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIThread.java index a4f05f1f6..81a0ebb61 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIThread.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/JNIThread.java @@ -61,7 +61,7 @@ public class JNIThread extends Thread { CMD_JUGGLE, CMD_FLIP, CMD_TOGGLE_TRAY, - CMD_TOGGLE_TRADE, + CMD_TRADE, CMD_UNDO_CUR, CMD_UNDO_LAST, CMD_HINT, @@ -365,7 +365,7 @@ public class JNIThread extends Thread { case CMD_TOGGLE_TRAY: draw = toggleTray(); break; - case CMD_TOGGLE_TRADE: + case CMD_TRADE: draw = XwJNI.board_beginTrade( m_jniGamePtr ); break; case CMD_UNDO_CUR: diff --git a/xwords4/common/board.c b/xwords4/common/board.c index 3832b47c9..b0d3fb250 100644 --- a/xwords4/common/board.c +++ b/xwords4/common/board.c @@ -1215,10 +1215,8 @@ invalCellsWithTiles( BoardCtxt* board ) */ for ( row = model_numRows( model )-1; row >= 0; --row ) { for ( col = model_numCols( model )-1; col >= 0; --col ) { - Tile tile; - XP_Bool ignore; if ( model_getTile( model, col, row, includePending, - turn, &tile, &ignore, &ignore, &ignore ) ) { + turn, NULL, NULL, NULL, NULL ) ) { XP_U16 boardCol, boardRow; flipIf( board, col, row, &boardCol, &boardRow ); invalCell( board, boardCol, boardRow ); @@ -2327,13 +2325,12 @@ cellOccupied( const BoardCtxt* board, XP_U16 col, XP_U16 row, XP_Bool inclPending ) { Tile tile; - XP_Bool ignr; XP_Bool result; flipIf( board, col, row, &col, &row ); result = model_getTile( board->model, col, row, inclPending, board->selPlayer, &tile, - &ignr, &ignr, &ignr ); + NULL, NULL, NULL ); return result; } /* cellOccupied */ @@ -2379,13 +2376,13 @@ XP_Bool holdsPendingTile( BoardCtxt* board, XP_U16 pencol, XP_U16 penrow ) { Tile tile; - XP_Bool ignore, isPending; + XP_Bool isPending; XP_U16 modcol, modrow; flipIf( board, pencol, penrow, &modcol, &modrow ); return model_getTile( board->model, modcol, modrow, XP_TRUE, - board->selPlayer, &tile, &ignore, &isPending, - (XP_Bool*)NULL ) + board->selPlayer, &tile, NULL, &isPending, + NULL ) && isPending; } /* holdsPendingTile */ @@ -3232,16 +3229,14 @@ boardCellChanged( void* p_board, XP_U16 turn, XP_U16 modelCol, XP_U16 modelRow, XP_Bool added ) { BoardCtxt* board = (BoardCtxt*)p_board; - XP_Bool pending, found, ignoreBlank; - Tile ignoreTile; + XP_Bool pending, found; XP_U16 col, row; flipIf( board, modelCol, modelRow, &col, &row ); /* for each player, check if the tile overwrites the cursor */ found = model_getTile( board->model, modelCol, modelRow, XP_TRUE, turn, - &ignoreTile, &ignoreBlank, &pending, - (XP_Bool*)NULL ); + NULL, NULL, &pending, NULL ); XP_ASSERT( !added || found ); /* if added is true so must found be */ diff --git a/xwords4/common/dragdrpp.c b/xwords4/common/dragdrpp.c index 92860bfc3..ec6d933d2 100644 --- a/xwords4/common/dragdrpp.c +++ b/xwords4/common/dragdrpp.c @@ -91,14 +91,13 @@ ddStartBoard( BoardCtxt* board, XP_U16 xx, XP_U16 yy ) trayVisible = board->trayVisState == TRAY_REVEALED; if ( trayVisible && holdsPendingTile( board, col, row ) ) { XP_U16 modelc, modelr; - XP_Bool ignore; ds->dtype = DT_TILE; flipIf( board, col, row, &modelc, &modelr ); found = model_getTile( board->model, modelc, modelr, XP_TRUE, board->selPlayer, &ds->tile, &ds->isBlank, - &ignore, &ignore ); + NULL, NULL ); XP_ASSERT( found ); } else { /* If we're not dragging a tile, we can either drag the board (scroll) diff --git a/xwords4/common/engine.c b/xwords4/common/engine.c index b9c6cf0ed..eb32eacad 100644 --- a/xwords4/common/engine.c +++ b/xwords4/common/engine.c @@ -732,7 +732,7 @@ localGetBoardTile( EngineCtxt* engine, XP_U16 col, XP_U16 row, XP_Bool substBlank ) { Tile result; - XP_Bool isBlank, ignore; + XP_Bool isBlank; if ( !engine->searchHorizontal ) { XP_U16 tmp = col; @@ -742,7 +742,7 @@ localGetBoardTile( EngineCtxt* engine, XP_U16 col, XP_U16 row, if ( model_getTile( engine->model, col, row, XP_FALSE, 0, /* don't get pending, so turn doesn't matter */ - &result, &isBlank, &ignore, (XP_Bool*)NULL ) ) { + &result, &isBlank, NULL, NULL ) ) { if ( isBlank && substBlank ) { result = engine->blankTile; } diff --git a/xwords4/common/model.c b/xwords4/common/model.c index 4b87f24fd..b1ade983c 100644 --- a/xwords4/common/model.c +++ b/xwords4/common/model.c @@ -327,10 +327,16 @@ model_getTile( const ModelCtxt* model, XP_U16 col, XP_U16 row, if ( (cellTile & TILE_EMPTY_BIT) != 0 ) { return XP_FALSE; } - - *tileP = cellTile & TILE_VALUE_MASK; - *isBlank = IS_BLANK(cellTile); - *pendingP = pending; + + if ( NULL != tileP ) { + *tileP = cellTile & TILE_VALUE_MASK; + } + if ( NULL != isBlank ) { + *isBlank = IS_BLANK(cellTile); + } + if ( NULL != pendingP ) { + *pendingP = pending; + } if ( !!recentP ) { *recentP = (cellTile & PREV_MOVE_BIT) != 0; } @@ -1007,12 +1013,11 @@ model_moveTrayToBoard( ModelCtxt* model, XP_S16 turn, XP_U16 col, XP_U16 row, XP_Bool model_redoPendingTiles( ModelCtxt* model, XP_S16 turn ) { - XP_Bool changed = XP_FALSE; + XP_U16 actualCnt = 0; PlayerCtxt* player = &model->players[turn]; XP_U16 nUndone = player->nUndone; - changed = nUndone > 0; - if ( changed ) { + if ( nUndone > 0 ) { PendingTile pendingTiles[nUndone]; PendingTile* pt = pendingTiles; @@ -1031,11 +1036,16 @@ model_redoPendingTiles( ModelCtxt* model, XP_S16 turn ) } foundAt = model_trayContains( model, turn, tile ); XP_ASSERT( foundAt >= 0 ); - model_moveTrayToBoard( model, turn, pt->col, pt->row, - foundAt, pt->tile & ~TILE_BLANK_BIT ); + + if ( !model_getTile( model, pt->col, pt->row, XP_FALSE, turn, + NULL, NULL, NULL, NULL ) ) { + model_moveTrayToBoard( model, turn, pt->col, pt->row, + foundAt, pt->tile & ~TILE_BLANK_BIT ); + ++actualCnt; + } } } - return changed; + return actualCnt > 0; } void diff --git a/xwords4/common/mscore.c b/xwords4/common/mscore.c index 917ff2631..e8b3279c4 100644 --- a/xwords4/common/mscore.c +++ b/xwords4/common/mscore.c @@ -317,11 +317,10 @@ static XP_Bool modelIsEmptyAt( const ModelCtxt* model, XP_U16 col, XP_U16 row ) { Tile tile; - XP_Bool ignore; XP_Bool found; found = model_getTile( model, col, row, XP_FALSE, -1, &tile, - &ignore, &ignore, (XP_Bool*)NULL ); + NULL, NULL, NULL ); return !found; } /* modelIsEmptyAt */ @@ -643,11 +642,10 @@ scoreWord( const ModelCtxt* model, MoveInfo* movei, /* new tiles */ ++tiles; --nTiles; } else { /* placed on the board before this move */ - XP_Bool ignore; tileMultiplier = 1; (void)model_getTile( model, col, row, XP_FALSE, -1, &tile, - &isBlank, &ignore, (XP_Bool*)NULL ); + &isBlank, NULL, NULL ); XP_ASSERT( (tile & TILE_VALUE_MASK) == tile ); }